aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2011-05-02 19:39:53 +0000
committerDimitry Andric <dim@FreeBSD.org>2011-05-02 19:39:53 +0000
commit01af97d3b23bded2b2b21af19bbc6e4cce49e5b3 (patch)
tree64a10f4c4154739d4a8191d7e1b52ce497f4ebd6
parentc3b054d250cdca485c71845089c316e10610ebad (diff)
downloadsrc-01af97d3b23bded2b2b21af19bbc6e4cce49e5b3.tar.gz
src-01af97d3b23bded2b2b21af19bbc6e4cce49e5b3.zip
Vendor import of clang trunk r130700:vendor/clang/clang-r130700
Notes
Notes: svn path=/vendor/clang/dist/; revision=221339 svn path=/vendor/clang/clang-r130700/; revision=221340; tag=vendor/clang/clang-r130700
-rw-r--r--CMakeLists.txt33
-rw-r--r--Makefile3
-rw-r--r--docs/DriverInternals.html6
-rw-r--r--docs/InternalsManual.html56
-rw-r--r--docs/LanguageExtensions.html118
-rw-r--r--docs/UsersManual.html104
-rw-r--r--docs/tools/clang.pod17
-rw-r--r--examples/CMakeLists.txt2
-rw-r--r--examples/Tooling/CMakeLists.txt6
-rw-r--r--examples/Tooling/ClangCheck.cpp108
-rw-r--r--examples/Tooling/Makefile24
-rw-r--r--examples/clang-interpreter/Makefile2
-rw-r--r--examples/clang-interpreter/main.cpp3
-rw-r--r--include/clang-c/Index.h78
-rw-r--r--include/clang/AST/ASTConsumer.h2
-rw-r--r--include/clang/AST/ASTContext.h76
-rw-r--r--include/clang/AST/ASTDiagnostic.h3
-rw-r--r--include/clang/AST/ASTMutationListener.h13
-rw-r--r--include/clang/AST/Attr.h15
-rw-r--r--include/clang/AST/CXXInheritance.h2
-rw-r--r--include/clang/AST/CanonicalType.h3
-rw-r--r--include/clang/AST/CharUnits.h16
-rw-r--r--include/clang/AST/Decl.h555
-rw-r--r--include/clang/AST/DeclBase.h87
-rw-r--r--include/clang/AST/DeclCXX.h351
-rw-r--r--include/clang/AST/DeclFriend.h11
-rw-r--r--include/clang/AST/DeclObjC.h46
-rw-r--r--include/clang/AST/DeclTemplate.h112
-rw-r--r--include/clang/AST/EvaluatedExprVisitor.h3
-rw-r--r--include/clang/AST/Expr.h508
-rw-r--r--include/clang/AST/ExprCXX.h280
-rw-r--r--include/clang/AST/ExprObjC.h40
-rw-r--r--include/clang/AST/ExternalASTSource.h67
-rw-r--r--include/clang/AST/NestedNameSpecifier.h140
-rw-r--r--include/clang/AST/PrettyPrinter.h26
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h118
-rw-r--r--include/clang/AST/Stmt.h168
-rw-r--r--include/clang/AST/StmtCXX.h82
-rw-r--r--include/clang/AST/StmtIterator.h1
-rw-r--r--include/clang/AST/TemplateBase.h27
-rw-r--r--include/clang/AST/Type.h325
-rw-r--r--include/clang/AST/TypeLoc.h157
-rw-r--r--include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h4
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h82
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValuesV2.h40
-rw-r--r--include/clang/Analysis/AnalysisContext.h60
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h3
-rw-r--r--include/clang/Analysis/CFG.h120
-rw-r--r--include/clang/Analysis/DomainSpecific/CocoaConventions.h2
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h8
-rw-r--r--include/clang/Analysis/ProgramPoint.h13
-rw-r--r--include/clang/Analysis/Visitors/CFGStmtVisitor.h5
-rw-r--r--include/clang/Basic/AddressSpaces.h44
-rw-r--r--include/clang/Basic/Attr.td55
-rw-r--r--include/clang/Basic/AttrKinds.h1
-rw-r--r--include/clang/Basic/Builtins.def9
-rw-r--r--include/clang/Basic/BuiltinsPTX.def62
-rw-r--r--include/clang/Basic/BuiltinsX86.def41
-rw-r--r--include/clang/Basic/CMakeLists.txt4
-rw-r--r--include/clang/Basic/ConvertUTF.h5
-rw-r--r--include/clang/Basic/DeclNodes.td4
-rw-r--r--include/clang/Basic/Diagnostic.h5
-rw-r--r--include/clang/Basic/Diagnostic.td14
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td10
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td31
-rw-r--r--include/clang/Basic/DiagnosticIDs.h26
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td10
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td73
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td284
-rw-r--r--include/clang/Basic/ExceptionSpecificationType.h39
-rw-r--r--include/clang/Basic/ExpressionTraits.h25
-rw-r--r--include/clang/Basic/FileManager.h17
-rw-r--r--include/clang/Basic/IdentifierTable.h77
-rw-r--r--include/clang/Basic/LangOptions.h24
-rw-r--r--include/clang/Basic/Makefile6
-rw-r--r--include/clang/Basic/OpenCL.h28
-rw-r--r--include/clang/Basic/PartialDiagnostic.h2
-rw-r--r--include/clang/Basic/SourceLocation.h9
-rw-r--r--include/clang/Basic/SourceManager.h152
-rw-r--r--include/clang/Basic/Specifiers.h1
-rw-r--r--include/clang/Basic/StmtNodes.td9
-rw-r--r--include/clang/Basic/TargetBuiltins.h11
-rw-r--r--include/clang/Basic/TargetInfo.h25
-rw-r--r--include/clang/Basic/TokenKinds.def97
-rw-r--r--include/clang/Basic/TypeTraits.h45
-rw-r--r--include/clang/Basic/Version.h5
-rw-r--r--include/clang/Basic/VersionTuple.h126
-rw-r--r--include/clang/Basic/arm_neon.td7
-rw-r--r--include/clang/Driver/Arg.h1
-rw-r--r--include/clang/Driver/CC1AsOptions.td6
-rw-r--r--include/clang/Driver/CC1Options.td62
-rw-r--r--include/clang/Driver/Driver.h32
-rw-r--r--include/clang/Driver/DriverDiagnostic.h3
-rw-r--r--include/clang/Driver/OptParser.td2
-rw-r--r--include/clang/Driver/Options.td51
-rw-r--r--include/clang/Driver/ToolChain.h9
-rw-r--r--include/clang/Frontend/ASTConsumers.h8
-rw-r--r--include/clang/Frontend/ASTUnit.h42
-rw-r--r--include/clang/Frontend/Analyses.def11
-rw-r--r--include/clang/Frontend/AnalyzerOptions.h7
-rw-r--r--include/clang/Frontend/ChainedDiagnosticClient.h3
-rw-r--r--include/clang/Frontend/CodeGenOptions.h17
-rw-r--r--include/clang/Frontend/CompilerInstance.h79
-rw-r--r--include/clang/Frontend/CompilerInvocation.h3
-rw-r--r--include/clang/Frontend/DeclContextXML.def113
-rw-r--r--include/clang/Frontend/DeclXML.def372
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h8
-rw-r--r--include/clang/Frontend/DocumentXML.def75
-rw-r--r--include/clang/Frontend/DocumentXML.h185
-rw-r--r--include/clang/Frontend/FrontendActions.h6
-rw-r--r--include/clang/Frontend/FrontendDiagnostic.h3
-rw-r--r--include/clang/Frontend/FrontendOptions.h1
-rw-r--r--include/clang/Frontend/LangStandard.h16
-rw-r--r--include/clang/Frontend/LangStandards.def14
-rw-r--r--include/clang/Frontend/LogDiagnosticPrinter.h77
-rw-r--r--include/clang/Frontend/MultiplexConsumer.h5
-rw-r--r--include/clang/Frontend/PreprocessorOptions.h8
-rw-r--r--include/clang/Frontend/StmtXML.def520
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h7
-rw-r--r--include/clang/Frontend/TypeXML.def304
-rw-r--r--include/clang/Frontend/Utils.h17
-rw-r--r--include/clang/Lex/DirectoryLookup.h22
-rw-r--r--include/clang/Lex/HeaderMap.h5
-rw-r--r--include/clang/Lex/HeaderSearch.h51
-rw-r--r--include/clang/Lex/LexDiagnostic.h3
-rw-r--r--include/clang/Lex/Lexer.h15
-rw-r--r--include/clang/Lex/LiteralSupport.h1
-rw-r--r--include/clang/Lex/MacroInfo.h1
-rw-r--r--include/clang/Lex/MultipleIncludeOpt.h2
-rw-r--r--include/clang/Lex/PPCallbacks.h28
-rw-r--r--include/clang/Lex/PTHLexer.h1
-rw-r--r--include/clang/Lex/Pragma.h1
-rw-r--r--include/clang/Lex/PreprocessingRecord.h4
-rw-r--r--include/clang/Lex/Preprocessor.h76
-rw-r--r--include/clang/Lex/PreprocessorLexer.h5
-rw-r--r--include/clang/Makefile16
-rw-r--r--include/clang/Parse/ParseDiagnostic.h3
-rw-r--r--include/clang/Parse/Parser.h205
-rw-r--r--include/clang/Rewrite/FrontendActions.h2
-rw-r--r--include/clang/Rewrite/Rewriter.h71
-rw-r--r--include/clang/Sema/AttributeList.h373
-rw-r--r--include/clang/Sema/DeclSpec.h342
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h18
-rw-r--r--include/clang/Sema/IdentifierResolver.h18
-rw-r--r--include/clang/Sema/Initialization.h13
-rw-r--r--include/clang/Sema/Lookup.h1
-rw-r--r--include/clang/Sema/Overload.h3
-rw-r--r--include/clang/Sema/Ownership.h13
-rw-r--r--include/clang/Sema/ParsedTemplate.h13
-rw-r--r--include/clang/Sema/Scope.h76
-rw-r--r--include/clang/Sema/Sema.h673
-rw-r--r--include/clang/Sema/SemaDiagnostic.h3
-rw-r--r--include/clang/Sema/Template.h2
-rw-r--r--include/clang/Sema/TemplateDeduction.h2
-rw-r--r--include/clang/Serialization/ASTBitCodes.h20
-rw-r--r--include/clang/Serialization/ASTReader.h25
-rw-r--r--include/clang/Serialization/ASTWriter.h9
-rw-r--r--include/clang/Serialization/ChainedIncludesSource.h76
-rw-r--r--include/clang/StaticAnalyzer/Checkers/CheckerBase.td11
-rw-r--r--include/clang/StaticAnalyzer/Checkers/LocalCheckers.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h (renamed from include/clang/StaticAnalyzer/Core/CheckerV2.h)126
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h206
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerProvider.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h166
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def48
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h103
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h38
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h109
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h16
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h26
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h155
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h27
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h50
-rw-r--r--include/clang/Tooling/Tooling.h81
-rw-r--r--lib/AST/ASTContext.cpp296
-rw-r--r--lib/AST/ASTDiagnostic.cpp7
-rw-r--r--lib/AST/ASTImporter.cpp237
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/CXXInheritance.cpp2
-rw-r--r--lib/AST/Decl.cpp417
-rw-r--r--lib/AST/DeclBase.cpp181
-rw-r--r--lib/AST/DeclCXX.cpp404
-rw-r--r--lib/AST/DeclObjC.cpp69
-rw-r--r--lib/AST/DeclPrinter.cpp59
-rw-r--r--lib/AST/DeclTemplate.cpp256
-rw-r--r--lib/AST/DumpXML.cpp19
-rw-r--r--lib/AST/Expr.cpp368
-rw-r--r--lib/AST/ExprCXX.cpp156
-rw-r--r--lib/AST/ExprClassification.cpp38
-rw-r--r--lib/AST/ExprConstant.cpp372
-rw-r--r--lib/AST/ExternalASTSource.cpp59
-rw-r--r--lib/AST/InheritViz.cpp39
-rw-r--r--lib/AST/ItaniumCXXABI.cpp2
-rw-r--r--lib/AST/ItaniumMangle.cpp558
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp2
-rw-r--r--lib/AST/MicrosoftMangle.cpp15
-rw-r--r--lib/AST/NestedNameSpecifier.cpp246
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp141
-rw-r--r--lib/AST/Stmt.cpp98
-rw-r--r--lib/AST/StmtDumper.cpp30
-rw-r--r--lib/AST/StmtIterator.cpp2
-rw-r--r--lib/AST/StmtPrinter.cpp148
-rw-r--r--lib/AST/StmtProfile.cpp58
-rw-r--r--lib/AST/TemplateBase.cpp12
-rw-r--r--lib/AST/TemplateName.cpp4
-rw-r--r--lib/AST/Type.cpp291
-rw-r--r--lib/AST/TypeLoc.cpp87
-rw-r--r--lib/AST/TypePrinter.cpp76
-rw-r--r--lib/Analysis/AnalysisContext.cpp118
-rw-r--r--lib/Analysis/CFG.cpp652
-rw-r--r--lib/Analysis/CFGReachabilityAnalysis.cpp6
-rw-r--r--lib/Analysis/CFGStmtMap.cpp6
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Analysis/CocoaConventions.cpp92
-rw-r--r--lib/Analysis/PrintfFormatString.cpp43
-rw-r--r--lib/Analysis/ReachableCode.cpp10
-rw-r--r--lib/Analysis/UninitializedValues.cpp874
-rw-r--r--lib/Analysis/UninitializedValuesV2.cpp610
-rw-r--r--lib/Basic/CMakeLists.txt4
-rw-r--r--lib/Basic/Diagnostic.cpp23
-rw-r--r--lib/Basic/DiagnosticIDs.cpp144
-rw-r--r--lib/Basic/FileManager.cpp73
-rw-r--r--lib/Basic/IdentifierTable.cpp85
-rw-r--r--lib/Basic/SourceManager.cpp220
-rw-r--r--lib/Basic/TargetInfo.cpp12
-rw-r--r--lib/Basic/Targets.cpp227
-rw-r--r--lib/Basic/Version.cpp19
-rw-r--r--lib/Basic/VersionTuple.cpp36
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/BackendUtil.cpp29
-rw-r--r--lib/CodeGen/CGBlocks.cpp586
-rw-r--r--lib/CodeGen/CGBlocks.h4
-rw-r--r--lib/CodeGen/CGBuiltin.cpp230
-rw-r--r--lib/CodeGen/CGCXX.cpp103
-rw-r--r--lib/CodeGen/CGCXXABI.cpp4
-rw-r--r--lib/CodeGen/CGCall.cpp164
-rw-r--r--lib/CodeGen/CGCall.h26
-rw-r--r--lib/CodeGen/CGClass.cpp156
-rw-r--r--lib/CodeGen/CGCleanup.cpp23
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp399
-rw-r--r--lib/CodeGen/CGDebugInfo.h32
-rw-r--r--lib/CodeGen/CGDecl.cpp353
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp48
-rw-r--r--lib/CodeGen/CGException.cpp108
-rw-r--r--lib/CodeGen/CGException.h1
-rw-r--r--lib/CodeGen/CGExpr.cpp99
-rw-r--r--lib/CodeGen/CGExprAgg.cpp134
-rw-r--r--lib/CodeGen/CGExprCXX.cpp650
-rw-r--r--lib/CodeGen/CGExprComplex.cpp9
-rw-r--r--lib/CodeGen/CGExprConstant.cpp401
-rw-r--r--lib/CodeGen/CGExprScalar.cpp245
-rw-r--r--lib/CodeGen/CGObjC.cpp335
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp1416
-rw-r--r--lib/CodeGen/CGObjCMac.cpp364
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp310
-rw-r--r--lib/CodeGen/CGObjCRuntime.h24
-rw-r--r--lib/CodeGen/CGRTTI.cpp17
-rw-r--r--lib/CodeGen/CGRecordLayout.h5
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp188
-rw-r--r--lib/CodeGen/CGStmt.cpp360
-rw-r--r--lib/CodeGen/CGVTT.cpp45
-rw-r--r--lib/CodeGen/CGVTables.cpp539
-rw-r--r--lib/CodeGen/CGVTables.h26
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenAction.cpp2
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp138
-rw-r--r--lib/CodeGen/CodeGenFunction.h97
-rw-r--r--lib/CodeGen/CodeGenModule.cpp179
-rw-r--r--lib/CodeGen/CodeGenModule.h69
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp5
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp82
-rw-r--r--lib/CodeGen/CodeGenTypes.h14
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp55
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp2
-rw-r--r--lib/CodeGen/TargetInfo.cpp178
-rw-r--r--lib/Driver/Compilation.cpp6
-rw-r--r--lib/Driver/Driver.cpp117
-rw-r--r--lib/Driver/HostInfo.cpp7
-rw-r--r--lib/Driver/OptTable.cpp4
-rw-r--r--lib/Driver/ToolChain.cpp16
-rw-r--r--lib/Driver/ToolChains.cpp475
-rw-r--r--lib/Driver/ToolChains.h82
-rw-r--r--lib/Driver/Tools.cpp504
-rw-r--r--lib/Driver/Tools.h3
-rw-r--r--lib/Frontend/ASTConsumers.cpp39
-rw-r--r--lib/Frontend/ASTUnit.cpp463
-rw-r--r--lib/Frontend/CMakeLists.txt6
-rw-r--r--lib/Frontend/CacheTokens.cpp6
-rw-r--r--lib/Frontend/CompilerInstance.cpp107
-rw-r--r--lib/Frontend/CompilerInvocation.cpp117
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp90
-rw-r--r--lib/Frontend/DeclXML.cpp183
-rw-r--r--lib/Frontend/DependencyFile.cpp2
-rw-r--r--lib/Frontend/DocumentXML.cpp381
-rw-r--r--lib/Frontend/FrontendAction.cpp31
-rw-r--r--lib/Frontend/FrontendActions.cpp7
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp32
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp124
-rw-r--r--lib/Frontend/InitPreprocessor.cpp37
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp146
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp19
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp2
-rw-r--r--lib/Frontend/StmtXML.cpp439
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp34
-rw-r--r--lib/Frontend/TypeXML.cpp119
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp1
-rw-r--r--lib/Headers/CMakeLists.txt30
-rw-r--r--lib/Headers/avxintrin.h42
-rw-r--r--lib/Headers/emmintrin.h10
-rw-r--r--lib/Headers/mm3dnow.h161
-rw-r--r--lib/Headers/mm_malloc.h2
-rw-r--r--lib/Headers/stddef.h5
-rw-r--r--lib/Headers/stdint.h37
-rw-r--r--lib/Headers/xmmintrin.h2
-rw-r--r--lib/Index/DeclReferenceMap.cpp2
-rw-r--r--lib/Index/Entity.cpp2
-rw-r--r--lib/Lex/HeaderMap.cpp4
-rw-r--r--lib/Lex/HeaderSearch.cpp123
-rw-r--r--lib/Lex/Lexer.cpp104
-rw-r--r--lib/Lex/LiteralSupport.cpp2
-rw-r--r--lib/Lex/MacroArgs.cpp2
-rw-r--r--lib/Lex/PPDirectives.cpp128
-rw-r--r--lib/Lex/PPExpressions.cpp18
-rw-r--r--lib/Lex/PPLexerChange.cpp20
-rw-r--r--lib/Lex/PPMacroExpansion.cpp39
-rw-r--r--lib/Lex/PTHLexer.cpp4
-rw-r--r--lib/Lex/Pragma.cpp26
-rw-r--r--lib/Lex/PreprocessingRecord.cpp15
-rw-r--r--lib/Lex/Preprocessor.cpp52
-rw-r--r--lib/Lex/PreprocessorLexer.cpp2
-rw-r--r--lib/Lex/TokenLexer.cpp8
-rwxr-xr-xlib/Makefile3
-rw-r--r--lib/Parse/ParseAST.cpp23
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp52
-rw-r--r--lib/Parse/ParseDecl.cpp832
-rw-r--r--lib/Parse/ParseDeclCXX.cpp440
-rw-r--r--lib/Parse/ParseExpr.cpp302
-rw-r--r--lib/Parse/ParseExprCXX.cpp322
-rw-r--r--lib/Parse/ParseInit.cpp2
-rw-r--r--lib/Parse/ParseObjc.cpp95
-rw-r--r--lib/Parse/ParsePragma.cpp44
-rw-r--r--lib/Parse/ParsePragma.h10
-rw-r--r--lib/Parse/ParseStmt.cpp438
-rw-r--r--lib/Parse/ParseTemplate.cpp151
-rw-r--r--lib/Parse/ParseTentative.cpp21
-rw-r--r--lib/Parse/Parser.cpp144
-rw-r--r--lib/Parse/RAIIObjectsForParser.h26
-rw-r--r--lib/Rewrite/RewriteObjC.cpp160
-rw-r--r--lib/Rewrite/Rewriter.cpp177
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp279
-rw-r--r--lib/Sema/AttributeList.cpp100
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp17
-rw-r--r--lib/Sema/DeclSpec.cpp331
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp51
-rw-r--r--lib/Sema/IdentifierResolver.cpp46
-rw-r--r--lib/Sema/JumpDiagnostics.cpp5
-rw-r--r--lib/Sema/Scope.cpp57
-rw-r--r--lib/Sema/Sema.cpp144
-rw-r--r--lib/Sema/SemaAccess.cpp16
-rw-r--r--lib/Sema/SemaAttr.cpp12
-rw-r--r--lib/Sema/SemaCXXCast.cpp366
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp85
-rw-r--r--lib/Sema/SemaChecking.cpp314
-rw-r--r--lib/Sema/SemaCodeComplete.cpp166
-rw-r--r--lib/Sema/SemaDecl.cpp1222
-rw-r--r--lib/Sema/SemaDeclAttr.cpp361
-rw-r--r--lib/Sema/SemaDeclCXX.cpp710
-rw-r--r--lib/Sema/SemaDeclObjC.cpp105
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp304
-rw-r--r--lib/Sema/SemaExpr.cpp2844
-rw-r--r--lib/Sema/SemaExprCXX.cpp1068
-rw-r--r--lib/Sema/SemaExprObjC.cpp219
-rw-r--r--lib/Sema/SemaInit.cpp240
-rw-r--r--lib/Sema/SemaLookup.cpp53
-rw-r--r--lib/Sema/SemaObjCProperty.cpp46
-rw-r--r--lib/Sema/SemaOverload.cpp801
-rw-r--r--lib/Sema/SemaStmt.cpp494
-rw-r--r--lib/Sema/SemaTemplate.cpp726
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp125
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp117
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp236
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp5
-rw-r--r--lib/Sema/SemaType.cpp396
-rw-r--r--lib/Sema/TargetAttributesSema.cpp2
-rw-r--r--lib/Sema/TreeTransform.h1475
-rw-r--r--lib/Sema/TypeLocBuilder.h3
-rw-r--r--lib/Serialization/ASTCommon.cpp2
-rw-r--r--lib/Serialization/ASTCommon.h4
-rw-r--r--lib/Serialization/ASTReader.cpp273
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp219
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp195
-rw-r--r--lib/Serialization/ASTWriter.cpp215
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp57
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp119
-rw-r--r--lib/Serialization/CMakeLists.txt3
-rw-r--r--lib/Serialization/ChainedIncludesSource.cpp235
-rw-r--r--lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp29
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp44
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp90
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp204
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h35
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt3
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp309
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp121
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp216
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td414
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp118
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h2
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp69
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp26
-rw-r--r--lib/StaticAnalyzer/Checkers/ExperimentalChecks.h31
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp40
-rw-r--r--lib/StaticAnalyzer/Checkers/InternalChecks.h48
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp582
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp187
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp380
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp30
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp15
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp38
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp28
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp28
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp39
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp37
-rw-r--r--lib/StaticAnalyzer/Core/AggExprVisitor.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/BasicStore.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp63
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt9
-rw-r--r--lib/StaticAnalyzer/Core/CXXExprEngine.cpp300
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp (renamed from lib/StaticAnalyzer/Core/Checker.cpp)10
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp97
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp23
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp19
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp (renamed from lib/StaticAnalyzer/Checkers/ExprEngine.cpp)1099
-rw-r--r--lib/StaticAnalyzer/Core/FlatStore.cpp13
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp56
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp77
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp139
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp30
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp4
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp91
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp5
-rw-r--r--lib/Tooling/CMakeLists.txt6
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.cpp214
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.h107
-rw-r--r--lib/Tooling/Makefile15
-rw-r--r--lib/Tooling/Tooling.cpp322
-rw-r--r--runtime/CMakeLists.txt1
-rw-r--r--runtime/Makefile108
-rw-r--r--runtime/compiler-rt/Makefile114
-rw-r--r--runtime/libcxx/Makefile63
-rw-r--r--test/ASTMerge/var.c2
-rw-r--r--test/Analysis/CFDateGC.m10
-rw-r--r--test/Analysis/CFNumber.c8
-rw-r--r--test/Analysis/CFRetainRelease_NSAssertionHandler.m8
-rw-r--r--test/Analysis/CGColorSpace.c8
-rw-r--r--test/Analysis/CheckNSError.m8
-rw-r--r--test/Analysis/MissingDealloc.m2
-rw-r--r--test/Analysis/NSPanel.m8
-rw-r--r--test/Analysis/NSString.m23
-rw-r--r--test/Analysis/NSWindow.m8
-rw-r--r--test/Analysis/NoReturn.m8
-rw-r--r--test/Analysis/OSAtomic_mac.cpp19
-rw-r--r--test/Analysis/ObjCProperties.m8
-rw-r--r--test/Analysis/ObjCRetSigs.m2
-rw-r--r--test/Analysis/PR2599.m8
-rw-r--r--test/Analysis/PR2978.m2
-rw-r--r--test/Analysis/PR3991.m8
-rw-r--r--test/Analysis/PR7218.c2
-rw-r--r--test/Analysis/PR9741.cpp8
-rw-r--r--test/Analysis/additive-folding-range-constraints.c2
-rw-r--r--test/Analysis/additive-folding.c4
-rw-r--r--test/Analysis/analyzer-stats.c2
-rw-r--r--test/Analysis/array-struct-region.c4
-rw-r--r--test/Analysis/array-struct.c8
-rw-r--r--test/Analysis/auto-obj-dtors-cfg-output.cpp150
-rw-r--r--test/Analysis/base-init.cpp3
-rw-r--r--test/Analysis/blocks.m2
-rw-r--r--test/Analysis/bstring.c111
-rw-r--r--test/Analysis/casts.c4
-rw-r--r--test/Analysis/casts.m4
-rw-r--r--test/Analysis/cfref_PR2519.c8
-rw-r--r--test/Analysis/cfref_rdar6080742.c8
-rw-r--r--test/Analysis/chroot.c2
-rw-r--r--test/Analysis/complex.c8
-rw-r--r--test/Analysis/concrete-address.c4
-rw-r--r--test/Analysis/conditional-op-missing-lhs.c26
-rw-r--r--test/Analysis/constant-folding.c2
-rw-r--r--test/Analysis/cxx-crashes.cpp13
-rw-r--r--test/Analysis/dead-stores.c10
-rw-r--r--test/Analysis/dead-stores.cpp10
-rw-r--r--test/Analysis/dead-stores.m4
-rw-r--r--test/Analysis/delegates.m4
-rw-r--r--test/Analysis/derived-to-base.cpp2
-rw-r--r--test/Analysis/dtor.cpp2
-rw-r--r--test/Analysis/elementtype.c2
-rw-r--r--test/Analysis/exercise-ps.c4
-rw-r--r--test/Analysis/fields.c4
-rw-r--r--test/Analysis/flat-store.c2
-rw-r--r--test/Analysis/free.c2
-rw-r--r--test/Analysis/func.c4
-rw-r--r--test/Analysis/idempotent-operations-limited-loops.c6
-rw-r--r--test/Analysis/idempotent-operations.c9
-rw-r--r--test/Analysis/idempotent-operations.cpp21
-rw-r--r--test/Analysis/idempotent-operations.m14
-rw-r--r--test/Analysis/initializer.cpp2
-rw-r--r--test/Analysis/inline.c3
-rw-r--r--test/Analysis/inline2.c2
-rw-r--r--test/Analysis/inline3.c2
-rw-r--r--test/Analysis/inline4.c2
-rw-r--r--test/Analysis/iterators.cpp105
-rw-r--r--test/Analysis/lvalue.cpp2
-rw-r--r--test/Analysis/malloc.c28
-rw-r--r--test/Analysis/method-arg-decay.m (renamed from test/SemaObjC/method-arg-decay.m)2
-rw-r--r--test/Analysis/method-call.cpp2
-rw-r--r--test/Analysis/misc-ps-64.m8
-rw-r--r--test/Analysis/misc-ps-basic-store.m2
-rw-r--r--test/Analysis/misc-ps-eager-assume.m4
-rw-r--r--test/Analysis/misc-ps-flat-store.c2
-rw-r--r--test/Analysis/misc-ps-ranges.m4
-rw-r--r--test/Analysis/misc-ps-region-store-i386.m2
-rw-r--r--test/Analysis/misc-ps-region-store-x86_64.m2
-rw-r--r--test/Analysis/misc-ps-region-store.cpp159
-rw-r--r--test/Analysis/misc-ps-region-store.m66
-rw-r--r--test/Analysis/misc-ps-region-store.mm4
-rw-r--r--test/Analysis/misc-ps.m48
-rw-r--r--test/Analysis/new.cpp2
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m2
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m12
-rw-r--r--test/Analysis/no-exit-cfg.c4
-rw-r--r--test/Analysis/no-outofbounds.c8
-rw-r--r--test/Analysis/null-deref-ps-region.c2
-rw-r--r--test/Analysis/null-deref-ps.c8
-rw-r--r--test/Analysis/nullptr.cpp41
-rw-r--r--test/Analysis/operator-calls.cpp2
-rw-r--r--test/Analysis/out-of-bounds.c11
-rw-r--r--test/Analysis/outofbound.c2
-rw-r--r--test/Analysis/override-werror.c4
-rw-r--r--test/Analysis/plist-output-alternate.m2
-rw-r--r--test/Analysis/plist-output.m2
-rw-r--r--test/Analysis/pr4209.m4
-rw-r--r--test/Analysis/pr_2542_rdar_6793404.m4
-rw-r--r--test/Analysis/pr_4164.c4
-rw-r--r--test/Analysis/properties.m2
-rw-r--r--test/Analysis/ptr-arith.c4
-rw-r--r--test/Analysis/rdar-6442306-1.m4
-rw-r--r--test/Analysis/rdar-6540084.m2
-rw-r--r--test/Analysis/rdar-6541136-region.c2
-rw-r--r--test/Analysis/rdar-6541136.c2
-rw-r--r--test/Analysis/rdar-6562655.m4
-rw-r--r--test/Analysis/rdar-6582778-basic-store.c2
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m4
-rw-r--r--test/Analysis/rdar-7168531.m4
-rw-r--r--test/Analysis/refcnt_naming.m4
-rw-r--r--test/Analysis/reference.cpp2
-rw-r--r--test/Analysis/region-1.m4
-rw-r--r--test/Analysis/retain-release-basic-store.m2
-rw-r--r--test/Analysis/retain-release-gc-only.m4
-rw-r--r--test/Analysis/retain-release-region-store.m2
-rw-r--r--test/Analysis/retain-release.m26
-rw-r--r--test/Analysis/security-syntax-checks-no-emit.c2
-rw-r--r--test/Analysis/security-syntax-checks.m63
-rw-r--r--test/Analysis/self-init.m2
-rw-r--r--test/Analysis/stack-addr-ps.c4
-rw-r--r--test/Analysis/stackaddrleak.c2
-rw-r--r--test/Analysis/stream.c2
-rw-r--r--test/Analysis/string.c448
-rw-r--r--test/Analysis/undef-buffers.c2
-rw-r--r--test/Analysis/uninit-msg-expr.m4
-rw-r--r--test/Analysis/uninit-ps-rdar6145427.m4
-rw-r--r--test/Analysis/uninit-vals-ps-region.m2
-rw-r--r--test/Analysis/uninit-vals-ps.c4
-rw-r--r--test/Analysis/uninit-vals.c53
-rw-r--r--test/Analysis/uninit-vals.m4
-rw-r--r--test/Analysis/unions-region.m2
-rw-r--r--test/Analysis/unix-fns.c4
-rw-r--r--test/Analysis/unreachable-code-path.c2
-rw-r--r--test/Analysis/unused-ivars.m2
-rw-r--r--test/Analysis/variadic-method-types.m93
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp2
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp68
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp26
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp2
-rw-r--r--test/CXX/class.access/p4.cpp2
-rw-r--r--test/CXX/class.derived/p8-0x.cpp22
-rw-r--r--test/CXX/class/class.mem/p2.cpp31
-rw-r--r--test/CXX/class/class.mem/p8-0x-pedantic.cpp14
-rw-r--r--test/CXX/class/class.mem/p8-0x.cpp2
-rw-r--r--test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp17
-rw-r--r--test/CXX/class/class.union/p1.cpp34
-rw-r--r--test/CXX/class/p1-0x.cpp4
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp21
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp7
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp44
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp161
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.string/p2.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp2
-rw-r--r--test/CXX/except/except.handle/p16.cpp2
-rw-r--r--test/CXX/except/except.spec/p1.cpp60
-rw-r--r--test/CXX/except/except.spec/p11.cpp12
-rw-r--r--test/CXX/except/except.spec/p14.cpp2
-rw-r--r--test/CXX/except/except.spec/p15.cpp24
-rw-r--r--test/CXX/except/except.spec/p2-dynamic-types.cpp34
-rw-r--r--test/CXX/except/except.spec/p2-places.cpp63
-rw-r--r--test/CXX/except/except.spec/p3.cpp106
-rw-r--r--test/CXX/except/except.spec/p5-pointers.cpp85
-rw-r--r--test/CXX/except/except.spec/p5-virtual.cpp96
-rw-r--r--test/CXX/except/except.spec/p9-dynamic.cpp11
-rw-r--r--test/CXX/except/except.spec/p9-noexcept.cpp18
-rw-r--r--test/CXX/except/except.spec/template.cpp12
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp6
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp6
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.op/p6.cpp6
-rw-r--r--test/CXX/lex/lex.pptoken/p3-0x.cpp11
-rw-r--r--test/CXX/over/over.over/p2-resolve-single-template-id.cpp102
-rw-r--r--test/CXX/special/class.copy/p33-0x.cpp2
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp210
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp18
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p4.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.cpp6
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp6
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp63
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp12
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp8
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp65
-rw-r--r--test/CodeCompletion/PR9728.cpp9
-rw-r--r--test/CodeCompletion/ordinary-name.cpp58
-rw-r--r--test/CodeGen/2008-07-17-no-emit-on-error.c4
-rw-r--r--test/CodeGen/altivec.c31
-rw-r--r--test/CodeGen/arm-clear.c21
-rw-r--r--test/CodeGen/arm-pcs.c12
-rw-r--r--test/CodeGen/arm-vector-align.c19
-rw-r--r--test/CodeGen/atomic.c5
-rw-r--r--test/CodeGen/attr-availability.c31
-rw-r--r--test/CodeGen/block-byref-aggr.c17
-rw-r--r--test/CodeGen/builtin-attributes.c5
-rw-r--r--test/CodeGen/builtin-expect.c12
-rw-r--r--test/CodeGen/builtin-memfns.c35
-rw-r--r--test/CodeGen/builtinmemcpy.c3
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c325
-rw-r--r--test/CodeGen/builtins-ptx.c99
-rw-r--r--test/CodeGen/builtins-x86.c31
-rw-r--r--test/CodeGen/builtins.c2
-rw-r--r--test/CodeGen/char-literal.c2
-rw-r--r--test/CodeGen/conditional.c21
-rw-r--r--test/CodeGen/const-init.c4
-rw-r--r--test/CodeGen/darwin-string-literals.c4
-rw-r--r--test/CodeGen/debug-info-line2.c17
-rw-r--r--test/CodeGen/decl.c2
-rw-r--r--test/CodeGen/ext-vector.c134
-rw-r--r--test/CodeGen/integer-overflow.c14
-rw-r--r--test/CodeGen/mangle.c9
-rw-r--r--test/CodeGen/mmx-inline-asm.c22
-rw-r--r--test/CodeGen/mrtd.c15
-rw-r--r--test/CodeGen/ms_struct-bitfield-init.c68
-rw-r--r--test/CodeGen/ms_struct-bitfield.c131
-rw-r--r--test/CodeGen/mult-alt-x86.c56
-rw-r--r--test/CodeGen/packed-arrays.c157
-rw-r--r--test/CodeGen/ptx-cc.c9
-rw-r--r--test/CodeGen/regparm-flag.c5
-rw-r--r--test/CodeGen/switch-dce.c247
-rw-r--r--test/CodeGen/union.c2
-rw-r--r--test/CodeGen/x86_64-arguments-darwin.c17
-rw-r--r--test/CodeGen/x86_64-arguments.c22
-rw-r--r--test/CodeGenCXX/PR5863-unreachable-block.cpp2
-rw-r--r--test/CodeGenCXX/anonymous-namespaces.cpp2
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp19
-rw-r--r--test/CodeGenCXX/apple-kext-guard-variable.cpp9
-rw-r--r--test/CodeGenCXX/arm.cpp3
-rw-r--r--test/CodeGenCXX/blocks.cpp49
-rw-r--r--test/CodeGenCXX/class-layout.cpp28
-rw-r--r--test/CodeGenCXX/cxx0x-delegating-ctors.cpp48
-rw-r--r--test/CodeGenCXX/debug-info-byval.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-cxx0x.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-fn-template.cpp15
-rw-r--r--test/CodeGenCXX/debug-info-method-spec.cpp10
-rw-r--r--test/CodeGenCXX/debug-info-namespace.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-template.cpp24
-rw-r--r--test/CodeGenCXX/debug-info-this.cpp15
-rw-r--r--test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp2
-rw-r--r--test/CodeGenCXX/destructors.cpp2
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls.cpp10
-rw-r--r--test/CodeGenCXX/dynamic-cast-always-null.cpp19
-rw-r--r--test/CodeGenCXX/dynamic-cast.cpp2
-rw-r--r--test/CodeGenCXX/dyncast.cpp367
-rw-r--r--test/CodeGenCXX/eh.cpp2
-rw-r--r--test/CodeGenCXX/exceptions-no-rtti.cpp2
-rw-r--r--test/CodeGenCXX/exceptions.cpp87
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp2
-rw-r--r--test/CodeGenCXX/for-range-temporaries.cpp131
-rw-r--r--test/CodeGenCXX/for-range.cpp128
-rw-r--r--test/CodeGenCXX/global-init.cpp21
-rw-r--r--test/CodeGenCXX/goto.cpp2
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp60
-rw-r--r--test/CodeGenCXX/mangle-subst-std.cpp4
-rw-r--r--test/CodeGenCXX/mangle.cpp67
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp23
-rw-r--r--test/CodeGenCXX/nrvo.cpp2
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp10
-rw-r--r--test/CodeGenCXX/pragma-pack.cpp4
-rw-r--r--test/CodeGenCXX/references.cpp11
-rw-r--r--test/CodeGenCXX/specialized-static-data-mem-init.cpp4
-rw-r--r--test/CodeGenCXX/static-data-member.cpp4
-rw-r--r--test/CodeGenCXX/static-init-3.cpp4
-rw-r--r--test/CodeGenCXX/static-init.cpp4
-rw-r--r--test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp2
-rw-r--r--test/CodeGenCXX/threadsafe-statics-exceptions.cpp2
-rw-r--r--test/CodeGenCXX/threadsafe-statics.cpp10
-rw-r--r--test/CodeGenCXX/throw-expression-dtor.cpp2
-rw-r--r--test/CodeGenCXX/throw-expressions.cpp2
-rw-r--r--test/CodeGenCXX/try-catch.cpp2
-rw-r--r--test/CodeGenCXX/typeid.cpp22
-rw-r--r--test/CodeGenCXX/unknown-anytype.cpp99
-rw-r--r--test/CodeGenCXX/value-init.cpp58
-rw-r--r--test/CodeGenCXX/visibility.cpp11
-rw-r--r--test/CodeGenCXX/vtable-debug-info.cpp5
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp22
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp2
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp6
-rw-r--r--test/CodeGenObjC/atomic-aggregate-property.m2
-rw-r--r--test/CodeGenObjC/attr-availability.m24
-rw-r--r--test/CodeGenObjC/bitfield-access.m9
-rw-r--r--test/CodeGenObjC/blocks.m13
-rw-r--r--test/CodeGenObjC/constant-strings.m16
-rw-r--r--test/CodeGenObjC/debug-info-foreach.m7
-rw-r--r--test/CodeGenObjC/debug-info-getter-name.m9
-rw-r--r--test/CodeGenObjC/debug-info-property.m12
-rw-r--r--test/CodeGenObjC/fpret.m2
-rw-r--r--test/CodeGenObjC/instance-method-metadata.m34
-rw-r--r--test/CodeGenObjC/messages.m20
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m6
-rw-r--r--test/CodeGenObjC/metadata_symbols.m4
-rw-r--r--test/CodeGenObjC/misc-atomic-property.m80
-rw-r--r--test/CodeGenObjC/missing-atend-metadata.m24
-rw-r--r--test/CodeGenObjC/no-vararg-messaging.m18
-rw-r--r--test/CodeGenObjC/property-agrr-getter.m8
-rw-r--r--test/CodeGenObjC/simplify-exceptions.mm18
-rw-r--r--test/CodeGenObjCXX/exceptions.mm2
-rw-r--r--test/CodeGenObjCXX/ivar-objects.mm18
-rw-r--r--test/CodeGenObjCXX/message-reference.mm20
-rw-r--r--test/CodeGenObjCXX/property-reference.mm34
-rw-r--r--test/CodeGenObjCXX/references.mm2
-rw-r--r--test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl12
-rw-r--r--test/CodeGenOpenCL/address-spaces.cl27
-rw-r--r--test/Coverage/ast-printing.c1
-rw-r--r--test/Coverage/ast-printing.cpp1
-rw-r--r--test/Coverage/html-diagnostics.c2
-rw-r--r--test/Driver/apple-kext-i386.cpp9
-rw-r--r--test/Driver/apple-kext-mkernel.c24
-rw-r--r--test/Driver/ast.c2
-rw-r--r--test/Driver/cc-log-diagnostics.c29
-rw-r--r--test/Driver/cc-print-options.c2
-rw-r--r--test/Driver/clang-exception-flags.cpp23
-rw-r--r--test/Driver/clang-translation.c2
-rw-r--r--test/Driver/clang_f_opts.c17
-rw-r--r--test/Driver/clang_wrapv_opts.c11
-rw-r--r--test/Driver/darwin-cc.c7
-rw-r--r--test/Driver/darwin-dsymutil.c7
-rw-r--r--test/Driver/darwin-ld.c4
-rw-r--r--test/Driver/darwin-version.c8
-rw-r--r--test/Driver/darwin-xarch.c4
-rw-r--r--test/Driver/exceptions.m19
-rw-r--r--test/Driver/hello.c6
-rw-r--r--test/Driver/sysroot-flags.c14
-rw-r--r--test/FixIt/fixit-cxx0x.cpp3
-rw-r--r--test/FixIt/fixit-unrecoverable.c2
-rw-r--r--test/FixIt/fixit.c6
-rw-r--r--test/FixIt/fixit.cpp19
-rw-r--r--test/FixIt/no-macro-fixit.c16
-rw-r--r--test/FixIt/typo.c14
-rw-r--r--test/FixIt/typo.cpp12
-rw-r--r--test/FixIt/typo.m18
-rw-r--r--test/Frontend/dependency-gen.c3
-rw-r--r--test/Frontend/dependency-generation-crash.c4
-rw-r--r--test/Frontend/diagnostic-name.c5
-rw-r--r--test/Index/TestClassDecl.m2
-rw-r--r--test/Index/annotate-context-sensitive.cpp42
-rw-r--r--test/Index/annotate-nested-name-specifier.cpp328
-rw-r--r--test/Index/annotate-tokens.c50
-rw-r--r--test/Index/annotate-tokens.cpp89
-rw-r--r--test/Index/annotate-tokens.m31
-rw-r--r--test/Index/blocks.c8
-rw-r--r--test/Index/c-index-api-loadTU-test.m14
-rw-r--r--test/Index/c-index-getCursor-test.m6
-rw-r--r--test/Index/cindex-on-invalid.m17
-rw-r--r--test/Index/complete-objc-message.m12
-rw-r--r--test/Index/complete-properties.m27
-rw-r--r--test/Index/index-templates.cpp58
-rw-r--r--test/Index/initializer-memory.cpp16
-rw-r--r--test/Index/invalid-rdar-8236270.cpp2
-rw-r--r--test/Index/load-classes.cpp4
-rw-r--r--test/Index/load-exprs.c20
-rw-r--r--test/Index/load-namespaces.cpp16
-rw-r--r--test/Index/load-stmts.cpp16
-rw-r--r--test/Index/local-symbols.m2
-rw-r--r--test/Index/nested-binaryoperators.cpp4
-rw-r--r--test/Index/overrides.cpp4
-rw-r--r--test/Index/pragma-diag-reparse.c13
-rw-r--r--test/Index/preamble-reparse-chained.c4
-rw-r--r--test/Index/preamble.c4
-rw-r--r--test/Index/rdar-8288645-invalid-code.mm2
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp523
-rw-r--r--test/Index/recursive-member-access.c12
-rw-r--r--test/Index/remap-load.c2
-rw-r--r--test/Index/usrs-cxx0x.cpp2
-rw-r--r--test/Index/usrs.cpp50
-rw-r--r--test/Index/usrs.m44
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp38
-rw-r--r--test/Lexer/pragma-message.c2
-rw-r--r--test/Makefile42
-rw-r--r--test/Misc/Inputs/include.h1
-rw-r--r--test/Misc/caret-diags-macros.c23
-rw-r--r--test/Misc/include-stack-for-note-flag.cpp18
-rw-r--r--test/Misc/warn-in-system-header.c4
-rw-r--r--test/Misc/warn-in-system-header.h4
-rw-r--r--test/PCH/Inputs/working-directory-1.h5
-rw-r--r--test/PCH/chain-cxx.cpp35
-rw-r--r--test/PCH/chain-empty-initial-namespace.cpp24
-rw-r--r--test/PCH/chain-implicit-definition.cpp39
-rw-r--r--test/PCH/chain-late-anonymous-namespace.cpp61
-rw-r--r--test/PCH/chain-pending-instantiations.cpp33
-rw-r--r--test/PCH/cxx-chain-function-template.cpp32
-rw-r--r--test/PCH/cxx-for-range.cpp19
-rw-r--r--test/PCH/cxx-for-range.h35
-rw-r--r--test/PCH/cxx-reference.cpp6
-rw-r--r--test/PCH/cxx-reference.h13
-rw-r--r--test/PCH/cxx-templates.cpp29
-rw-r--r--test/PCH/cxx-templates.h12
-rw-r--r--test/PCH/cxx_exprs.cpp6
-rw-r--r--test/PCH/exprs.c5
-rw-r--r--test/PCH/exprs.h6
-rw-r--r--test/PCH/headersearch.cpp6
-rw-r--r--test/PCH/modified-header-crash.c10
-rw-r--r--test/PCH/modified-header-crash.h1
-rw-r--r--test/PCH/objcxx-ivar-class.h1
-rw-r--r--test/PCH/pragma-diag-section.cpp5
-rw-r--r--test/PCH/pragma-diag.c3
-rw-r--r--test/PCH/rdar8852495.c3
-rw-r--r--test/PCH/reloc.c2
-rw-r--r--test/PCH/source-manager-stack.c4
-rw-r--r--test/PCH/working-directory.cpp12
-rw-r--r--test/PCH/working-directory.h1
-rw-r--r--test/Parser/DelayedTemplateParsing.cpp42
-rw-r--r--test/Parser/MicrosoftExtensions.c2
-rw-r--r--test/Parser/MicrosoftExtensions.cpp53
-rw-r--r--test/Parser/altivec.c8
-rw-r--r--test/Parser/attr-availability.c20
-rw-r--r--test/Parser/c1x-generic-selection.c10
-rw-r--r--test/Parser/cxx-casting.cpp34
-rw-r--r--test/Parser/cxx-decl.cpp4
-rw-r--r--test/Parser/cxx-exception-spec.cpp17
-rw-r--r--test/Parser/cxx-member-crash.cpp15
-rw-r--r--test/Parser/cxx-stmt.cpp2
-rw-r--r--test/Parser/cxx-throw.cpp2
-rw-r--r--test/Parser/cxx0x-attributes.cpp2
-rw-r--r--test/Parser/cxx0x-override-control-keywords.cpp3
-rw-r--r--test/Parser/expressions.c6
-rw-r--r--test/Parser/objc-missing-impl.m2
-rw-r--r--test/Parser/objcxx-at.mm15
-rw-r--r--test/Parser/opencl-image-access.cl16
-rw-r--r--test/Parser/recovery.m5
-rw-r--r--test/Parser/selector-1.m26
-rw-r--r--test/Parser/switch-recovery.cpp124
-rw-r--r--test/Preprocessor/init.c14
-rw-r--r--test/Preprocessor/pragma-pushpop-macro.c2
-rw-r--r--test/Preprocessor/pragma_diagnostic_sections.cpp8
-rw-r--r--test/Preprocessor/pragma_unknown.c2
-rw-r--r--test/Preprocessor/stdint.c12
-rw-r--r--test/Preprocessor/traditional-cpp.c12
-rw-r--r--test/Rewriter/rewrite-block-literal-1.mm32
-rw-r--r--test/Rewriter/rewrite-block-pointer.mm17
-rw-r--r--test/Sema/__try.c171
-rw-r--r--test/Sema/align-x86-64.c14
-rw-r--r--test/Sema/align-x86.c26
-rw-r--r--test/Sema/altivec-init.c12
-rw-r--r--test/Sema/annotate.c2
-rw-r--r--test/Sema/anonymous-struct-union.c2
-rw-r--r--test/Sema/arm-layout.c2
-rw-r--r--test/Sema/attr-args.c40
-rw-r--r--test/Sema/attr-availability-ios.c21
-rw-r--r--test/Sema/attr-availability-macosx.c17
-rw-r--r--test/Sema/attr-availability.c6
-rw-r--r--test/Sema/attr-cleanup.c4
-rw-r--r--test/Sema/attr-naked.c2
-rw-r--r--test/Sema/attr-nodebug.c2
-rw-r--r--test/Sema/attr-noinline.c2
-rw-r--r--test/Sema/attr-noreturn.c4
-rw-r--r--test/Sema/attr-regparm.c2
-rw-r--r--test/Sema/attr-unused.c2
-rw-r--r--test/Sema/block-args.c5
-rw-r--r--test/Sema/builtins-decl.c8
-rw-r--r--test/Sema/builtins.c2
-rw-r--r--test/Sema/c89.c2
-rw-r--r--test/Sema/callingconv.c4
-rw-r--r--test/Sema/const-eval.c2
-rw-r--r--test/Sema/constructor-attribute.c4
-rw-r--r--test/Sema/conversion.c4
-rw-r--r--test/Sema/expr-address-of.c11
-rw-r--r--test/Sema/exprs.c16
-rw-r--r--test/Sema/format-strings-fixit.c26
-rw-r--r--test/Sema/function-redecl.c2
-rw-r--r--test/Sema/generic-selection.c26
-rw-r--r--test/Sema/incomplete-call.c6
-rw-r--r--test/Sema/knr-def-call.c6
-rw-r--r--test/Sema/memset-invalid.c6
-rw-r--r--test/Sema/missing-field-initializers.c2
-rw-r--r--test/Sema/neon-vector-types.c2
-rw-r--r--test/Sema/overloaded-func-transparent-union.c28
-rw-r--r--test/Sema/parentheses.c3
-rw-r--r--test/Sema/pragma-ms_struct.c34
-rw-r--r--test/Sema/sentinel-attribute.c2
-rw-r--r--test/Sema/shift.c10
-rw-r--r--test/Sema/static-assert.c11
-rw-r--r--test/Sema/struct-decl.c11
-rw-r--r--test/Sema/uninit-variables-vectors.c17
-rw-r--r--test/Sema/uninit-variables.c123
-rw-r--r--test/Sema/vector-ops.c3
-rw-r--r--test/Sema/warn-gnu-designators.c2
-rw-r--r--test/Sema/warn-unused-function.c6
-rw-r--r--test/Sema/warn-unused-value.c9
-rw-r--r--test/Sema/warn-write-strings.c2
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp86
-rw-r--r--test/SemaCXX/PR9459.cpp7
-rw-r--r--test/SemaCXX/PR9460.cpp19
-rw-r--r--test/SemaCXX/PR9461.cpp32
-rw-r--r--test/SemaCXX/PR9572.cpp15
-rw-r--r--test/SemaCXX/__try.cpp58
-rw-r--r--test/SemaCXX/addr-of-overloaded-function.cpp7
-rw-r--r--test/SemaCXX/address-space-conversion.cpp197
-rw-r--r--test/SemaCXX/address-space-newdelete.cpp24
-rw-r--r--test/SemaCXX/address-space-references.cpp19
-rw-r--r--test/SemaCXX/alignof-sizeof-reference.cpp6
-rw-r--r--test/SemaCXX/altivec.cpp30
-rw-r--r--test/SemaCXX/array-bounds.cpp53
-rw-r--r--test/SemaCXX/attr-nonnull.cpp6
-rw-r--r--test/SemaCXX/attr-unavailable.cpp2
-rw-r--r--test/SemaCXX/auto-subst-failure.cpp15
-rw-r--r--test/SemaCXX/conditional-expr.cpp2
-rw-r--r--test/SemaCXX/conversion-function.cpp25
-rw-r--r--test/SemaCXX/cxx0x-constexpr-const.cpp10
-rw-r--r--test/SemaCXX/cxx0x-delegating-ctors.cpp36
-rw-r--r--test/SemaCXX/cxx0x-return-init-list.cpp18
-rw-r--r--test/SemaCXX/decltype-98.cpp3
-rw-r--r--test/SemaCXX/decltype-overloaded-functions.cpp13
-rw-r--r--test/SemaCXX/destructor.cpp13
-rw-r--r--test/SemaCXX/enum-scoped.cpp6
-rw-r--r--test/SemaCXX/exception-spec-no-exceptions.cpp7
-rw-r--r--test/SemaCXX/exception-spec.cpp193
-rw-r--r--test/SemaCXX/exceptions.cpp2
-rw-r--r--test/SemaCXX/expression-traits.cpp620
-rw-r--r--test/SemaCXX/flexible-array-test.cpp16
-rw-r--r--test/SemaCXX/for-range-examples.cpp150
-rw-r--r--test/SemaCXX/for-range-no-std.cpp37
-rw-r--r--test/SemaCXX/friend.cpp4
-rw-r--r--test/SemaCXX/generic-selection.cpp46
-rw-r--r--test/SemaCXX/goto.cpp105
-rw-r--r--test/SemaCXX/goto2.cpp47
-rw-r--r--test/SemaCXX/init-priority-attr.cpp2
-rw-r--r--test/SemaCXX/libstdcxx_is_pod_hack.cpp16
-rw-r--r--test/SemaCXX/literal-type.cpp63
-rw-r--r--test/SemaCXX/member-expr.cpp5
-rw-r--r--test/SemaCXX/member-pointers-2.cpp15
-rw-r--r--test/SemaCXX/neon-vector-types.cpp27
-rw-r--r--test/SemaCXX/nested-name-spec-locations.cpp94
-rw-r--r--test/SemaCXX/nullptr.cpp2
-rw-r--r--test/SemaCXX/operator-arrow-temporary.cpp19
-rw-r--r--test/SemaCXX/overloaded-name.cpp12
-rw-r--r--test/SemaCXX/overloaded-operator.cpp15
-rw-r--r--test/SemaCXX/pascal-strings.cpp6
-rw-r--r--test/SemaCXX/pseudo-destructors.cpp7
-rw-r--r--test/SemaCXX/ptrtomember.cpp5
-rw-r--r--test/SemaCXX/reinterpret-cast.cpp16
-rw-r--r--test/SemaCXX/return-noreturn.cpp73
-rw-r--r--test/SemaCXX/return.cpp14
-rw-r--r--test/SemaCXX/rval-references.cpp2
-rw-r--r--test/SemaCXX/scope-check.cpp20
-rw-r--r--test/SemaCXX/short-enums.cpp17
-rw-r--r--test/SemaCXX/short-wchar-sign.cpp6
-rw-r--r--test/SemaCXX/sourceranges.cpp6
-rw-r--r--test/SemaCXX/static-cast.cpp6
-rw-r--r--test/SemaCXX/storage-class.cpp3
-rw-r--r--test/SemaCXX/type-traits.cpp1598
-rw-r--r--test/SemaCXX/uninit-variables-conditional.cpp23
-rw-r--r--test/SemaCXX/uninit-variables.cpp66
-rw-r--r--test/SemaCXX/uninitialized.cpp53
-rw-r--r--test/SemaCXX/unknown-anytype.cpp36
-rw-r--r--test/SemaCXX/unreachable-catch-clauses.cpp2
-rw-r--r--test/SemaCXX/unreachable-code.cpp2
-rw-r--r--test/SemaCXX/unused-functions.cpp4
-rw-r--r--test/SemaCXX/vtable-instantiation.cc26
-rw-r--r--test/SemaCXX/warn-assignment-condition.cpp13
-rw-r--r--test/SemaCXX/warn-bool-conversion.cpp24
-rw-r--r--test/SemaCXX/warn-deprecated-header.cpp6
-rw-r--r--test/SemaCXX/warn-exit-time-destructors.cpp27
-rw-r--r--test/SemaCXX/warn-global-constructors.cpp4
-rw-r--r--test/SemaCXX/warn-literal-conversion.cpp15
-rw-r--r--test/SemaCXX/warn-missing-prototypes.cpp6
-rw-r--r--test/SemaCXX/warn-non-pod-memset.cpp63
-rw-r--r--test/SemaCXX/warn-overloaded-virtual.cpp12
-rw-r--r--test/SemaCXX/warn-shadow.cpp11
-rw-r--r--test/SemaCXX/warn-unreachable.cpp2
-rw-r--r--test/SemaCXX/warn-unused-filescoped.cpp9
-rw-r--r--test/SemaCXX/warn-using-namespace-in-header.cpp54
-rw-r--r--test/SemaCXX/warn-using-namespace-in-header.h50
-rw-r--r--test/SemaCXX/warn_false_to_pointer.cpp10
-rw-r--r--test/SemaCXX/writable-strings-deprecated.cpp2
-rw-r--r--test/SemaObjC/assign-rvalue-message.m24
-rw-r--r--test/SemaObjC/attr-objc-gc.m26
-rw-r--r--test/SemaObjC/auto-objective-c.m33
-rw-r--r--test/SemaObjC/block-type-safety.m17
-rw-r--r--test/SemaObjC/call-super-2.m14
-rw-r--r--test/SemaObjC/class-message-protocol-lookup.m34
-rw-r--r--test/SemaObjC/class-unavail-warning.m24
-rw-r--r--test/SemaObjC/comptypes-4.m2
-rw-r--r--test/SemaObjC/conditional-expr-8.m25
-rw-r--r--test/SemaObjC/exprs.m4
-rw-r--r--test/SemaObjC/foreach.m30
-rw-r--r--test/SemaObjC/format-arg-attribute.m8
-rw-r--r--test/SemaObjC/iboutletcollection-attr.m4
-rw-r--r--test/SemaObjC/idiomatic-parentheses.m4
-rw-r--r--test/SemaObjC/ignore-weakimport-method.m1
-rw-r--r--test/SemaObjC/ivar-lookup.m12
-rw-r--r--test/SemaObjC/method-bad-param.m2
-rw-r--r--test/SemaObjC/method-not-defined.m6
-rw-r--r--test/SemaObjC/method-prototype-scope.m4
-rw-r--r--test/SemaObjC/method-sentinel-attr.m2
-rw-r--r--test/SemaObjC/missing-atend-metadata.m22
-rw-r--r--test/SemaObjC/nonnull.m27
-rw-r--r--test/SemaObjC/objc-qualified-property-lookup.m21
-rw-r--r--test/SemaObjC/property-13.m2
-rw-r--r--test/SemaObjC/property-lookup-in-id.m33
-rw-r--r--test/SemaObjC/protocol-attribute.m2
-rw-r--r--test/SemaObjC/self-declared-in-block.m51
-rw-r--r--test/SemaObjC/self-in-function.m26
-rw-r--r--test/SemaObjC/sizeof-interface.m2
-rw-r--r--test/SemaObjC/special-dep-unavail-warning.m8
-rw-r--r--test/SemaObjC/uninit-variables.m4
-rw-r--r--test/SemaObjC/unqualified-to-qualified-class-warn.m72
-rw-r--r--test/SemaObjC/warn-write-strings.m2
-rw-r--r--test/SemaObjC/weak-attr-ivar.m10
-rw-r--r--test/SemaObjCXX/argument-dependent-lookup.mm19
-rw-r--r--test/SemaObjCXX/exceptions-fragile.mm2
-rw-r--r--test/SemaObjCXX/goto.mm16
-rw-r--r--test/SemaObjCXX/objc-pointer-conv.mm2
-rw-r--r--test/SemaObjCXX/overload-gc.mm24
-rw-r--r--test/SemaObjCXX/overload.mm26
-rw-r--r--test/SemaObjCXX/parameters.mm5
-rw-r--r--test/SemaObjCXX/propert-dot-error.mm11
-rw-r--r--test/SemaObjCXX/property-reference.mm44
-rw-r--r--test/SemaObjCXX/references.mm6
-rw-r--r--test/SemaOpenCL/extension-fp64.cl8
-rw-r--r--test/SemaOpenCL/vec_step.cl32
-rw-r--r--test/SemaTemplate/address-spaces.cpp86
-rw-r--r--test/SemaTemplate/deduction-crash.cpp2
-rw-r--r--test/SemaTemplate/dependent-template-recover.cpp42
-rw-r--r--test/SemaTemplate/destructor-template.cpp7
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp9
-rw-r--r--test/SemaTemplate/instantiate-cast.cpp2
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp2
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp2
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp23
-rw-r--r--test/SemaTemplate/instantiate-member-template.cpp44
-rw-r--r--test/SemaTemplate/instantiate-try-catch.cpp2
-rw-r--r--test/SemaTemplate/issue150.cpp107
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp41
-rw-r--r--test/SemaTemplate/resolve-single-template-id.cpp80
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp9
-rw-r--r--test/SemaTemplate/typename-specifier-4.cpp8
-rw-r--r--test/lit.cfg9
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c39
-rw-r--r--tools/driver/CMakeLists.txt1
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/driver/cc1_main.cpp2
-rw-r--r--tools/driver/cc1as_main.cpp9
-rw-r--r--tools/driver/driver.cpp105
-rw-r--r--tools/libclang/CIndex.cpp807
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp21
-rw-r--r--tools/libclang/CIndexInclusionStack.cpp10
-rw-r--r--tools/libclang/CIndexUSRs.cpp10
-rw-r--r--tools/libclang/CIndexer.cpp5
-rw-r--r--tools/libclang/CMakeLists.txt64
-rw-r--r--tools/libclang/CXCursor.cpp9
-rw-r--r--tools/libclang/libclang.darwin.exports6
-rw-r--r--tools/libclang/libclang.exports4
-rwxr-xr-xtools/scan-build/ccc-analyzer66
-rwxr-xr-xtools/scan-build/scan-build30
-rw-r--r--unittests/CMakeLists.txt10
-rw-r--r--unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp232
-rw-r--r--unittests/Tooling/ToolingTest.cpp175
-rwxr-xr-xutils/CmpDriver2
-rw-r--r--utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c2
-rw-r--r--www/OpenProjects.html7
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/release_notes.html50
-rw-r--r--www/analyzer/scan-build.html2
-rw-r--r--www/cxx_status.html56
-rw-r--r--www/get_started.html15
-rw-r--r--www/hacking.html88
-rw-r--r--www/libstdc++4.4-clang0x.patch369
1142 files changed, 52310 insertions, 22408 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b1ab11de72df..7b54deaaf546 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,7 +30,7 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
include(AddLLVM)
include(TableGen)
- include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVM.cmake")
+ include("${CLANG_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
include(HandleLLVMOptions)
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
@@ -40,9 +40,6 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories("${PATH_TO_LLVM_BUILD}/include" "${LLVM_MAIN_INCLUDE_DIR}")
- if( NOT PATH_TO_LLVM_BUILD STREQUAL LLVM_MAIN_SRC_DIR )
- include_directories("${LLVM_MAIN_INCLUDE_DIR}")
- endif()
link_directories("${PATH_TO_LLVM_BUILD}/lib")
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/tblgen")
@@ -174,23 +171,12 @@ macro(add_clang_library name)
if( LLVM_COMMON_DEPENDS )
add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
endif( LLVM_COMMON_DEPENDS )
- if( LLVM_USED_LIBS )
- foreach(lib ${LLVM_USED_LIBS})
- target_link_libraries( ${name} ${lib} )
- endforeach(lib)
- endif( LLVM_USED_LIBS )
- if( LLVM_LINK_COMPONENTS )
- llvm_config(${name} ${LLVM_LINK_COMPONENTS})
- endif( LLVM_LINK_COMPONENTS )
- if (LLVM_COMMON_LIBS)
- target_link_libraries(${name} ${LLVM_COMMON_LIBS})
- endif()
- if( NOT MINGW )
- get_system_libs(llvm_system_libs)
- if( llvm_system_libs )
- target_link_libraries(${name} ${llvm_system_libs})
- endif()
- endif()
+
+ target_link_libraries( ${name} ${LLVM_USED_LIBS} )
+ llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
+ target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
+ link_system_libs( ${name} )
+
add_dependencies(${name} ClangDiagnosticCommon)
if(MSVC)
get_target_property(cflag ${name} COMPILE_FLAGS)
@@ -211,9 +197,9 @@ macro(add_clang_executable name)
set_target_properties(${name} PROPERTIES FOLDER "Clang executables")
endmacro(add_clang_executable)
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/include
+include_directories(BEFORE
${CMAKE_CURRENT_BINARY_DIR}/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
)
install(DIRECTORY include/
@@ -221,7 +207,6 @@ install(DIRECTORY include/
FILES_MATCHING
PATTERN "*.def"
PATTERN "*.h"
- PATTERN "*.td"
PATTERN ".svn" EXCLUDE
)
diff --git a/Makefile b/Makefile
index 1216dadd297e..b6c630aa10af 100644
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,9 @@ CPP.Flags += -I$(PROJ_SRC_DIR)/$(CLANG_LEVEL)/include -I$(PROJ_OBJ_DIR)/$(CLANG_
ifdef CLANG_VENDOR
CPP.Flags += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
endif
+ifdef CLANG_REPOSITORY_STRING
+CPP.Flags += -DCLANG_REPOSITORY_STRING='"$(CLANG_REPOSITORY_STRING)"'
+endif
# Disable -fstrict-aliasing. Darwin disables it by default (and LLVM doesn't
# work with it enabled with GCC), Clang/llvm-gcc don't support it yet, and newer
diff --git a/docs/DriverInternals.html b/docs/DriverInternals.html
index a7d2da37711e..4f5f0ae112f9 100644
--- a/docs/DriverInternals.html
+++ b/docs/DriverInternals.html
@@ -88,7 +88,7 @@
<h3 id="components">Flexible</h3>
<!--=======================================================================-->
- <p>The driver was designed to be flexible and easily accomodate
+ <p>The driver was designed to be flexible and easily accommodate
new uses as we grow the clang and LLVM infrastructure. As one
example, the driver can easily support the introduction of
tools which have an integrated assembler; something we hope to
@@ -218,7 +218,7 @@
<p>The clang driver can dump the results of this
stage using the <tt>-ccc-print-options</tt> flag (which
- must preceed any actual command line arguments). For
+ must precede any actual command line arguments). For
example:</p>
<pre>
$ <b>clang -ccc-print-options -Xarch_i386 -fomit-frame-pointer -Wa,-fast -Ifoo -I foo t.c</b>
@@ -490,7 +490,7 @@
<li>
<b>Specs</b>
- <p>The clang driver has no direct correspondant for
+ <p>The clang driver has no direct correspondent for
"specs". The majority of the functionality that is
embedded in specs is in the Tool specific argument
translation routines. The parts of specs which control the
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index 813015ecf659..961198938f20 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -412,7 +412,7 @@ it is rendered.
</p>
<!-- ==================================================== -->
-<h4 id="code-modification-hints">Code Modification Hints</h4>
+<h4 id="fix-it-hints">Fix-It Hints</h4>
<!-- ==================================================== -->
<p>In some cases, the front end emits diagnostics when it is clear
@@ -422,14 +422,14 @@ deprecated syntax that is easily rewritten into a more modern form.
Clang tries very hard to emit the diagnostic and recover gracefully
in these and other cases.</p>
-<p>However, for these cases where the fix is obvious, the diagnostic
-can be annotated with a code
-modification "hint" that describes how to change the code referenced
-by the diagnostic to fix the problem. For example, it might add the
-missing semicolon at the end of the statement or rewrite the use of a
-deprecated construct into something more palatable. Here is one such
-example C++ front end, where we warn about the right-shift operator
-changing meaning from C++98 to C++0x:</p>
+<p>However, for these cases where the fix is obvious, the diagnostic
+can be annotated with a hint (referred to as a "fix-it hint") that
+describes how to change the code referenced by the diagnostic to fix
+the problem. For example, it might add the missing semicolon at the
+end of the statement or rewrite the use of a deprecated construct
+into something more palatable. Here is one such example from the C++
+front end, where we warn about the right-shift operator changing
+meaning from C++98 to C++0x:</p>
<pre>
test.cpp:3:7: warning: use of right-shift operator ('&gt;&gt;') in template argument will require parentheses in C++0x
@@ -438,33 +438,31 @@ A&lt;100 &gt;&gt; 2&gt; *a;
( )
</pre>
-<p>Here, the code modification hint is suggesting that parentheses be
-added, and showing exactly where those parentheses would be inserted
-into the source code. The code modification hints themselves describe
-what changes to make to the source code in an abstract manner, which
-the text diagnostic printer renders as a line of "insertions" below
-the caret line. <a href="#DiagnosticClient">Other diagnostic
-clients</a> might choose to render the code differently (e.g., as
-markup inline) or even give the user the ability to automatically fix
-the problem.</p>
-
-<p>All code modification hints are described by the
-<code>CodeModificationHint</code> class, instances of which should be
-attached to the diagnostic using the &lt;&lt; operator in the same way
-that highlighted source ranges and arguments are passed to the
-diagnostic. Code modification hints can be created with one of three
-constructors:</p>
+<p>Here, the fix-it hint is suggesting that parentheses be added,
+and showing exactly where those parentheses would be inserted into the
+source code. The fix-it hints themselves describe what changes to make
+to the source code in an abstract manner, which the text diagnostic
+printer renders as a line of "insertions" below the caret line. <a
+href="#DiagnosticClient">Other diagnostic clients</a> might choose
+to render the code differently (e.g., as markup inline) or even give
+the user the ability to automatically fix the problem.</p>
+
+<p>All fix-it hints are described by the <code>FixItHint</code> class,
+instances of which should be attached to the diagnostic using the
+&lt;&lt; operator in the same way that highlighted source ranges and
+arguments are passed to the diagnostic. Fix-it hints can be created
+with one of three constructors:</p>
<dl>
- <dt><code>CodeModificationHint::CreateInsertion(Loc, Code)</code></dt>
+ <dt><code>FixItHint::CreateInsertion(Loc, Code)</code></dt>
<dd>Specifies that the given <code>Code</code> (a string) should be inserted
before the source location <code>Loc</code>.</dd>
- <dt><code>CodeModificationHint::CreateRemoval(Range)</code></dt>
+ <dt><code>FixItHint::CreateRemoval(Range)</code></dt>
<dd>Specifies that the code in the given source <code>Range</code>
should be removed.</dd>
- <dt><code>CodeModificationHint::CreateReplacement(Range, Code)</code></dt>
+ <dt><code>FixItHint::CreateReplacement(Range, Code)</code></dt>
<dd>Specifies that the code in the given source <code>Range</code>
should be removed, and replaced with the given <code>Code</code> string.</dd>
</dl>
@@ -821,7 +819,7 @@ code is vectorized on X86 and PowerPC hosts).</p>
within the filename.</li>
<li>When parsing a preprocessor directive (after "<tt>#</tt>") the
ParsingPreprocessorDirective mode is entered. This changes the parser to
- return EOM at a newline.</li>
+ return EOD at a newline.</li>
<li>The Lexer uses a LangOptions object to know whether trigraphs are enabled,
whether C++ or ObjC keywords are recognized, etc.</li>
</ul>
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index b0de13a91e9b..f86835a9d1df 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -38,6 +38,8 @@ td {
<li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
<li><a href="#cxx_lambdas">C++0x lambdas</a></li>
<li><a href="#cxx_nullptr">C++0x nullptr</a></li>
+ <li><a href="#cxx_override_control">C++0x override control</a></li>
+ <li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
<li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
<li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
<li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
@@ -46,14 +48,17 @@ td {
<li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
<li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
<li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
+ <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
</ul>
<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
<li><a href="#blocks">Blocks</a></li>
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
+<li><a href="#generic-selections">Generic Selections</a></li>
<li><a href="#builtins">Builtin Functions</a>
<ul>
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
<li><a href="#__builtin_unreachable">__builtin_unreachable</a></li>
+ <li><a href="#__sync_swap">__sync_swap</a></li>
</ul>
</li>
<li><a href="#targetspecific">Target-Specific Extensions</a>
@@ -61,11 +66,7 @@ td {
<li><a href="#x86-specific">X86/X86-64 Language Extensions</a></li>
</ul>
</li>
-<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a>
- <ul>
- <li><a href="#analyzerattributes">Analyzer Attributes</a></li>
- </ul>
-</li>
+<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
</ul>
<!-- ======================================================================= -->
@@ -83,7 +84,7 @@ more information on these extensions.</p>
<!-- ======================================================================= -->
<p>Language extensions can be very useful, but only if you know you can depend
-on them. In order to allow fine-grain features checks, we support two builtin
+on them. In order to allow fine-grain features checks, we support three builtin
function-like macros. This allows you to directly test for a feature in your
code without having to resort to something like autoconf or fragile "compiler
version checks".</p>
@@ -402,9 +403,19 @@ lambdas is enabled. clang does not currently implement this feature.</p>
<tt>nullptr</tt> is enabled. clang does not yet fully implement this
feature.</p>
+<h3 id="cxx_override_control">C++0x <tt>override control</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_override_control)</tt> to determine if support for
+the override control keywords is enabled.</p>
+
<h3 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h3>
<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> to determine if support for reference-qualified functions (e.g., member functions with <code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>) is enabled.</p>
+<h3 id="cxx_range_for">C++0x range-based for loop</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_range_for)</tt> to determine if support for
+the range-based for loop is enabled. </p>
+
<h3 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> to determine if support for
@@ -436,6 +447,11 @@ inline namespaces is enabled.</p>
<p>Use <tt>__has_feature(cxx_trailing_return)</tt> to determine if support for
the alternate function declaration syntax with trailing return type is enabled.</p>
+<h3 id="cxx_noexcept">C++0x noexcept</h3>
+
+<p>Use <tt>__has_feature(cxx_noexcept)</tt> to determine if support for
+noexcept exception specifications is enabled.</p>
+
<h3 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
<p>Use <tt>__has_feature(cxx_strong_enums)</tt> to determine if support for
@@ -595,6 +611,20 @@ caveats to this use of name mangling:</p>
<!-- ======================================================================= -->
+<h2 id="generic-selections">Generic Selections</h2>
+<!-- ======================================================================= -->
+
+<p>The C1X generic selection expression is available in all languages
+supported by Clang. The syntax is the same as that given in the C1X draft
+standard.</p>
+
+<p>In C, type compatibility is decided according to the rules given in the
+appropriate standard, but in C++, which lacks the type compatibility rules
+used in C, types are considered compatible only if they are equivalent.</p>
+
+<p>Query for this feature with __has_feature(generic_selections).</p>
+
+<!-- ======================================================================= -->
<h2 id="builtins">Builtin Functions</h2>
<!-- ======================================================================= -->
@@ -703,6 +733,36 @@ no arguments and produces a void result.
<p>Query for this feature with __has_builtin(__builtin_unreachable).</p>
+<!-- ======================================================================= -->
+<h3 id="__sync_swap">__sync_swap</h3>
+<!-- ======================================================================= -->
+
+<p><tt>__sync_swap</tt> is used to atomically swap integers or pointers in
+memory.
+</p>
+
+<p><b>Syntax:</b></p>
+
+<pre>
+<i>type</i> __sync_swap(<i>type</i> *ptr, <i>type</i> value, ...)
+</pre>
+
+<p><b>Example of Use:</b></p>
+
+<pre>
+int old_value = __sync_swap(&value, new_value);
+</pre>
+
+<p><b>Description:</b></p>
+
+<p>The __sync_swap() builtin extends the existing __sync_*() family of atomic
+intrinsics to allow code to atomically swap the current value with the new
+value. More importantly, it helps developers write more efficient and correct
+code by avoiding expensive loops around __sync_bool_compare_and_swap() or
+relying on the platform specific implementation details of
+__sync_lock_test_and_set(). The __sync_swap() builtin is a full barrier.
+</p>
+
<!-- ======================================================================= -->
<h2 id="targetspecific">Target-Specific Extensions</h2>
@@ -754,11 +814,7 @@ are used by the <a
href="http://clang.llvm.org/StaticAnalysis.html">path-sensitive static analyzer
engine</a> that is part of Clang's Analysis library.</p>
-<!-- ======================================================================= -->
-<h3 id="analyzerattributes">Analyzer Attributes</h3>
-<!-- ======================================================================= -->
-
-<h4 id="attr_analyzer_noreturn"><tt>analyzer_noreturn</tt></h4>
+<h3 id="attr_analyzer_noreturn">The <tt>analyzer_noreturn</tt> attribute</h3>
<p>Clang's static analysis engine understands the standard <tt>noreturn</tt>
attribute. This attribute, which is typically affixed to a function prototype,
@@ -786,16 +842,47 @@ placed at the end of function prototypes:</p>
void foo() <b>__attribute__((analyzer_noreturn))</b>;
</pre>
-<p>Query for this feature with __has_feature(attribute_analyzer_noreturn).</p>
+<p>Query for this feature with
+<tt>__has_attribute(analyzer_noreturn)</tt>.</p>
+
+<h3 id="attr_method_family">The <tt>objc_method_family</tt> attribute</h3>
-<h4 id="attr_retain_release">Objective-C retaining behavior attributes</h4>
+<p>Many methods in Objective-C have conventional meanings determined
+by their selectors. For the purposes of static analysis, it is
+sometimes useful to be able to mark a method as having a particular
+conventional meaning despite not having the right selector, or as not
+having the conventional meaning that its selector would suggest.
+For these use cases, we provide an attribute to specifically describe
+the <q>method family</q> that a method belongs to.</p>
+
+<p><b>Usage</b>: <tt>__attribute__((objc_method_family(X)))</tt>,
+where <tt>X</tt> is one of <tt>none</tt>, <tt>alloc</tt>, <tt>copy</tt>,
+<tt>init</tt>, <tt>mutableCopy</tt>, or <tt>new</tt>. This attribute
+can only be placed at the end of a method declaration:</p>
+
+<pre>
+ - (NSString*) initMyStringValue <b>__attribute__((objc_method_family(none)))</b>;
+</pre>
+
+<p>Users who do not wish to change the conventional meaning of a
+method, and who merely want to document its non-standard retain and
+release semantics, should use the
+<a href="#attr_retain_release">retaining behavior attributes</a>
+described below.</p>
+
+<p>Query for this feature with
+<tt>__has_attribute(objc_method_family)</tt>.</p>
+
+<h3 id="attr_retain_release">Objective-C retaining behavior attributes</h3>
<p>In Objective-C, functions and methods are generally assumed to take
and return objects with +0 retain counts, with some exceptions for
special methods like <tt>+alloc</tt> and <tt>init</tt>. However,
there are exceptions, and so Clang provides attributes to allow these
exceptions to be documented, which helps the analyzer find leaks (and
-ignore non-leaks).</p>
+ignore non-leaks). Some exceptions may be better described using
+the <a href="#attr_method_family"><tt>objc_method_family</tt></a>
+attribute instead.</p>
<p><b>Usage</b>: The <tt>ns_returns_retained</tt>, <tt>ns_returns_not_retained</tt>,
<tt>ns_returns_autoreleased</tt>, <tt>cf_returns_retained</tt>,
@@ -834,6 +921,9 @@ balance in some way.</p>
- (void) baz: (id) <b>__attribute__((ns_consumed))</b> x;
</pre>
+<p>Query for these features with <tt>__has_attribute(ns_consumed)</tt>,
+<tt>__has_attribute(ns_returns_retained)</tt>, etc.</p>
+
</div>
</body>
</html>
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 82c4fa27321e..73ca6c6980b3 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -32,7 +32,7 @@ td {
</li>
<li><a href="#general_features">Language and Target-Independent Features</a>
<ul>
- <li><a href="#diagnostics">Controlling Errors and Warnings</a></li>
+ <li><a href="#diagnostics">Controlling Errors and Warnings</a>
<ul>
<li><a href="#diagnostics_display">Controlling How Clang Displays Diagnostics</a></li>
<li><a href="#diagnostics_mappings">Diagnostic Mappings</a></li>
@@ -41,9 +41,10 @@ td {
<li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
<li><a href="#analyzer_diagnositics">Controlling Static Analyzer Diagnostics</a></li>
</ul>
+ </li>
<li><a href="#precompiledheaders">Precompiled Headers</a></li>
<li><a href="#codegen">Controlling Code Generation</a></li>
- </ul>
+ </ul>
</li>
<li><a href="#c">C Language Features</a>
<ul>
@@ -67,8 +68,8 @@ td {
<ul>
<li><a href="#target_os_darwin">Darwin (Mac OS/X)</a></li>
<li>Linux, etc.</li>
+ <li><a href="#target_os_win32">Windows</a></li>
</ul>
-
</li>
</ul>
</li>
@@ -205,7 +206,7 @@ diagnostics that it generates.</p>
diagnostic.</dt>
<dd>This option, which defaults to on, controls whether or not Clang prints the
column number of a diagnostic. For example, when this is enabled, Clang will
-print something like:</p>
+print something like:
<pre>
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
@@ -223,7 +224,7 @@ column number.</p>
source file/line/column information in diagnostic.</dt>
<dd>This option, which defaults to on, controls whether or not Clang prints the
filename, line number and column number of a diagnostic. For example,
-when this is enabled, Clang will print something like:</p>
+when this is enabled, Clang will print something like:
<pre>
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
@@ -240,7 +241,7 @@ when this is enabled, Clang will print something like:</p>
line and ranges from source code in diagnostic.</dt>
<dd>This option, which defaults to on, controls whether or not Clang prints the
source line, source ranges, and caret when emitting a diagnostic. For example,
-when this is enabled, Clang will print something like:</p>
+when this is enabled, Clang will print something like:
<pre>
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
@@ -277,7 +278,7 @@ Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
<dd>This option, which defaults to on,
controls whether or not Clang prints the associated <A
href="#cl_diag_warning_groups">warning group</a> option name when outputting
-a warning diagnostic. For example, in this output:</p>
+a warning diagnostic. For example, in this output:
<pre>
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
@@ -299,7 +300,7 @@ Enable printing category information in diagnostic line.</dt>
controls whether or not Clang prints the category associated with a diagnostic
when emitting it. Each diagnostic may or many not have an associated category,
if it has one, it is listed in the diagnostic categorization field of the
-diagnostic line (in the []'s).</p>
+diagnostic line (in the []'s).
<p>For example, a format string warning will produce these three renditions
based on the setting of this option:</p>
@@ -322,7 +323,7 @@ hundreds or thousands of them.</p>
Enable "FixIt" information in the diagnostics output.</dt>
<dd>This option, which defaults to on, controls whether or not Clang prints the
information on how to fix a specific diagnostic underneath it when it knows.
-For example, in this output:</p>
+For example, in this output:
<pre>
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
@@ -345,7 +346,7 @@ Print machine parsable information about source ranges.</dt>
information about source ranges in a machine parsable format after the
file/line/column number information. The information is a simple sequence of
brace enclosed ranges, where each range lists the start and end line/column
-locations. For example, in this output:</p>
+locations. For example, in this output:
<pre>
exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expression ('int *' and '_Complex float')
@@ -366,7 +367,14 @@ Print Fix-Its in a machine parseable form.</dt>
fix-it:"t.cpp":{7:25-7:29}:"Gamma"
</pre>
-<p>The range printed is a half-open range, so in this example the characters at column 25 up to but not including column 29 on line 7 in t.cpp should be replaced with the string "Gamma". Either the range or the replacement string may be empty (representing strict insertions and strict erasures, respectively). Both the file name and the insertion string escape backslash (as "\\"), tabs (as "\t"), newlines (as "\n"), double quotes(as "\"") and non-printable characters (as octal "\xxx").</p>
+<p>The range printed is a half-open range, so in this example the characters at
+column 25 up to but not including column 29 on line 7 in t.cpp should be
+replaced with the string &quot;Gamma&quot;. Either the range or the replacement
+string may be empty (representing strict insertions and strict erasures,
+respectively). Both the file name and the insertion string escape backslash (as
+&quot;\\&quot;), tabs (as &quot;\t&quot;), newlines (as &quot;\n&quot;), double
+quotes(as &quot;\&quot;&quot;) and non-printable characters (as octal
+&quot;\xxx&quot;).</p>
</dd>
</dl>
@@ -388,7 +396,7 @@ Print Fix-Its in a machine parseable form.</dt>
<dt id="opt_Wextra-tokens"><b>-Wextra-tokens</b>: Warn about excess tokens at
the end of a preprocessor directive.</dt>
<dd>This option, which defaults to on, enables warnings about extra tokens at
-the end of preprocessor directives. For example:</p>
+the end of preprocessor directives. For example:
<pre>
test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
@@ -408,7 +416,7 @@ by commenting them out.</p>
Warn about unqualified uses of a member template whose name resolves
to another template at the location of the use.</dt>
<dd>This option, which defaults to on, enables a warning in the
-following code:</p>
+following code:
<pre>
template&lt;typename T> struct set{};
@@ -432,7 +440,7 @@ an extension.</p>
an unusable copy constructor when binding a reference to a temporary.</dt>
<dd>This option, which defaults to on, enables warnings about binding a
reference to a temporary when the temporary doesn't have a usable copy
-constructor. For example:</p>
+constructor. For example:
<pre>
struct NonCopyable {
@@ -484,7 +492,6 @@ and gives you fine-grain control over which information is printed. Clang has
the ability to print this information, and these are the options that control
it:</p>
-<p>
<ol>
<li>A file/line/column indicator that shows exactly where the diagnostic occurs
in your code [<a href="#opt_fshow-column">-fshow-column</a>, <a
@@ -508,7 +515,7 @@ it:</p>
<li>A machine-parsable representation of the ranges involved (off by
default) [<a
href="opt_fdiagnostics-print-source-range-info">-fdiagnostics-print-source-range-info</a>].</li>
-</ol></p>
+</ol>
<p>For more information please see <a href="#cl_diag_formatting">Formatting of
Diagnostics</a>.</p>
@@ -518,14 +525,13 @@ Diagnostics</a>.</p>
<p>All diagnostics are mapped into one of these 5 classes:</p>
-<p>
<ul>
<li>Ignored</li>
<li>Note</li>
<li>Warning</li>
<li>Error</li>
<li>Fatal</li>
-</ul></p>
+</ul>
<h4 id="diagnostics_categories">Diagnostic Categories</h4>
@@ -735,6 +741,7 @@ likely to affect PCH files that reference a large number of headers.</p>
<p>Clang provides a number of ways to control code generation. The options are listed below.</p>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dl>
<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>: Turn
on runtime code generation to check for undefined behavior.</dt>
@@ -742,7 +749,7 @@ on runtime code generation to check for undefined behavior.</dt>
adds runtime checks for undefined runtime behavior. If a check fails,
<tt>__builtin_trap()</tt> is used to indicate failure.
The checks are:
-<p>
+<ul>
<li>Subscripting where the static type of one operand is a variable
which is decayed from an array type and the other operand is
greater than the size of the array or less than zero.</li>
@@ -752,7 +759,7 @@ The checks are:
<li>When llvm implements more __builtin_object_size support, reads and
writes for objects that __builtin_object_size indicates we aren't
accessing valid memory. Bit-fields and vectors are not yet checked.
-</p>
+</ul>
</dd>
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
@@ -761,6 +768,19 @@ Don't assume that the C++'s new operator is sane.</dt>
operator will always return a pointer that does not
alias any other pointer when the function returns.</dd>
+<dt id="opt_ftrap-function"><b>-ftrap-function=[name]</b>: Instruct code
+generator to emit a function call to the specified function name for
+<tt>__builtin_trap()</tt>.</dt>
+
+<dd>LLVM code generator translates <tt>__builtin_trap()</tt> to a trap
+instruction if it is supported by the target ISA. Otherwise, the builtin is
+translated into a call to <tt>abort</tt>. If this option is set, then the code
+generator will always lower the builtin to a call to the specified function
+regardless of whether the target ISA has a trap instruction. This option is
+useful for environments (e.g. deeply embedded) where a trap cannot be properly
+handled, or when some custom behavior is desired.</dd>
+</dl>
+
<!-- ======================================================================= -->
<h2 id="c">C Language Features</h2>
<!-- ======================================================================= -->
@@ -917,6 +937,7 @@ support is incomplete; enabling Microsoft extensions will silently drop
certain constructs (including __declspec and Microsoft-style asm statements).
</p>
+<ul>
<li>clang allows setting _MSC_VER with -fmsc-version=. It defaults to 1300 which
is the same as Visual C/C++ 2003. Any number is supported and can greatly affect
what Windows SDK and c++stdlib headers clang can compile. This option will be
@@ -930,6 +951,7 @@ record members can be declared using user defined typedefs.</li>
controlling record layout. GCC also contains support for this feature,
however where MSVC and GCC are incompatible clang follows the MSVC
definition.</li>
+</ul>
<!-- ======================================================================= -->
<h2 id="target_features">Target-Specific Features and Limitations</h2>
@@ -948,6 +970,10 @@ definition.</li>
(Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested to correctly
compile many large C, C++, Objective-C, and Objective-C++ codebases.</p>
+<p>On x86_64-mingw32, passing i128(by value) is incompatible to Microsoft x64
+calling conversion. You might need to tweak WinX86_64ABIInfo::classify()
+in lib/CodeGen/TargetInfo.cpp.</p>
+
<!-- ======================== -->
<h4 id="target_arch_arm">ARM</h4>
<!-- ======================== -->
@@ -985,6 +1011,44 @@ Generating assembly requires a suitable LLVM backend.
<p>No __thread support, 64-bit ObjC support requires SL tools.</p>
+<!-- ======================================= -->
+<h4 id="target_os_win32">Windows</h4>
+<!-- ======================================= -->
+
+<p>Experimental supports are on Cygming.</p>
+
+<h5>Cygwin</h5>
+
+<p>Clang works on Cygwin-1.7.</p>
+
+<h5>MinGW32</h5>
+
+<p>Clang works on some mingw32 distributions.
+Clang assumes directories as below;</p>
+
+<ul>
+<li><tt>C:/mingw/include</tt></li>
+<li><tt>C:/mingw/lib</tt></li>
+<li><tt>C:/mingw/lib/gcc/mingw32/4.[3-5].0/include/c++</tt></li>
+</ul>
+
+<p>On MSYS, a few tests might fail. It is due to <a href="http://llvm.org/bugs/show_bug.cgi?id=8520">Bug 8520</a> and is fixed in <a href="http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20110314/118106.html">LLVM's r127724</a>.</p>
+
+<h5>MinGW-w64</h5>
+
+<p>For x32(i686-w64-mingw32), it is not supported yet.</p>
+
+<p>For x64(x86_64-w64-mingw32), <a href="http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20110321/118499.html">an essential patch(LLVM's r128206)</a> would be needed. It is incompatible to <a href="http://tdm-gcc.tdragon.net/development">TDM-GCC</a> due to the definition of symbol &quot;<code>___chkstk</code>&quot;. Clang assumes as below;<p>
+
+<ul>
+<li><tt>C:/mingw/x86_64-w64-mingw32/include</tt></li>
+<li><tt>C:/mingw/x86_64-w64-mingw32/include/c++/4.5.[23]</tt></li>
+<li>GCC driver &quot;gcc.exe&quot; to build x86_64-w64-mingw32 binary.</li>
+</ul>
+
+<p><a href="http://llvm.org/bugs/show_bug.cgi?id=8833">Some tests might fail</a>
+on x64.</p>
+
</div>
</body>
</html>
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index 9f7a4483019e..704cc8743ba6 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -7,7 +7,7 @@ clang - the Clang C, C++, and Objective-C compiler
=head1 SYNOPSIS
B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g>
- [B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-O3>|B<-O4>]
+ [B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-Oz>|B<-O3>|B<-O4>]
B<-W>I<warnings...> B<-pedantic>
B<-I>I<dir...> B<-L>I<dir...>
B<-D>I<macro[=defn]>
@@ -53,7 +53,7 @@ parse errors. The output of this stage is an "Abstract Syntax Tree" (AST).
This stage translates an AST into low-level intermediate code (known as "LLVM
IR") and ultimately to machine code. This phase is responsible for optimizing
-the generated code and handling target-specfic code generation. The output of
+the generated code and handling target-specific code generation. The output of
this stage is typically called a ".s" file or "assembly" file.
Clang also supports the use of an integrated assembler, in which the code
@@ -263,12 +263,13 @@ may not exist on earlier ones.
=over
-=item B<-O0> B<-O1> B<-O2> B<-Os> B<-O3> B<-O4>
+=item B<-O0> B<-O1> B<-O2> B<-Os> B<-Oz> B<-O3> B<-O4>
Specify which optimization level to use. B<-O0> means "no optimization": this
level compiles the fastest and generates the most debuggable code. B<-O2> is a
moderate level of optimization which enables most optimizations. B<-Os> is like
-B<-O2> with extra optimizations to reduce code size. B<-O3> is like B<-O2>,
+B<-O2> with extra optimizations to reduce code size. B<-Oz> is like B<-Os>
+(and thus B<-O2>), but reduces code size further. B<-O3> is like B<-O2>,
except that it enables optimizations that take longer to perform or that may
generate larger code (in an attempt to make the program run faster). On
supported platforms, B<-O4> enables link-time optimization; object files are
@@ -356,18 +357,10 @@ Pass I<arg> to the static analyzer.
Pass I<arg> to the assembler.
-=item B<-Xclang> I<arg>
-
-Pass I<arg> to the clang compiler frontend.
-
=item B<-Xlinker> I<arg>
Pass I<arg> to the linker.
-=item B<-mllvm> I<arg>
-
-Pass I<arg> to the LLVM backend.
-
=item B<-Xpreprocessor> I<arg>
Pass I<arg> to the preprocessor.
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 9a32ee406523..8e16ef1c6cfb 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,3 +1,3 @@
add_subdirectory(clang-interpreter)
add_subdirectory(PrintFunctionNames)
-
+add_subdirectory(Tooling)
diff --git a/examples/Tooling/CMakeLists.txt b/examples/Tooling/CMakeLists.txt
new file mode 100644
index 000000000000..257d3ea8eaa3
--- /dev/null
+++ b/examples/Tooling/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(LLVM_USED_LIBS clangTooling clangBasic)
+
+add_clang_executable(clang-check
+ ClangCheck.cpp
+ )
+
diff --git a/examples/Tooling/ClangCheck.cpp b/examples/Tooling/ClangCheck.cpp
new file mode 100644
index 000000000000..41283759a104
--- /dev/null
+++ b/examples/Tooling/ClangCheck.cpp
@@ -0,0 +1,108 @@
+//===- examples/Tooling/ClangCheck.cpp - Clang check tool -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a clang-check tool that runs the
+// clang::SyntaxOnlyAction over a number of translation units.
+//
+// Usage:
+// clang-check <cmake-output-dir> <file1> <file2> ...
+//
+// Where <cmake-output-dir> is a CMake build directory in which a file named
+// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+// CMake to get this output).
+//
+// <file1> ... specify the paths of files in the CMake source tree. This path
+// is looked up in the compile command database. If the path of a file is
+// absolute, it needs to point into CMake's source tree. If the path is
+// relative, the current working directory needs to be in the CMake source
+// tree and the file must be in a subdirectory of the current working
+// directory. "./" prefixes in the relative files will be automatically
+// removed, but the rest of a relative path must be a suffix of a path in
+// the compile command line database.
+//
+// For example, to use clang-check on all files in a subtree of the source
+// tree, use:
+//
+// /path/in/subtree $ find . -name '*.cpp'| xargs clang-check /path/to/source
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+/// \brief Returns the absolute path of 'File', by prepending it with
+/// 'BaseDirectory' if 'File' is not absolute. Otherwise returns 'File'.
+/// If 'File' starts with "./", the returned path will not contain the "./".
+/// Otherwise, the returned path will contain the literal path-concatenation of
+/// 'BaseDirectory' and 'File'.
+///
+/// \param File Either an absolute or relative path.
+/// \param BaseDirectory An absolute path.
+///
+/// FIXME: Put this somewhere where it is more generally available.
+static std::string GetAbsolutePath(
+ llvm::StringRef File, llvm::StringRef BaseDirectory) {
+ assert(llvm::sys::path::is_absolute(BaseDirectory));
+ if (llvm::sys::path::is_absolute(File)) {
+ return File;
+ }
+ llvm::StringRef RelativePath(File);
+ if (RelativePath.startswith("./")) {
+ RelativePath = RelativePath.substr(strlen("./"));
+ }
+ llvm::SmallString<1024> AbsolutePath(BaseDirectory);
+ llvm::sys::path::append(AbsolutePath, RelativePath);
+ return AbsolutePath.str();
+}
+
+int main(int argc, char **argv) {
+ if (argc < 3) {
+ llvm::outs() << "Usage: " << argv[0] << " <cmake-output-dir> "
+ << "<file1> <file2> ...\n";
+ return 1;
+ }
+ // FIXME: We should pull how to find the database into the Tooling package.
+ llvm::OwningPtr<llvm::MemoryBuffer> JsonDatabase;
+ llvm::SmallString<1024> JsonDatabasePath(argv[1]);
+ llvm::sys::path::append(JsonDatabasePath, "compile_commands.json");
+ llvm::error_code Result =
+ llvm::MemoryBuffer::getFile(JsonDatabasePath, JsonDatabase);
+ if (Result != 0) {
+ llvm::outs() << "Error while opening JSON database: " << Result.message()
+ << "\n";
+ return 1;
+ }
+ llvm::StringRef BaseDirectory(::getenv("PWD"));
+ for (int I = 2; I < argc; ++I) {
+ llvm::SmallString<1024> File(GetAbsolutePath(argv[I], BaseDirectory));
+ llvm::outs() << "Processing " << File << ".\n";
+ std::string ErrorMessage;
+ clang::tooling::CompileCommand LookupResult =
+ clang::tooling::FindCompileArgsInJsonDatabase(
+ File.str(), JsonDatabase->getBuffer(), ErrorMessage);
+ if (!LookupResult.CommandLine.empty()) {
+ if (!clang::tooling::RunToolWithFlags(
+ new clang::SyntaxOnlyAction,
+ LookupResult.CommandLine.size(),
+ clang::tooling::CommandLineToArgv(
+ &LookupResult.CommandLine).data())) {
+ llvm::outs() << "Error while processing " << File << ".\n";
+ }
+ } else {
+ llvm::outs() << "Skipping " << File << ". Command line not found.\n";
+ }
+ }
+ return 0;
+}
diff --git a/examples/Tooling/Makefile b/examples/Tooling/Makefile
new file mode 100644
index 000000000000..66e86a03f1c6
--- /dev/null
+++ b/examples/Tooling/Makefile
@@ -0,0 +1,24 @@
+##===- examples/Tooling/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+
+TOOLNAME = clang-check
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+LINK_COMPONENTS := support mc
+USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
+ clangTooling.a clangSema.a clangAnalysis.a \
+ clangAST.a clangParse.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/examples/clang-interpreter/Makefile b/examples/clang-interpreter/Makefile
index 6e762da708d2..3f020037e16f 100644
--- a/examples/clang-interpreter/Makefile
+++ b/examples/clang-interpreter/Makefile
@@ -16,7 +16,7 @@ NO_INSTALL = 1
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
- selectiondag asmparser
+ selectiondag asmparser instrumentation
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangSema.a clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangAnalysis.a clangRewrite.a \
clangAST.a clangParse.a clangLex.a clangBasic.a
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index a99766f9a314..ad39ecec9bd3 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -85,8 +85,7 @@ int main(int argc, const char **argv, char * const *envp) {
// (basically, exactly one input, and the operation mode is hard wired).
llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
Args.push_back("-fsyntax-only");
- llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args.size(),
- Args.data()));
+ llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
if (!C)
return 0;
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 722f6be538b4..d89a903e4112 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -1012,7 +1012,68 @@ CINDEX_LINKAGE int clang_reparseTranslationUnit(CXTranslationUnit TU,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files,
unsigned options);
-
+
+/**
+ * \brief Categorizes how memory is being used by a translation unit.
+ */
+enum CXTUResourceUsageKind {
+ CXTUResourceUsage_AST = 1,
+ CXTUResourceUsage_Identifiers = 2,
+ CXTUResourceUsage_Selectors = 3,
+ CXTUResourceUsage_GlobalCompletionResults = 4,
+ CXTUResourceUsage_SourceManagerContentCache = 5,
+ CXTUResourceUsage_AST_SideTables = 6,
+ CXTUResourceUsage_SourceManager_Membuffer_Malloc = 7,
+ CXTUResourceUsage_SourceManager_Membuffer_MMap = 8,
+ CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc = 9,
+ CXTUResourceUsage_ExternalASTSource_Membuffer_MMap = 10,
+ CXTUResourceUsage_MEMORY_IN_BYTES_BEGIN = CXTUResourceUsage_AST,
+ CXTUResourceUsage_MEMORY_IN_BYTES_END =
+ CXTUResourceUsage_ExternalASTSource_Membuffer_MMap,
+
+ CXTUResourceUsage_First = CXTUResourceUsage_AST,
+ CXTUResourceUsage_Last = CXTUResourceUsage_ExternalASTSource_Membuffer_MMap
+};
+
+/**
+ * \brief Returns the human-readable null-terminated C string that represents
+ * the name of the memory category. This string should never be freed.
+ */
+CINDEX_LINKAGE
+const char *clang_getTUResourceUsageName(enum CXTUResourceUsageKind kind);
+
+typedef struct CXTUResourceUsageEntry {
+ /* \brief The memory usage category. */
+ enum CXTUResourceUsageKind kind;
+ /* \brief Amount of resources used.
+ The units will depend on the resource kind. */
+ unsigned long amount;
+} CXTUResourceUsageEntry;
+
+/**
+ * \brief The memory usage of a CXTranslationUnit, broken into categories.
+ */
+typedef struct CXTUResourceUsage {
+ /* \brief Private data member, used for queries. */
+ void *data;
+
+ /* \brief The number of entries in the 'entries' array. */
+ unsigned numEntries;
+
+ /* \brief An array of key-value pairs, representing the breakdown of memory
+ usage. */
+ CXTUResourceUsageEntry *entries;
+
+} CXTUResourceUsage;
+
+/**
+ * \brief Return the memory usage of a translation unit. This object
+ * should be released with clang_disposeCXTUResourceUsage().
+ */
+CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU);
+
+CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage);
+
/**
* @}
*/
@@ -1101,10 +1162,12 @@ enum CXCursorKind {
CXCursor_NamespaceAlias = 33,
/** \brief A C++ using directive. */
CXCursor_UsingDirective = 34,
- /** \brief A using declaration. */
+ /** \brief A C++ using declaration. */
CXCursor_UsingDeclaration = 35,
+ /** \brief A C++ alias declaration */
+ CXCursor_TypeAliasDecl = 36,
CXCursor_FirstDecl = CXCursor_UnexposedDecl,
- CXCursor_LastDecl = CXCursor_UsingDeclaration,
+ CXCursor_LastDecl = CXCursor_TypeAliasDecl,
/* References */
CXCursor_FirstRef = 40, /* Decl references */
@@ -2871,6 +2934,15 @@ CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
*/
CINDEX_LINKAGE CXString clang_getClangVersion();
+
+/**
+ * \brief Enable/disable crash recovery.
+ *
+ * \param Flag to indicate if crash recovery is enabled. A non-zero value
+ * enables crash recovery, while 0 disables it.
+ */
+CINDEX_LINKAGE void clang_toggleCrashRecovery(unsigned isEnabled);
+
/**
* \brief Visitor invoked for each file in a translation unit
* (used with clang_getInclusions()).
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index 08ee4ef40de0..fcc91768dac3 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -89,7 +89,7 @@ public:
/// \brief If the consumer is interested in entities getting modified after
/// their initial creation, it should return a pointer to
- /// a GetASTMutationListener here.
+ /// an ASTMutationListener here.
virtual ASTMutationListener *GetASTMutationListener() { return 0; }
/// \brief If the consumer is interested in entities being deserialized from
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index c0eeb5af3892..28ec8cf88d52 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -14,10 +14,12 @@
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
#define LLVM_CLANG_AST_ASTCONTEXT_H
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/VersionTuple.h"
#include "clang/AST/Decl.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
@@ -27,6 +29,7 @@
#include "clang/AST/UsuallyTinyPtrVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Allocator.h"
@@ -68,7 +71,7 @@ namespace clang {
class TemplateTypeParmDecl;
class TranslationUnitDecl;
class TypeDecl;
- class TypedefDecl;
+ class TypedefNameDecl;
class UsingDecl;
class UsingShadowDecl;
class UnresolvedSetIterator;
@@ -77,7 +80,7 @@ namespace clang {
/// ASTContext - This class holds long-lived AST nodes (such as types and
/// decls) that can be referred to throughout the semantic analysis of a file.
-class ASTContext {
+class ASTContext : public llvm::RefCountedBase<ASTContext> {
ASTContext &this_() { return *this; }
mutable std::vector<Type*> Types;
@@ -96,7 +99,8 @@ class ASTContext {
DependentSizedExtVectorTypes;
mutable llvm::FoldingSet<VectorType> VectorTypes;
mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
- mutable llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes;
+ mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&>
+ FunctionProtoTypes;
mutable llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes;
mutable llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes;
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
@@ -310,6 +314,9 @@ class ASTContext {
llvm::OwningPtr<CXXABI> ABI;
CXXABI *createCXXABI(const TargetInfo &T);
+ /// \brief The logical -> physical address space map.
+ const LangAS::Map &AddrSpaceMap;
+
friend class ASTDeclReader;
public:
@@ -335,6 +342,14 @@ public:
}
void Deallocate(void *Ptr) const { }
+ /// Return the total amount of physical memory allocated for representing
+ /// AST nodes and type information.
+ size_t getASTAllocatedMemory() const {
+ return BumpAlloc.getTotalMemory();
+ }
+ /// Return the total memory used for various side tables.
+ size_t getSideTableAllocatedMemory() const;
+
PartialDiagnostic::StorageAllocator &getDiagAllocator() {
return DiagAllocator;
}
@@ -381,6 +396,16 @@ public:
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
+
+ /// ZeroBitfieldFollowsNonBitfield - return 'true" if 'FD' is a zero-length
+ /// bitfield which follows the non-bitfield 'LastFD'.
+ bool ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const;
+
+ /// ZeroBitfieldFollowsBitfield - return 'true" if 'FD' is a zero-length
+ /// bitfield which follows the bitfield 'LastFD'.
+ bool ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const;
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::iterator overridden_cxx_method_iterator;
@@ -413,10 +438,13 @@ public:
CanQualType FloatTy, DoubleTy, LongDoubleTy;
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
- CanQualType OverloadTy;
- CanQualType DependentTy;
+ CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
+ // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
+ mutable QualType AutoDeductTy; // Deduction against 'auto'.
+ mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'.
+
ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
@@ -654,9 +682,9 @@ public:
}
/// getTypedefType - Return the unique reference to the type for the
- /// specified typename decl.
- QualType getTypedefType(const TypedefDecl *Decl, QualType Canon = QualType())
- const;
+ /// specified typedef-name decl.
+ QualType getTypedefType(const TypedefNameDecl *Decl,
+ QualType Canon = QualType()) const;
QualType getRecordType(const RecordDecl *Decl) const;
@@ -676,7 +704,7 @@ public:
QualType getTemplateTypeParmType(unsigned Depth, unsigned Index,
bool ParameterPack,
- IdentifierInfo *Name = 0) const;
+ TemplateTypeParmDecl *ParmDecl = 0) const;
QualType getTemplateSpecializationType(TemplateName T,
const TemplateArgument *Args,
@@ -739,6 +767,12 @@ public:
/// getAutoType - C++0x deduced auto type.
QualType getAutoType(QualType DeducedType) const;
+ /// getAutoDeductType - C++0x deduction pattern for 'auto' type.
+ QualType getAutoDeductType() const;
+
+ /// getAutoRRefDeductType - C++0x deduction pattern for 'auto &&' type.
+ QualType getAutoRRefDeductType() const;
+
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const;
@@ -1294,6 +1328,21 @@ public:
QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize,
QualType typeDomain) const;
+ unsigned getTargetAddressSpace(QualType T) const {
+ return getTargetAddressSpace(T.getQualifiers());
+ }
+
+ unsigned getTargetAddressSpace(Qualifiers Q) const {
+ return getTargetAddressSpace(Q.getAddressSpace());
+ }
+
+ unsigned getTargetAddressSpace(unsigned AS) const {
+ if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count)
+ return AS;
+ else
+ return AddrSpaceMap[AS - LangAS::Offset];
+ }
+
private:
// Helper for integer ordering
unsigned getIntegerRank(const Type *T) const;
@@ -1332,7 +1381,8 @@ public:
const ObjCObjectType *RHS);
bool canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
- const ObjCObjectPointerType *RHSOPT);
+ const ObjCObjectPointerType *RHSOPT,
+ bool BlockReturnType);
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
@@ -1340,7 +1390,7 @@ public:
// Functions for calculating composite types
QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false,
- bool Unqualified = false);
+ bool Unqualified = false, bool BlockReturnType = false);
QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false,
bool Unqualified = false);
QualType mergeFunctionArgumentTypes(QualType, QualType,
@@ -1528,13 +1578,13 @@ private:
};
/// @brief Utility function for constructing a nullary selector.
-static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
+static inline Selector GetNullarySelector(llvm::StringRef name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
/// @brief Utility function for constructing an unary selector.
-static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) {
+static inline Selector GetUnarySelector(llvm::StringRef name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
}
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index 1ab53b3e9148..1cb803a3396a 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -15,7 +15,8 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#define ASTSTART
#include "clang/Basic/DiagnosticASTKinds.inc"
#undef DIAG
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index 01e618024913..470cca8ee76e 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -20,6 +20,8 @@ namespace clang {
class CXXRecordDecl;
class ClassTemplateDecl;
class ClassTemplateSpecializationDecl;
+ class FunctionDecl;
+ class FunctionTemplateDecl;
/// \brief An abstract interface that should be implemented by listeners
/// that want to be notified when an AST entity gets modified after its
@@ -41,6 +43,17 @@ public:
/// template declaration.
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D) {}
+
+ /// \brief A template specialization (or partial one) was added to the
+ /// template declaration.
+ virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
+ const FunctionDecl *D) {}
+
+ /// \brief An implicit member got a definition.
+ virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
+
+ /// \brief A static data member was implicitly instantiated.
+ virtual void StaticDataMemberInstantiated(const VarDecl *D) {}
};
} // end namespace clang
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 67968fde2d6b..719023926bae 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -17,9 +17,11 @@
#include "llvm/Support/Casting.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/VersionTuple.h"
#include <cassert>
#include <cstring>
#include <algorithm>
@@ -120,6 +122,19 @@ public:
static bool classof(const InheritableAttr *) { return true; }
};
+class InheritableParamAttr : public InheritableAttr {
+protected:
+ InheritableParamAttr(attr::Kind AK, SourceLocation L)
+ : InheritableAttr(AK, L) {}
+
+public:
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() <= attr::LAST_INHERITABLE_PARAM;
+ }
+ static bool classof(const InheritableParamAttr *) { return true; }
+};
+
#include "clang/AST/Attrs.inc"
/// AttrVec - A vector of Attr, which is how they are stored on the AST.
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index 2d30cb3b8b62..d712e7d0c751 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -87,7 +87,7 @@ public:
/// BasePaths - Represents the set of paths from a derived class to
/// one of its (direct or indirect) bases. For example, given the
-/// following class hierachy:
+/// following class hierarchy:
///
/// @code
/// class A { };
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 4d7fcfd1d121..b3550f877323 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -655,7 +655,8 @@ struct CanProxyAdaptor<TemplateTypeParmType>
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getName)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TemplateTypeParmDecl *, getDecl)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getIdentifier)
};
template<>
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index cf909e88220f..d7cbd08e6c2e 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -34,7 +34,7 @@ namespace clang {
/// architectures where the two are the same size.
///
/// For portability, never assume that a target character is 8 bits wide. Use
- /// CharUnit values whereever you calculate sizes, offsets, or alignments
+ /// CharUnit values wherever you calculate sizes, offsets, or alignments
/// in character units.
class CharUnits {
public:
@@ -70,10 +70,24 @@ namespace clang {
Quantity += Other.Quantity;
return *this;
}
+ CharUnits& operator++ () {
+ ++Quantity;
+ return *this;
+ }
+ CharUnits operator++ (int) {
+ return CharUnits(Quantity++);
+ }
CharUnits& operator-= (const CharUnits &Other) {
Quantity -= Other.Quantity;
return *this;
}
+ CharUnits& operator-- () {
+ --Quantity;
+ return *this;
+ }
+ CharUnits operator-- (int) {
+ return CharUnits(Quantity--);
+ }
// Comparison operators.
bool operator== (const CharUnits &Other) const {
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 31cee24df993..ef4920520391 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -20,6 +20,7 @@
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/Basic/Linkage.h"
+#include "llvm/ADT/Optional.h"
namespace clang {
class CXXTemporary;
@@ -119,14 +120,6 @@ public:
return getIdentifier() ? getIdentifier()->getName() : "";
}
- llvm::StringRef getMessageUnavailableAttr(bool unavailable) const {
- if (!unavailable)
- return "";
- if (const UnavailableAttr *UA = getAttr<UnavailableAttr>())
- return UA->getMessage();
- return "";
- }
-
/// getNameAsString - Get a human-readable name for the declaration, even if
/// it is one of the special kinds of names (C++ constructor, Objective-C
/// selector, etc). Creating this name requires expensive string
@@ -281,6 +274,10 @@ public:
/// \brief Determines the linkage and visibility of this entity.
LinkageInfo getLinkageAndVisibility() const;
+ /// \brief If visibility was explicitly specified for this
+ /// declaration, return that visibility.
+ llvm::Optional<Visibility> getExplicitVisibility() const;
+
/// \brief Clear the linkage cache in response to a change
/// to the declaration.
void ClearLinkageCache();
@@ -310,16 +307,32 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
/// location is where the __label__ is.
class LabelDecl : public NamedDecl {
LabelStmt *TheStmt;
- LabelDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *II, LabelStmt *S)
- : NamedDecl(Label, DC, L, II), TheStmt(S) {}
-
+ /// LocStart - For normal labels, this is the same as the main declaration
+ /// label, i.e., the location of the identifier; for GNU local labels,
+ /// this is the location of the __label__ keyword.
+ SourceLocation LocStart;
+
+ LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II,
+ LabelStmt *S, SourceLocation StartL)
+ : NamedDecl(Label, DC, IdentL, II), TheStmt(S), LocStart(StartL) {}
+
public:
static LabelDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *II);
+ SourceLocation IdentL, IdentifierInfo *II);
+ static LabelDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation IdentL, IdentifierInfo *II,
+ SourceLocation GnuLabelL);
LabelStmt *getStmt() const { return TheStmt; }
void setStmt(LabelStmt *T) { TheStmt = T; }
-
+
+ bool isGnuLocal() const { return LocStart != getLocation(); }
+ void setLocStart(SourceLocation L) { LocStart = L; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(LocStart, getLocation());
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const LabelDecl *D) { return true; }
@@ -330,7 +343,11 @@ public:
class NamespaceDecl : public NamedDecl, public DeclContext {
bool IsInline : 1;
- SourceLocation LBracLoc, RBracLoc;
+ /// LocStart - The starting location of the source range, pointing
+ /// to either the namespace or the inline keyword.
+ SourceLocation LocStart;
+ /// RBraceLoc - The ending location of the source range.
+ SourceLocation RBraceLoc;
// For extended namespace definitions:
//
@@ -357,13 +374,16 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
/// namespace declaration (which the boolean indicates).
llvm::PointerIntPair<NamespaceDecl *, 1, bool> OrigOrAnonNamespace;
- NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
- : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace),
- IsInline(false), NextNamespace(), OrigOrAnonNamespace(0, true) { }
+ NamespaceDecl(DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id)
+ : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
+ IsInline(false), LocStart(StartLoc), RBraceLoc(),
+ NextNamespace(), OrigOrAnonNamespace(0, true) { }
public:
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id);
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id);
/// \brief Returns true if this is an anonymous namespace declaration.
///
@@ -427,7 +447,7 @@ public:
void setAnonymousNamespace(NamespaceDecl *D) {
assert(!D || D->isAnonymousNamespace());
- assert(!D || D->getParent() == this);
+ assert(!D || D->getParent()->getRedeclContext() == this);
getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D);
}
@@ -437,14 +457,14 @@ public:
}
virtual SourceRange getSourceRange() const {
- return SourceRange(getLocation(), RBracLoc);
+ return SourceRange(LocStart, RBraceLoc);
}
- SourceLocation getLBracLoc() const { return LBracLoc; }
- SourceLocation getRBracLoc() const { return RBracLoc; }
- void setLBracLoc(SourceLocation L) { LBracLoc = L; }
- void setRBracLoc(SourceLocation R) { RBracLoc = R; }
-
+ SourceLocation getLocStart() const { return LocStart; }
+ SourceLocation getRBraceLoc() const { return RBraceLoc; }
+ void setLocStart(SourceLocation L) { LocStart = L; }
+ void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamespaceDecl *D) { return true; }
@@ -484,16 +504,24 @@ public:
/// name qualifier, to be used for the case of out-of-line declarations.
struct QualifierInfo {
NestedNameSpecifierLoc QualifierLoc;
- /// NumTemplParamLists - The number of template parameter lists
- /// that were matched against the template-ids occurring into the NNS.
+
+ /// NumTemplParamLists - The number of "outer" template parameter lists.
+ /// The count includes all of the template parameter lists that were matched
+ /// against the template-ids occurring into the NNS and possibly (in the
+ /// case of an explicit specialization) a final "template <>".
unsigned NumTemplParamLists;
+
/// TemplParamLists - A new-allocated array of size NumTemplParamLists,
- /// containing pointers to the matched template parameter lists.
+ /// containing pointers to the "outer" template parameter lists.
+ /// It includes all of the template parameter lists that were matched
+ /// against the template-ids occurring into the NNS and possibly (in the
+ /// case of an explicit specialization) a final "template <>".
TemplateParameterList** TemplParamLists;
/// Default constructor.
QualifierInfo() : QualifierLoc(), NumTemplParamLists(0), TemplParamLists(0) {}
- /// setTemplateParameterListsInfo - Sets info about matched template
+
+ /// setTemplateParameterListsInfo - Sets info about "outer" template
/// parameter lists.
void setTemplateParameterListsInfo(ASTContext &Context,
unsigned NumTPLists,
@@ -516,14 +544,20 @@ class DeclaratorDecl : public ValueDecl {
llvm::PointerUnion<TypeSourceInfo*, ExtInfo*> DeclInfo;
+ /// InnerLocStart - The start of the source range for this declaration,
+ /// ignoring outer template declarations.
+ SourceLocation InnerLocStart;
+
bool hasExtInfo() const { return DeclInfo.is<ExtInfo*>(); }
ExtInfo *getExtInfo() { return DeclInfo.get<ExtInfo*>(); }
const ExtInfo *getExtInfo() const { return DeclInfo.get<ExtInfo*>(); }
protected:
DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L,
- DeclarationName N, QualType T, TypeSourceInfo *TInfo)
- : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo) {}
+ DeclarationName N, QualType T, TypeSourceInfo *TInfo,
+ SourceLocation StartL)
+ : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo), InnerLocStart(StartL) {
+ }
public:
TypeSourceInfo *getTypeSourceInfo() const {
@@ -540,14 +574,14 @@ public:
/// getInnerLocStart - Return SourceLocation representing start of source
/// range ignoring outer template declarations.
- virtual SourceLocation getInnerLocStart() const { return getLocation(); }
+ SourceLocation getInnerLocStart() const { return InnerLocStart; }
+ void setInnerLocStart(SourceLocation L) { InnerLocStart = L; }
/// getOuterLocStart - Return SourceLocation representing start of source
/// range taking into account any outer template declarations.
SourceLocation getOuterLocStart() const;
- SourceRange getSourceRange() const {
- return SourceRange(getOuterLocStart(), getLocation());
- }
+
+ virtual SourceRange getSourceRange() const;
/// \brief Retrieve the nested-name-specifier that qualifies the name of this
/// declaration, if it was present in the source.
@@ -574,9 +608,7 @@ public:
return getExtInfo()->TemplParamLists[index];
}
void setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists,
- TemplateParameterList **TPLists) {
- getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
- }
+ TemplateParameterList **TPLists);
SourceLocation getTypeSpecStartLoc() const;
@@ -650,32 +682,77 @@ protected:
mutable InitType Init;
private:
- // FIXME: This can be packed into the bitfields in Decl.
- unsigned SClass : 3;
- unsigned SClassAsWritten : 3;
- bool ThreadSpecified : 1;
- bool HasCXXDirectInit : 1;
-
- /// \brief Whether this variable is the exception variable in a C++ catch
- /// or an Objective-C @catch statement.
- bool ExceptionVar : 1;
+ class VarDeclBitfields {
+ friend class VarDecl;
+ friend class ASTDeclReader;
+
+ unsigned SClass : 3;
+ unsigned SClassAsWritten : 3;
+ unsigned ThreadSpecified : 1;
+ unsigned HasCXXDirectInit : 1;
+
+ /// \brief Whether this variable is the exception variable in a C++ catch
+ /// or an Objective-C @catch statement.
+ unsigned ExceptionVar : 1;
- /// \brief Whether this local variable could be allocated in the return
- /// slot of its function, enabling the named return value optimization (NRVO).
- bool NRVOVariable : 1;
+ /// \brief Whether this local variable could be allocated in the return
+ /// slot of its function, enabling the named return value optimization (NRVO).
+ unsigned NRVOVariable : 1;
+
+ /// \brief Whether this variable is the for-range-declaration in a C++0x
+ /// for-range statement.
+ unsigned CXXForRangeDecl : 1;
+ };
+ enum { NumVarDeclBits = 13 }; // two reserved bits for now
- friend class StmtIteratorBase;
friend class ASTDeclReader;
+ friend class StmtIteratorBase;
protected:
- VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ class ParmVarDeclBitfields {
+ friend class ParmVarDecl;
+ friend class ASTDeclReader;
+
+ unsigned : NumVarDeclBits;
+
+ /// Whether this parameter inherits a default argument from a
+ /// prior declaration.
+ unsigned HasInheritedDefaultArg : 1;
+
+ /// Whether this parameter undergoes K&R argument promotion.
+ unsigned IsKNRPromoted : 1;
+
+ /// Whether this parameter is an ObjC method parameter or not.
+ unsigned IsObjCMethodParam : 1;
+
+ /// If IsObjCMethodParam, a Decl::ObjCDeclQualifier.
+ /// Otherwise, the number of function parameter scopes enclosing
+ /// the function parameter scope in which this parameter was
+ /// declared.
+ unsigned ScopeDepthOrObjCQuals : 8;
+
+ /// The number of parameters preceding this parameter in the
+ /// function parameter scope in which it was declared.
+ unsigned ParameterIndex : 8;
+ };
+
+ union {
+ unsigned AllBits;
+ VarDeclBitfields VarDeclBits;
+ ParmVarDeclBitfields ParmVarDeclBits;
+ };
+
+ VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, StorageClass SC,
StorageClass SCAsWritten)
- : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(),
- ThreadSpecified(false), HasCXXDirectInit(false),
- ExceptionVar(false), NRVOVariable(false) {
- SClass = SC;
- SClassAsWritten = SCAsWritten;
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
+ assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
+ assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
+ AllBits = 0;
+ VarDeclBits.SClass = SC;
+ VarDeclBits.SClassAsWritten = SCAsWritten;
+ // Everything else is implicitly initialized to false.
}
typedef Redeclarable<VarDecl> redeclarable_base;
@@ -691,26 +768,27 @@ public:
}
static VarDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, StorageClass S,
- StorageClass SCAsWritten);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, StorageClass SCAsWritten);
- virtual SourceLocation getInnerLocStart() const;
virtual SourceRange getSourceRange() const;
- StorageClass getStorageClass() const { return (StorageClass)SClass; }
+ StorageClass getStorageClass() const {
+ return (StorageClass) VarDeclBits.SClass;
+ }
StorageClass getStorageClassAsWritten() const {
- return (StorageClass) SClassAsWritten;
+ return (StorageClass) VarDeclBits.SClassAsWritten;
}
void setStorageClass(StorageClass SC);
void setStorageClassAsWritten(StorageClass SC) {
assert(isLegalForVariable(SC));
- SClassAsWritten = SC;
+ VarDeclBits.SClassAsWritten = SC;
}
- void setThreadSpecified(bool T) { ThreadSpecified = T; }
+ void setThreadSpecified(bool T) { VarDeclBits.ThreadSpecified = T; }
bool isThreadSpecified() const {
- return ThreadSpecified;
+ return VarDeclBits.ThreadSpecified;
}
/// hasLocalStorage - Returns true if a variable with function scope
@@ -988,7 +1066,7 @@ public:
Eval->IsICE = IsICE;
}
- void setCXXDirectInitializer(bool T) { HasCXXDirectInit = T; }
+ void setCXXDirectInitializer(bool T) { VarDeclBits.HasCXXDirectInit = T; }
/// hasCXXDirectInitializer - If true, the initializer was a direct
/// initializer, e.g: "int x(1);". The Init expression will be the expression
@@ -997,15 +1075,15 @@ public:
/// by checking hasCXXDirectInitializer.
///
bool hasCXXDirectInitializer() const {
- return HasCXXDirectInit;
+ return VarDeclBits.HasCXXDirectInit;
}
/// \brief Determine whether this variable is the exception variable in a
/// C++ catch statememt or an Objective-C @catch statement.
bool isExceptionVariable() const {
- return ExceptionVar;
+ return VarDeclBits.ExceptionVar;
}
- void setExceptionVariable(bool EV) { ExceptionVar = EV; }
+ void setExceptionVariable(bool EV) { VarDeclBits.ExceptionVar = EV; }
/// \brief Determine whether this local variable can be used with the named
/// return value optimization (NRVO).
@@ -1017,8 +1095,13 @@ public:
/// return slot when returning from the function. Within the function body,
/// each return that returns the NRVO object will have this variable as its
/// NRVO candidate.
- bool isNRVOVariable() const { return NRVOVariable; }
- void setNRVOVariable(bool NRVO) { NRVOVariable = NRVO; }
+ bool isNRVOVariable() const { return VarDeclBits.NRVOVariable; }
+ void setNRVOVariable(bool NRVO) { VarDeclBits.NRVOVariable = NRVO; }
+
+ /// \brief Determine whether this variable is the for-range-declaration in
+ /// a C++0x for-range statement.
+ bool isCXXForRangeDecl() const { return VarDeclBits.CXXForRangeDecl; }
+ void setCXXForRangeDecl(bool FRD) { VarDeclBits.CXXForRangeDecl = FRD; }
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
@@ -1048,12 +1131,12 @@ public:
class ImplicitParamDecl : public VarDecl {
public:
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T);
- ImplicitParamDecl(DeclContext *DC, SourceLocation loc,
- IdentifierInfo *name, QualType type)
- : VarDecl(ImplicitParam, DC, loc, name, type,
+ ImplicitParamDecl(DeclContext *DC, SourceLocation IdLoc,
+ IdentifierInfo *Id, QualType Type)
+ : VarDecl(ImplicitParam, DC, IdLoc, IdLoc, Id, Type,
/*tinfo*/ 0, SC_None, SC_None) {
setImplicit();
}
@@ -1064,35 +1147,85 @@ public:
static bool classofKind(Kind K) { return K == ImplicitParam; }
};
-/// ParmVarDecl - Represent a parameter to a function.
+/// ParmVarDecl - Represents a parameter to a function.
class ParmVarDecl : public VarDecl {
- // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
- /// FIXME: Also can be paced into the bitfields in Decl.
- /// in, inout, etc.
- unsigned objcDeclQualifier : 6;
- bool HasInheritedDefaultArg : 1;
+public:
+ enum { MaxFunctionScopeDepth = 255 };
+ enum { MaxFunctionScopeIndex = 255 };
protected:
- ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
+ ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten, Expr *DefArg)
- : VarDecl(DK, DC, L, Id, T, TInfo, S, SCAsWritten),
- objcDeclQualifier(OBJC_TQ_None), HasInheritedDefaultArg(false) {
+ : VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten) {
+ assert(ParmVarDeclBits.HasInheritedDefaultArg == false);
+ assert(ParmVarDeclBits.IsKNRPromoted == false);
+ assert(ParmVarDeclBits.IsObjCMethodParam == false);
setDefaultArg(DefArg);
}
public:
static ParmVarDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,IdentifierInfo *Id,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten,
Expr *DefArg);
+ void setObjCMethodScopeInfo(unsigned parameterIndex) {
+ ParmVarDeclBits.IsObjCMethodParam = true;
+
+ ParmVarDeclBits.ParameterIndex = parameterIndex;
+ assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
+ }
+
+ void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) {
+ assert(!ParmVarDeclBits.IsObjCMethodParam);
+
+ ParmVarDeclBits.ScopeDepthOrObjCQuals = scopeDepth;
+ assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth && "truncation!");
+
+ ParmVarDeclBits.ParameterIndex = parameterIndex;
+ assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
+ }
+
+ bool isObjCMethodParameter() const {
+ return ParmVarDeclBits.IsObjCMethodParam;
+ }
+
+ unsigned getFunctionScopeDepth() const {
+ if (ParmVarDeclBits.IsObjCMethodParam) return 0;
+ return ParmVarDeclBits.ScopeDepthOrObjCQuals;
+ }
+
+ /// Returns the index of this parameter in its prototype or method scope.
+ unsigned getFunctionScopeIndex() const {
+ return ParmVarDeclBits.ParameterIndex;
+ }
+
ObjCDeclQualifier getObjCDeclQualifier() const {
- return ObjCDeclQualifier(objcDeclQualifier);
+ if (!ParmVarDeclBits.IsObjCMethodParam) return OBJC_TQ_None;
+ return ObjCDeclQualifier(ParmVarDeclBits.ScopeDepthOrObjCQuals);
}
void setObjCDeclQualifier(ObjCDeclQualifier QTVal) {
- objcDeclQualifier = QTVal;
+ assert(ParmVarDeclBits.IsObjCMethodParam);
+ ParmVarDeclBits.ScopeDepthOrObjCQuals = QTVal;
+ }
+
+ /// True if the value passed to this parameter must undergo
+ /// K&R-style default argument promotion:
+ ///
+ /// C99 6.5.2.2.
+ /// If the expression that denotes the called function has a type
+ /// that does not include a prototype, the integer promotions are
+ /// performed on each argument, and arguments that have type float
+ /// are promoted to double.
+ bool isKNRPromoted() const {
+ return ParmVarDeclBits.IsKNRPromoted;
+ }
+ void setKNRPromoted(bool promoted) {
+ ParmVarDeclBits.IsKNRPromoted = promoted;
}
Expr *getDefaultArg();
@@ -1158,11 +1291,11 @@ public:
}
bool hasInheritedDefaultArg() const {
- return HasInheritedDefaultArg;
+ return ParmVarDeclBits.HasInheritedDefaultArg;
}
void setHasInheritedDefaultArg(bool I = true) {
- HasInheritedDefaultArg = I;
+ ParmVarDeclBits.HasInheritedDefaultArg = I;
}
QualType getOriginalType() const {
@@ -1233,6 +1366,7 @@ private:
bool IsDeleted : 1;
bool IsTrivial : 1; // sunk from CXXMethodDecl
bool HasImplicitReturnZero : 1;
+ bool IsLateTemplateParsed : 1;
/// \brief End part of this FunctionDecl's source range.
///
@@ -1302,17 +1436,20 @@ private:
void setParams(ASTContext &C, ParmVarDecl **NewParamInfo, unsigned NumParams);
protected:
- FunctionDecl(Kind DK, DeclContext *DC, const DeclarationNameInfo &NameInfo,
+ FunctionDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified)
- : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo),
+ : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
+ StartLoc),
DeclContext(DK),
ParamInfo(0), Body(),
- SClass(S), SClassAsWritten(SCAsWritten),
+ SClass(S), SClassAsWritten(SCAsWritten),
IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
- HasImplicitReturnZero(false), EndRangeLoc(NameInfo.getEndLoc()),
+ HasImplicitReturnZero(false), IsLateTemplateParsed(false),
+ EndRangeLoc(NameInfo.getEndLoc()),
TemplateOrSpecialization(),
DNLoc(NameInfo.getInfo()) {}
@@ -1328,22 +1465,25 @@ public:
return redeclarable_base::redecls_end();
}
- static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation NLoc,
DeclarationName N, QualType T,
TypeSourceInfo *TInfo,
- StorageClass S = SC_None,
+ StorageClass SC = SC_None,
StorageClass SCAsWritten = SC_None,
bool isInlineSpecified = false,
bool hasWrittenPrototype = true) {
- DeclarationNameInfo NameInfo(N, L);
- return FunctionDecl::Create(C, DC, NameInfo, T, TInfo, S, SCAsWritten,
+ DeclarationNameInfo NameInfo(N, NLoc);
+ return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo,
+ SC, SCAsWritten,
isInlineSpecified, hasWrittenPrototype);
}
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S = SC_None,
+ StorageClass SC = SC_None,
StorageClass SCAsWritten = SC_None,
bool isInlineSpecified = false,
bool hasWrittenPrototype = true);
@@ -1356,12 +1496,9 @@ public:
const PrintingPolicy &Policy,
bool Qualified) const;
- virtual SourceRange getSourceRange() const {
- return SourceRange(getOuterLocStart(), EndRangeLoc);
- }
- void setLocEnd(SourceLocation E) {
- EndRangeLoc = E;
- }
+ void setRangeEnd(SourceLocation E) { EndRangeLoc = E; }
+
+ virtual SourceRange getSourceRange() const;
/// \brief Returns true if the function has a body (definition). The
/// function body might be in any of the (re-)declarations of this
@@ -1395,7 +1532,9 @@ public:
/// previous definition); for that information, use getBody.
/// FIXME: Should return true if function is deleted or defaulted. However,
/// CodeGenModule.cpp uses it, and I don't know if this would break it.
- bool isThisDeclarationADefinition() const { return Body; }
+ bool isThisDeclarationADefinition() const {
+ return Body || IsLateTemplateParsed;
+ }
void setBody(Stmt *B);
void setLazyBody(uint64_t Offset) { Body = Offset; }
@@ -1412,6 +1551,14 @@ public:
bool isPure() const { return IsPure; }
void setPure(bool P = true);
+ /// Whether this is a constexpr function or constexpr constructor.
+ // FIXME: C++0x: Implement tracking of the constexpr specifier.
+ bool isConstExpr() const { return false; }
+
+ /// Whether this templated function will be late parsed.
+ bool isLateTemplateParsed() const { return IsLateTemplateParsed; }
+ void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; }
+
/// Whether this function is "trivial" in some specialized C++ senses.
/// Can only be true for default constructors, copy constructors,
/// copy assignment operators, and destructors. Not meaningful until
@@ -1757,16 +1904,17 @@ class FieldDecl : public DeclaratorDecl {
Expr *BitWidth;
protected:
- FieldDecl(Kind DK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- Expr *BW, bool Mutable)
- : DeclaratorDecl(DK, DC, L, Id, T, TInfo),
+ FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable)
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW) {
}
public:
static FieldDecl *Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id, QualType T,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable);
/// getFieldIndex - Returns the index of this field within its record,
@@ -1803,7 +1951,9 @@ public:
RecordDecl *getParent() {
return cast<RecordDecl>(getDeclContext());
}
-
+
+ SourceRange getSourceRange() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FieldDecl *D) { return true; }
@@ -1895,6 +2045,8 @@ class TypeDecl : public NamedDecl {
/// ASTContext::getTypedefType, ASTContext::getTagDeclType, and
/// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl.
mutable const Type *TypeForDecl;
+ /// LocStart - The start of the source range for this declaration.
+ SourceLocation LocStart;
friend class ASTContext;
friend class DeclContext;
friend class TagDecl;
@@ -1902,15 +2054,24 @@ class TypeDecl : public NamedDecl {
friend class TagType;
protected:
- TypeDecl(Kind DK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id)
- : NamedDecl(DK, DC, L, Id), TypeForDecl(0) {}
+ TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ SourceLocation StartL = SourceLocation())
+ : NamedDecl(DK, DC, L, Id), TypeForDecl(0), LocStart(StartL) {}
public:
// Low-level accessor
const Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(const Type *TD) { TypeForDecl = TD; }
+ SourceLocation getLocStart() const { return LocStart; }
+ void setLocStart(SourceLocation L) { LocStart = L; }
+ virtual SourceRange getSourceRange() const {
+ if (LocStart.isValid())
+ return SourceRange(LocStart, getLocation());
+ else
+ return SourceRange(getLocation());
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypeDecl *D) { return true; }
@@ -1918,17 +2079,21 @@ public:
};
-class TypedefDecl : public TypeDecl, public Redeclarable<TypedefDecl> {
+/// Base class for declarations which introduce a typedef-name.
+class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
/// UnderlyingType - This is the type the typedef is set to.
TypeSourceInfo *TInfo;
- TypedefDecl(DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, TypeSourceInfo *TInfo)
- : TypeDecl(Typedef, DC, L, Id), TInfo(TInfo) {}
-
protected:
- typedef Redeclarable<TypedefDecl> redeclarable_base;
- virtual TypedefDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+ TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ TypeSourceInfo *TInfo)
+ : TypeDecl(DK, DC, IdLoc, Id, StartLoc), TInfo(TInfo) {}
+
+ typedef Redeclarable<TypedefNameDecl> redeclarable_base;
+ virtual TypedefNameDecl *getNextRedeclaration() {
+ return RedeclLink.getNext();
+ }
public:
typedef redeclarable_base::redecl_iterator redecl_iterator;
@@ -1939,19 +2104,15 @@ public:
return redeclarable_base::redecls_end();
}
- static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- TypeSourceInfo *TInfo);
-
TypeSourceInfo *getTypeSourceInfo() const {
return TInfo;
}
- /// Retrieves the canonical declaration of this typedef.
- TypedefDecl *getCanonicalDecl() {
+ /// Retrieves the canonical declaration of this typedef-name.
+ TypedefNameDecl *getCanonicalDecl() {
return getFirstDeclaration();
}
- const TypedefDecl *getCanonicalDecl() const {
+ const TypedefNameDecl *getCanonicalDecl() const {
return getFirstDeclaration();
}
@@ -1964,11 +2125,51 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const TypedefNameDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= firstTypedefName && K <= lastTypedefName;
+ }
+};
+
+/// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef'
+/// type specifier.
+class TypedefDecl : public TypedefNameDecl {
+ TypedefDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, TypeSourceInfo *TInfo)
+ : TypedefNameDecl(Typedef, DC, StartLoc, IdLoc, Id, TInfo) {}
+
+public:
+ static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, TypeSourceInfo *TInfo);
+
+ SourceRange getSourceRange() const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypedefDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Typedef; }
};
-class TypedefDecl;
+/// TypeAliasDecl - Represents the declaration of a typedef-name via a C++0x
+/// alias-declaration.
+class TypeAliasDecl : public TypedefNameDecl {
+ TypeAliasDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, TypeSourceInfo *TInfo)
+ : TypedefNameDecl(TypeAlias, DC, StartLoc, IdLoc, Id, TInfo) {}
+
+public:
+ static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, TypeSourceInfo *TInfo);
+
+ SourceRange getSourceRange() const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const TypeAliasDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == TypeAlias; }
+};
/// TagDecl - Represents the declaration of a struct/union/class/enum.
class TagDecl
@@ -2013,32 +2214,31 @@ protected:
bool IsFixed : 1;
private:
- SourceLocation TagKeywordLoc;
SourceLocation RBraceLoc;
// A struct representing syntactic qualifier info,
// to be used for the (uncommon) case of out-of-line declarations.
typedef QualifierInfo ExtInfo;
- /// TypedefDeclOrQualifier - If the (out-of-line) tag declaration name
+ /// TypedefNameDeclOrQualifier - If the (out-of-line) tag declaration name
/// is qualified, it points to the qualifier info (nns and range);
/// otherwise, if the tag declaration is anonymous and it is part of
- /// a typedef, it points to the TypedefDecl (used for mangling);
- /// otherwise, it is a null (TypedefDecl) pointer.
- llvm::PointerUnion<TypedefDecl*, ExtInfo*> TypedefDeclOrQualifier;
+ /// a typedef or alias, it points to the TypedefNameDecl (used for mangling);
+ /// otherwise, it is a null (TypedefNameDecl) pointer.
+ llvm::PointerUnion<TypedefNameDecl*, ExtInfo*> TypedefNameDeclOrQualifier;
- bool hasExtInfo() const { return TypedefDeclOrQualifier.is<ExtInfo*>(); }
- ExtInfo *getExtInfo() { return TypedefDeclOrQualifier.get<ExtInfo*>(); }
+ bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo*>(); }
+ ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo*>(); }
const ExtInfo *getExtInfo() const {
- return TypedefDeclOrQualifier.get<ExtInfo*>();
+ return TypedefNameDeclOrQualifier.get<ExtInfo*>();
}
protected:
TagDecl(Kind DK, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- TagDecl *PrevDecl, SourceLocation TKL = SourceLocation())
- : TypeDecl(DK, DC, L, Id), DeclContext(DK), TagKeywordLoc(TKL),
- TypedefDeclOrQualifier((TypedefDecl*) 0) {
+ TagDecl *PrevDecl, SourceLocation StartL)
+ : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK),
+ TypedefNameDeclOrQualifier((TypedefNameDecl*) 0) {
assert((DK != Enum || TK == TTK_Enum) &&
"EnumDecl not matched with TTK_Enum");
TagDeclKind = TK;
@@ -2068,12 +2268,9 @@ public:
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
- SourceLocation getTagKeywordLoc() const { return TagKeywordLoc; }
- void setTagKeywordLoc(SourceLocation TKL) { TagKeywordLoc = TKL; }
-
/// getInnerLocStart - Return SourceLocation representing start of source
/// range ignoring outer template declarations.
- virtual SourceLocation getInnerLocStart() const { return TagKeywordLoc; }
+ SourceLocation getInnerLocStart() const { return getLocStart(); }
/// getOuterLocStart - Return SourceLocation representing start of source
/// range taking into account any outer template declarations.
@@ -2146,11 +2343,11 @@ public:
bool isUnion() const { return getTagKind() == TTK_Union; }
bool isEnum() const { return getTagKind() == TTK_Enum; }
- TypedefDecl *getTypedefForAnonDecl() const {
- return hasExtInfo() ? 0 : TypedefDeclOrQualifier.get<TypedefDecl*>();
+ TypedefNameDecl *getTypedefNameForAnonDecl() const {
+ return hasExtInfo() ? 0 : TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
}
- void setTypedefForAnonDecl(TypedefDecl *TDD);
+ void setTypedefNameForAnonDecl(TypedefNameDecl *TDD);
/// \brief Retrieve the nested-name-specifier that qualifies the name of this
/// declaration, if it was present in the source.
@@ -2177,9 +2374,7 @@ public:
return getExtInfo()->TemplParamLists[i];
}
void setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists,
- TemplateParameterList **TPLists) {
- getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
- }
+ TemplateParameterList **TPLists);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -2235,18 +2430,19 @@ class EnumDecl : public TagDecl {
NumBitsMask = (1 << NumBitsWidth) - 1
};
- EnumDecl(DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL,
+ EnumDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, EnumDecl *PrevDecl,
bool Scoped, bool ScopedUsingClassTag, bool Fixed)
- : TagDecl(Enum, TTK_Enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) {
- assert(Scoped || !ScopedUsingClassTag);
- IntegerType = (const Type*)0;
- NumNegativeBits = 0;
- NumPositiveBits = 0;
- IsScoped = Scoped;
- IsScopedUsingClassTag = ScopedUsingClassTag;
- IsFixed = Fixed;
- }
+ : TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc),
+ InstantiatedFrom(0) {
+ assert(Scoped || !ScopedUsingClassTag);
+ IntegerType = (const Type*)0;
+ NumNegativeBits = 0;
+ NumPositiveBits = 0;
+ IsScoped = Scoped;
+ IsScopedUsingClassTag = ScopedUsingClassTag;
+ IsFixed = Fixed;
+ }
public:
EnumDecl *getCanonicalDecl() {
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
@@ -2263,8 +2459,8 @@ public:
}
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- SourceLocation TKL, EnumDecl *PrevDecl,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, EnumDecl *PrevDecl,
bool IsScoped, bool IsScopedUsingClassTag,
bool IsFixed);
static EnumDecl *Create(ASTContext &C, EmptyShell Empty);
@@ -2326,7 +2522,7 @@ public:
return IntegerType.dyn_cast<TypeSourceInfo*>();
}
- /// \brief Returns the width in bits requred to store all the
+ /// \brief Returns the width in bits required to store all the
/// non-negative enumerators of this enum.
unsigned getNumPositiveBits() const {
return NumPositiveBits;
@@ -2336,7 +2532,7 @@ public:
assert(NumPositiveBits == Num && "can't store this bitcount");
}
- /// \brief Returns the width in bits requred to store all the
+ /// \brief Returns the width in bits required to store all the
/// negative enumerators of this enum. These widths include
/// the rightmost leading 1; that is:
///
@@ -2419,14 +2615,13 @@ class RecordDecl : public TagDecl {
protected:
RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- RecordDecl *PrevDecl, SourceLocation TKL);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, RecordDecl *PrevDecl);
public:
static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- SourceLocation TKL = SourceLocation(),
- RecordDecl* PrevDecl = 0);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, RecordDecl* PrevDecl = 0);
static RecordDecl *Create(const ASTContext &C, EmptyShell Empty);
const RecordDecl *getPreviousDeclaration() const {
@@ -2519,11 +2714,21 @@ private:
class FileScopeAsmDecl : public Decl {
StringLiteral *AsmString;
- FileScopeAsmDecl(DeclContext *DC, SourceLocation L, StringLiteral *asmstring)
- : Decl(FileScopeAsm, DC, L), AsmString(asmstring) {}
+ SourceLocation RParenLoc;
+ FileScopeAsmDecl(DeclContext *DC, StringLiteral *asmstring,
+ SourceLocation StartL, SourceLocation EndL)
+ : Decl(FileScopeAsm, DC, StartL), AsmString(asmstring), RParenLoc(EndL) {}
public:
static FileScopeAsmDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, StringLiteral *Str);
+ StringLiteral *Str, SourceLocation AsmLoc,
+ SourceLocation RParenLoc);
+
+ SourceLocation getAsmLoc() const { return getLocation(); }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+ SourceRange getSourceRange() const {
+ return SourceRange(getAsmLoc(), getRParenLoc());
+ }
const StringLiteral *getAsmString() const { return AsmString; }
StringLiteral *getAsmString() { return AsmString; }
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index b35d134d0534..ce48187f3ade 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -62,6 +62,15 @@ public:
namespace clang {
+ /// \brief Captures the result of checking the availability of a
+ /// declaration.
+ enum AvailabilityResult {
+ AR_Available = 0,
+ AR_NotYetIntroduced,
+ AR_Deprecated,
+ AR_Unavailable
+ };
+
/// Decl - This represents one declaration (or definition), e.g. a variable,
/// typedef, function, struct, etc.
///
@@ -147,9 +156,20 @@ public:
IDNS_NonMemberOperator = 0x0400
};
- /// ObjCDeclQualifier - Qualifier used on types in method declarations
- /// for remote messaging. They are meant for the arguments though and
- /// applied to the Decls (ObjCMethodDecl and ParmVarDecl).
+ /// ObjCDeclQualifier - 'Qualifiers' written next to the return and
+ /// parameter types in method declarations. Other than remembering
+ /// them and mangling them into the method's signature string, these
+ /// are ignored by the compiler; they are consumed by certain
+ /// remote-messaging frameworks.
+ ///
+ /// in, inout, and out are mutually exclusive and apply only to
+ /// method parameters. bycopy and byref are mutually exclusive and
+ /// apply only to method parameters (?). oneway applies only to
+ /// results. All of these expect their corresponding parameter to
+ /// have a particular type. None of this is currently enforced by
+ /// clang.
+ ///
+ /// This should be kept in sync with ObjCDeclSpec::ObjCDeclQualifier.
enum ObjCDeclQualifier {
OBJC_TQ_None = 0x0,
OBJC_TQ_In = 0x1,
@@ -218,6 +238,12 @@ private:
/// required.
unsigned Used : 1;
+ /// \brief Whether this declaration was "referenced".
+ /// The difference with 'Used' is whether the reference appears in a
+ /// evaluated context or not, e.g. functions used in uninstantiated templates
+ /// are regarded as "referenced" but not "used".
+ unsigned Referenced : 1;
+
protected:
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
@@ -252,7 +278,7 @@ protected:
Decl(Kind DK, DeclContext *DC, SourceLocation L)
: NextDeclInContext(0), DeclCtx(DC),
Loc(L), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false),
+ HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
@@ -262,7 +288,7 @@ protected:
Decl(Kind DK, EmptyShell Empty)
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false),
+ HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
@@ -399,6 +425,57 @@ public:
void setUsed(bool U = true) { Used = U; }
+ /// \brief Whether this declaration was referenced.
+ bool isReferenced() const;
+
+ void setReferenced(bool R = true) { Referenced = R; }
+
+ /// \brief Determine the availability of the given declaration.
+ ///
+ /// This routine will determine the most restrictive availability of
+ /// the given declaration (e.g., preferring 'unavailable' to
+ /// 'deprecated').
+ ///
+ /// \param Message If non-NULL and the result is not \c
+ /// AR_Available, will be set to a (possibly empty) message
+ /// describing why the declaration has not been introduced, is
+ /// deprecated, or is unavailable.
+ AvailabilityResult getAvailability(std::string *Message = 0) const;
+
+ /// \brief Determine whether this declaration is marked 'deprecated'.
+ ///
+ /// \param Message If non-NULL and the declaration is deprecated,
+ /// this will be set to the message describing why the declaration
+ /// was deprecated (which may be empty).
+ bool isDeprecated(std::string *Message = 0) const {
+ return getAvailability(Message) == AR_Deprecated;
+ }
+
+ /// \brief Determine whether this declaration is marked 'unavailable'.
+ ///
+ /// \param Message If non-NULL and the declaration is unavailable,
+ /// this will be set to the message describing why the declaration
+ /// was made unavailable (which may be empty).
+ bool isUnavailable(std::string *Message = 0) const {
+ return getAvailability(Message) == AR_Unavailable;
+ }
+
+ /// \brief Determine whether this is a weak-imported symbol.
+ ///
+ /// Weak-imported symbols are typically marked with the
+ /// 'weak_import' attribute, but may also be marked with an
+ /// 'availability' attribute where we're targing a platform prior to
+ /// the introduction of this feature.
+ bool isWeakImported() const;
+
+ /// \brief Determines whether this symbol can be weak-imported,
+ /// e.g., whether it would be well-formed to add the weak_import
+ /// attribute.
+ ///
+ /// \param IsDefinition Set to \c true to indicate that this
+ /// declaration cannot be weak-imported because it has a definition.
+ bool canBeWeakImported(bool &IsDefinition) const;
+
/// \brief Retrieve the level of precompiled header from which this
/// declaration was generated.
///
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 1656a7e9737c..8c819e38781d 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -306,6 +306,37 @@ class CXXRecordDecl : public RecordDecl {
/// one pure virtual function, (that can come from a base class).
bool Abstract : 1;
+ /// IsStandardLayout - True when this class has standard layout.
+ ///
+ /// C++0x [class]p7. A standard-layout class is a class that:
+ /// * has no non-static data members of type non-standard-layout class (or
+ /// array of such types) or reference,
+ /// * has no virtual functions (10.3) and no virtual base classes (10.1),
+ /// * has the same access control (Clause 11) for all non-static data members
+ /// * has no non-standard-layout base classes,
+ /// * either has no non-static data members in the most derived class and at
+ /// most one base class with non-static data members, or has no base
+ /// classes with non-static data members, and
+ /// * has no base classes of the same type as the first non-static data
+ /// member.
+ bool IsStandardLayout : 1;
+
+ /// HasNoNonEmptyBases - True when there are no non-empty base classes.
+ ///
+ /// This is a helper bit of state used to implement IsStandardLayout more
+ /// efficiently.
+ bool HasNoNonEmptyBases : 1;
+
+ /// HasPrivateFields - True when there are private non-static data members.
+ bool HasPrivateFields : 1;
+
+ /// HasProtectedFields - True when there are protected non-static data
+ /// members.
+ bool HasProtectedFields : 1;
+
+ /// HasPublicFields - True when there are private non-static data members.
+ bool HasPublicFields : 1;
+
/// HasTrivialConstructor - True when this class has a trivial constructor.
///
/// C++ [class.ctor]p5. A constructor is trivial if it is an
@@ -316,31 +347,71 @@ class CXXRecordDecl : public RecordDecl {
/// (or array thereof), each such class has a trivial constructor.
bool HasTrivialConstructor : 1;
+ /// HasConstExprNonCopyMoveConstructor - True when this class has at least
+ /// one constexpr constructor which is neither the copy nor move
+ /// constructor.
+ bool HasConstExprNonCopyMoveConstructor : 1;
+
/// HasTrivialCopyConstructor - True when this class has a trivial copy
/// constructor.
///
- /// C++ [class.copy]p6. A copy constructor for class X is trivial
- /// if it is implicitly declared and if
- /// * class X has no virtual functions and no virtual base classes, and
- /// * each direct base class of X has a trivial copy constructor, and
- /// * for all the nonstatic data members of X that are of class type (or
- /// array thereof), each such class type has a trivial copy constructor;
- /// otherwise the copy constructor is non-trivial.
+ /// C++0x [class.copy]p13:
+ /// A copy/move constructor for class X is trivial if it is neither
+ /// user-provided nor deleted and if
+ /// -- class X has no virtual functions and no virtual base classes, and
+ /// -- the constructor selected to copy/move each direct base class
+ /// subobject is trivial, and
+ /// -- for each non-static data member of X that is of class type (or an
+ /// array thereof), the constructor selected to copy/move that member
+ /// is trivial;
+ /// otherwise the copy/move constructor is non-trivial.
bool HasTrivialCopyConstructor : 1;
+ /// HasTrivialMoveConstructor - True when this class has a trivial move
+ /// constructor.
+ ///
+ /// C++0x [class.copy]p13:
+ /// A copy/move constructor for class X is trivial if it is neither
+ /// user-provided nor deleted and if
+ /// -- class X has no virtual functions and no virtual base classes, and
+ /// -- the constructor selected to copy/move each direct base class
+ /// subobject is trivial, and
+ /// -- for each non-static data member of X that is of class type (or an
+ /// array thereof), the constructor selected to copy/move that member
+ /// is trivial;
+ /// otherwise the copy/move constructor is non-trivial.
+ bool HasTrivialMoveConstructor : 1;
+
/// HasTrivialCopyAssignment - True when this class has a trivial copy
/// assignment operator.
///
- /// C++ [class.copy]p11. A copy assignment operator for class X is
- /// trivial if it is implicitly declared and if
- /// * class X has no virtual functions and no virtual base classes, and
- /// * each direct base class of X has a trivial copy assignment operator, and
- /// * for all the nonstatic data members of X that are of class type (or
- /// array thereof), each such class type has a trivial copy assignment
- /// operator;
- /// otherwise the copy assignment operator is non-trivial.
+ /// C++0x [class.copy]p27:
+ /// A copy/move assignment operator for class X is trivial if it is
+ /// neither user-provided nor deleted and if
+ /// -- class X has no virtual functions and no virtual base classes, and
+ /// -- the assignment operator selected to copy/move each direct base
+ /// class subobject is trivial, and
+ /// -- for each non-static data member of X that is of class type (or an
+ /// array thereof), the assignment operator selected to copy/move
+ /// that member is trivial;
+ /// otherwise the copy/move assignment operator is non-trivial.
bool HasTrivialCopyAssignment : 1;
+ /// HasTrivialMoveAssignment - True when this class has a trivial move
+ /// assignment operator.
+ ///
+ /// C++0x [class.copy]p27:
+ /// A copy/move assignment operator for class X is trivial if it is
+ /// neither user-provided nor deleted and if
+ /// -- class X has no virtual functions and no virtual base classes, and
+ /// -- the assignment operator selected to copy/move each direct base
+ /// class subobject is trivial, and
+ /// -- for each non-static data member of X that is of class type (or an
+ /// array thereof), the assignment operator selected to copy/move
+ /// that member is trivial;
+ /// otherwise the copy/move assignment operator is non-trivial.
+ bool HasTrivialMoveAssignment : 1;
+
/// HasTrivialDestructor - True when this class has a trivial destructor.
///
/// C++ [class.dtor]p3. A destructor is trivial if it is an
@@ -351,6 +422,10 @@ class CXXRecordDecl : public RecordDecl {
/// type (or array thereof), each such class has a trivial destructor.
bool HasTrivialDestructor : 1;
+ /// HasNonLiteralTypeFieldsOrBases - True when this class contains at least
+ /// one non-static data member or base class of non literal type.
+ bool HasNonLiteralTypeFieldsOrBases : 1;
+
/// ComputedVisibleConversions - True when visible conversion functions are
/// already computed and are available.
bool ComputedVisibleConversions : 1;
@@ -449,9 +524,8 @@ class CXXRecordDecl : public RecordDecl {
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- CXXRecordDecl *PrevDecl,
- SourceLocation TKL = SourceLocation());
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, CXXRecordDecl *PrevDecl);
public:
/// base_class_iterator - Iterator that traverses the base classes
@@ -494,9 +568,8 @@ public:
bool hasDefinition() const { return DefinitionData != 0; }
static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- SourceLocation TKL = SourceLocation(),
- CXXRecordDecl* PrevDecl=0,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0,
bool DelayTypeCreation = false);
static CXXRecordDecl *Create(const ASTContext &C, EmptyShell Empty);
@@ -723,26 +796,58 @@ public:
/// which means that the class contains or inherits a pure virtual function.
bool isAbstract() const { return data().Abstract; }
+ /// isStandardLayout - Whether this class has standard layout
+ /// (C++ [class]p7)
+ bool isStandardLayout() const { return data().IsStandardLayout; }
+
// hasTrivialConstructor - Whether this class has a trivial constructor
// (C++ [class.ctor]p5)
bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
+ // hasConstExprNonCopyMoveConstructor - Whether this class has at least one
+ // constexpr constructor other than the copy or move constructors
+ bool hasConstExprNonCopyMoveConstructor() const {
+ return data().HasConstExprNonCopyMoveConstructor;
+ }
+
// hasTrivialCopyConstructor - Whether this class has a trivial copy
- // constructor (C++ [class.copy]p6)
+ // constructor (C++ [class.copy]p6, C++0x [class.copy]p13)
bool hasTrivialCopyConstructor() const {
return data().HasTrivialCopyConstructor;
}
+ // hasTrivialMoveConstructor - Whether this class has a trivial move
+ // constructor (C++0x [class.copy]p13)
+ bool hasTrivialMoveConstructor() const {
+ return data().HasTrivialMoveConstructor;
+ }
+
// hasTrivialCopyAssignment - Whether this class has a trivial copy
- // assignment operator (C++ [class.copy]p11)
+ // assignment operator (C++ [class.copy]p11, C++0x [class.copy]p27)
bool hasTrivialCopyAssignment() const {
return data().HasTrivialCopyAssignment;
}
+ // hasTrivialMoveAssignment - Whether this class has a trivial move
+ // assignment operator (C++0x [class.copy]p27)
+ bool hasTrivialMoveAssignment() const {
+ return data().HasTrivialMoveAssignment;
+ }
+
// hasTrivialDestructor - Whether this class has a trivial destructor
// (C++ [class.dtor]p3)
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
+ // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal type
+ // non-static data member or base class.
+ bool hasNonLiteralTypeFieldsOrBases() const {
+ return data().HasNonLiteralTypeFieldsOrBases;
+ }
+
+ // isTriviallyCopyable - Whether this class is considered trivially copyable
+ // (C++0x [class]p5).
+ bool isTriviallyCopyable() const;
+
/// \brief If this record is an instantiation of a member class,
/// retrieves the member class from which it was instantiated.
///
@@ -1034,20 +1139,27 @@ public:
/// struct/union/class.
class CXXMethodDecl : public FunctionDecl {
protected:
- CXXMethodDecl(Kind DK, CXXRecordDecl *RD,
+ CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, StorageClass SCAsWritten, bool isInline)
- : FunctionDecl(DK, RD, NameInfo, T, TInfo, (isStatic ? SC_Static : SC_None),
- SCAsWritten, isInline) {}
+ bool isStatic, StorageClass SCAsWritten, bool isInline,
+ SourceLocation EndLocation)
+ : FunctionDecl(DK, RD, StartLoc, NameInfo, T, TInfo,
+ (isStatic ? SC_Static : SC_None),
+ SCAsWritten, isInline) {
+ if (EndLocation.isValid())
+ setRangeEnd(EndLocation);
+ }
public:
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic = false,
- StorageClass SCAsWritten = SC_None,
- bool isInline = false);
+ bool isStatic,
+ StorageClass SCAsWritten,
+ bool isInline,
+ SourceLocation EndLocation);
bool isStatic() const { return getStorageClass() == SC_Static; }
bool isInstance() const { return !isStatic(); }
@@ -1148,13 +1260,16 @@ public:
/// @endcode
class CXXCtorInitializer {
/// \brief Either the base class name (stored as a TypeSourceInfo*), an normal
- /// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being
- /// initialized.
- llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *>
+ /// field (FieldDecl), anonymous field (IndirectFieldDecl*), or target
+ /// constructor (CXXConstructorDecl*) being initialized.
+ llvm::PointerUnion4<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *,
+ CXXConstructorDecl *>
Initializee;
/// \brief The source location for the field name or, for a base initializer
- /// pack expansion, the location of the ellipsis.
+ /// pack expansion, the location of the ellipsis. In the case of a delegating
+ /// constructor, it will still include the type's source location as the
+ /// Initializee points to the CXXConstructorDecl (to allow loop detection).
SourceLocation MemberOrEllipsisLocation;
/// \brief The argument used to initialize the base or member, which may
@@ -1199,11 +1314,17 @@ public:
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
SourceLocation R);
+ /// CXXCtorInitializer - Creates a new anonymous field initializer.
explicit
CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member,
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
SourceLocation R);
+ /// CXXCtorInitializer - Creates a new delegating Initializer.
+ explicit
+ CXXCtorInitializer(ASTContext &Context, SourceLocation D, SourceLocation L,
+ CXXConstructorDecl *Target, Expr *Init, SourceLocation R);
+
/// \brief Creates a new member initializer that optionally contains
/// array indices used to describe an elementwise initialization.
static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member,
@@ -1227,6 +1348,12 @@ public:
return Initializee.is<IndirectFieldDecl*>();
}
+ /// isDelegatingInitializer - Returns true when this initializer is creating
+ /// a delegating constructor.
+ bool isDelegatingInitializer() const {
+ return Initializee.is<CXXConstructorDecl *>();
+ }
+
/// \brief Determine whether this initializer is a pack expansion.
bool isPackExpansion() const {
return isBaseInitializer() && MemberOrEllipsisLocation.isValid();
@@ -1284,6 +1411,13 @@ public:
return 0;
}
+ CXXConstructorDecl *getTargetConstructor() const {
+ if (isDelegatingInitializer())
+ return Initializee.get<CXXConstructorDecl*>();
+ else
+ return 0;
+ }
+
SourceLocation getMemberLocation() const {
return MemberOrEllipsisLocation;
}
@@ -1373,12 +1507,13 @@ class CXXConstructorDecl : public CXXMethodDecl {
CXXCtorInitializer **CtorInitializers;
unsigned NumCtorInitializers;
- CXXConstructorDecl(CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo,
+ CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isExplicitSpecified, bool isInline,
bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXConstructor, RD, NameInfo, T, TInfo, false,
- SC_None, isInline),
+ : CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false,
+ SC_None, isInline, SourceLocation()),
IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
CtorInitializers(0), NumCtorInitializers(0) {
setImplicit(isImplicitlyDeclared);
@@ -1387,6 +1522,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
public:
static CXXConstructorDecl *Create(ASTContext &C, EmptyShell Empty);
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isExplicit,
@@ -1472,6 +1608,23 @@ public:
void setCtorInitializers(CXXCtorInitializer ** initializers) {
CtorInitializers = initializers;
}
+
+ /// isDelegatingConstructor - Whether this constructor is a
+ /// delegating constructor
+ bool isDelegatingConstructor() const {
+ return (getNumCtorInitializers() == 1) &&
+ CtorInitializers[0]->isDelegatingInitializer();
+ }
+
+ /// getTargetConstructor - When this constructor delegates to
+ /// another, retrieve the target
+ CXXConstructorDecl *getTargetConstructor() const {
+ if (isDelegatingConstructor())
+ return CtorInitializers[0]->getTargetConstructor();
+ else
+ return 0;
+ }
+
/// isDefaultConstructor - Whether this constructor is a default
/// constructor (C++ [class.ctor]p5), which can be used to
/// default-initialize a class of this type.
@@ -1508,8 +1661,11 @@ public:
/// \brief Determine whether this constructor is a move constructor
/// (C++0x [class.copy]p3), which can be used to move values of the class.
- bool isMoveConstructor() const;
-
+ bool isMoveConstructor() const {
+ unsigned TypeQuals = 0;
+ return isMoveConstructor(TypeQuals);
+ }
+
/// \brief Determine whether this is a copy or move constructor.
///
/// \param TypeQuals Will be set to the type qualifiers on the reference
@@ -1567,11 +1723,12 @@ class CXXDestructorDecl : public CXXMethodDecl {
FunctionDecl *OperatorDelete;
- CXXDestructorDecl(CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo,
+ CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXDestructor, RD, NameInfo, T, TInfo, false,
- SC_None, isInline),
+ : CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo, false,
+ SC_None, isInline, SourceLocation()),
ImplicitlyDefined(false), OperatorDelete(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -1579,6 +1736,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
public:
static CXXDestructorDecl *Create(ASTContext& C, EmptyShell Empty);
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo* TInfo,
bool isInline,
@@ -1629,19 +1787,23 @@ class CXXConversionDecl : public CXXMethodDecl {
/// explicitly wrote a cast. This is a C++0x feature.
bool IsExplicitSpecified : 1;
- CXXConversionDecl(CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo,
+ CXXConversionDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicitSpecified)
- : CXXMethodDecl(CXXConversion, RD, NameInfo, T, TInfo, false,
- SC_None, isInline),
+ bool isInline, bool isExplicitSpecified,
+ SourceLocation EndLocation)
+ : CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo, false,
+ SC_None, isInline, EndLocation),
IsExplicitSpecified(isExplicitSpecified) { }
public:
static CXXConversionDecl *Create(ASTContext &C, EmptyShell Empty);
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicit);
+ bool isInline, bool isExplicit,
+ SourceLocation EndLocation);
/// IsExplicitSpecified - Whether this conversion function declaration is
/// marked "explicit", meaning that it can only be applied when the user
@@ -1688,33 +1850,48 @@ public:
private:
/// Language - The language for this linkage specification.
LanguageIDs Language;
+ /// ExternLoc - The source location for the extern keyword.
+ SourceLocation ExternLoc;
+ /// RBraceLoc - The source location for the right brace (if valid).
+ SourceLocation RBraceLoc;
- /// HadBraces - Whether this linkage specification had curly braces or not.
- bool HadBraces : 1;
-
- LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang,
- bool Braces)
- : Decl(LinkageSpec, DC, L),
- DeclContext(LinkageSpec), Language(lang), HadBraces(Braces) { }
+ LinkageSpecDecl(DeclContext *DC, SourceLocation ExternLoc,
+ SourceLocation LangLoc, LanguageIDs lang,
+ SourceLocation RBLoc)
+ : Decl(LinkageSpec, DC, LangLoc), DeclContext(LinkageSpec),
+ Language(lang), ExternLoc(ExternLoc), RBraceLoc(RBLoc) { }
public:
static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, LanguageIDs Lang,
- bool Braces);
+ SourceLocation ExternLoc,
+ SourceLocation LangLoc, LanguageIDs Lang,
+ SourceLocation RBraceLoc = SourceLocation());
/// \brief Return the language specified by this linkage specification.
LanguageIDs getLanguage() const { return Language; }
-
/// \brief Set the language specified by this linkage specification.
void setLanguage(LanguageIDs L) { Language = L; }
/// \brief Determines whether this linkage specification had braces in
/// its syntactic form.
- bool hasBraces() const { return HadBraces; }
+ bool hasBraces() const { return RBraceLoc.isValid(); }
- /// \brief Set whether this linkage specification has braces in its
- /// syntactic form.
- void setHasBraces(bool B) { HadBraces = B; }
+ SourceLocation getExternLoc() const { return ExternLoc; }
+ SourceLocation getRBraceLoc() const { return RBraceLoc; }
+ void setExternLoc(SourceLocation L) { ExternLoc = L; }
+ void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
+
+ SourceLocation getLocEnd() const {
+ if (hasBraces())
+ return getRBraceLoc();
+ // No braces: get the end location of the (only) declaration in context
+ // (if present).
+ return decls_empty() ? getLocation() : decls_begin()->getLocEnd();
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(ExternLoc, getLocEnd());
+ }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const LinkageSpecDecl *D) { return true; }
@@ -2023,12 +2200,6 @@ public:
return QualifierLoc.getNestedNameSpecifier();
}
- /// \brief Retrieve the source range of the nested-name-specifier
- /// that qualifies the name.
- SourceRange getQualifierRange() const {
- return QualifierLoc.getSourceRange();
- }
-
DeclarationNameInfo getNameInfo() const {
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
}
@@ -2154,12 +2325,6 @@ public:
return QualifierLoc.getNestedNameSpecifier();
}
- /// \brief Retrieve the source range of the nested-name-specifier
- /// that qualifies the name.
- SourceRange getQualifierRange() const {
- return QualifierLoc.getSourceRange();
- }
-
DeclarationNameInfo getNameInfo() const {
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
}
@@ -2205,15 +2370,15 @@ class UnresolvedUsingTypenameDecl : public TypeDecl {
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc,
IdentifierInfo *TargetName)
- : TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName),
- UsingLocation(UsingLoc), TypenameLocation(TypenameLoc),
- QualifierLoc(QualifierLoc) { }
+ : TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName,
+ UsingLoc),
+ TypenameLocation(TypenameLoc), QualifierLoc(QualifierLoc) { }
friend class ASTDeclReader;
public:
/// \brief Returns the source location of the 'using' keyword.
- SourceLocation getUsingLoc() const { return UsingLocation; }
+ SourceLocation getUsingLoc() const { return getLocStart(); }
/// \brief Returns the source location of the 'typename' keyword.
SourceLocation getTypenameLoc() const { return TypenameLocation; }
@@ -2227,22 +2392,11 @@ public:
return QualifierLoc.getNestedNameSpecifier();
}
- /// \brief Retrieve the source range of the nested-name-specifier
- /// that qualifies the name.
- SourceRange getQualifierRange() const {
- return QualifierLoc.getSourceRange();
- }
-
- // FIXME: DeclarationNameInfo
static UnresolvedUsingTypenameDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc,
SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc, DeclarationName TargetName);
- SourceRange getSourceRange() const {
- return SourceRange(UsingLocation, getLocation());
- }
-
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
@@ -2252,15 +2406,19 @@ public:
class StaticAssertDecl : public Decl {
Expr *AssertExpr;
StringLiteral *Message;
+ SourceLocation RParenLoc;
- StaticAssertDecl(DeclContext *DC, SourceLocation L,
- Expr *assertexpr, StringLiteral *message)
- : Decl(StaticAssert, DC, L), AssertExpr(assertexpr), Message(message) { }
+ StaticAssertDecl(DeclContext *DC, SourceLocation StaticAssertLoc,
+ Expr *assertexpr, StringLiteral *message,
+ SourceLocation RParenLoc)
+ : Decl(StaticAssert, DC, StaticAssertLoc), AssertExpr(assertexpr),
+ Message(message), RParenLoc(RParenLoc) { }
public:
static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, Expr *AssertExpr,
- StringLiteral *Message);
+ SourceLocation StaticAssertLoc,
+ Expr *AssertExpr, StringLiteral *Message,
+ SourceLocation RParenLoc);
Expr *getAssertExpr() { return AssertExpr; }
const Expr *getAssertExpr() const { return AssertExpr; }
@@ -2268,6 +2426,13 @@ public:
StringLiteral *getMessage() { return Message; }
const StringLiteral *getMessage() const { return Message; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getLocation(), getRParenLoc());
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(StaticAssertDecl *D) { return true; }
static bool classofKind(Kind K) { return K == StaticAssert; }
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 20d6da19b8ca..b84e5bba86b7 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -98,6 +98,17 @@ public:
return FriendLoc;
}
+ /// Retrieves the source range for the friend declaration.
+ SourceRange getSourceRange() const {
+ /* FIXME: consider the case of templates wrt start of range. */
+ if (NamedDecl *ND = getFriendDecl())
+ return SourceRange(getFriendLoc(), ND->getLocEnd());
+ else if (TypeSourceInfo *TInfo = getFriendType())
+ return SourceRange(getFriendLoc(), TInfo->getTypeLoc().getEndLoc());
+ else
+ return SourceRange(getFriendLoc(), getLocation());
+ }
+
/// Determines if this friend kind is unsupported.
bool isUnsupportedFriend() const {
return UnsupportedFriend;
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index b3ca474fcc19..0a4d864cd867 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -112,17 +112,20 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
public:
enum ImplementationControl { None, Required, Optional };
private:
- /// Bitfields must be first fields in this class so they pack with those
- /// declared in class Decl.
+ // The conventional meaning of this method; an ObjCMethodFamily.
+ // This is not serialized; instead, it is computed on demand and
+ // cached.
+ mutable unsigned Family : ObjCMethodFamilyBitWidth;
+
/// instance (true) or class (false) method.
- bool IsInstance : 1;
- bool IsVariadic : 1;
+ unsigned IsInstance : 1;
+ unsigned IsVariadic : 1;
// Synthesized declaration method for a property setter/getter
- bool IsSynthesized : 1;
+ unsigned IsSynthesized : 1;
// Method has a definition.
- bool IsDefined : 1;
+ unsigned IsDefined : 1;
// NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
/// @required/@optional
@@ -170,7 +173,7 @@ private:
ImplementationControl impControl = None,
unsigned numSelectorArgs = 0)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
- DeclContext(ObjCMethod),
+ DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
IsInstance(isInstance), IsVariadic(isVariadic),
IsSynthesized(isSynthesized),
IsDefined(isDefined),
@@ -279,6 +282,9 @@ public:
ImplicitParamDecl * getCmdDecl() const { return CmdDecl; }
void setCmdDecl(ImplicitParamDecl *CD) { CmdDecl = CD; }
+ /// Determines the family of this method.
+ ObjCMethodFamily getMethodFamily() const;
+
bool isInstanceMethod() const { return IsInstance; }
void setInstanceMethod(bool isInst) { IsInstance = isInst; }
bool isVariadic() const { return IsVariadic; }
@@ -453,7 +459,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
///
/// Categories are stored as a linked list in the AST, since the categories
/// and class extensions come long after the initial interface declaration,
- /// and we avoid dynamically-resized arrays in the AST whereever possible.
+ /// and we avoid dynamically-resized arrays in the AST wherever possible.
ObjCCategoryDecl *CategoryList;
/// IvarList - List of all ivars defined by this class; including class
@@ -701,15 +707,18 @@ public:
};
private:
- ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation L, IdentifierInfo *Id,
+ ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized)
- : FieldDecl(ObjCIvar, DC, L, Id, T, TInfo, BW, /*Mutable=*/false),
- NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
+ : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
+ /*Mutable=*/false),
+ NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
public:
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
- SourceLocation L, IdentifierInfo *Id, QualType T,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW = NULL,
bool synthesized=false);
@@ -753,17 +762,18 @@ private:
/// @defs(...).
class ObjCAtDefsFieldDecl : public FieldDecl {
private:
- ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, Expr *BW)
- : FieldDecl(ObjCAtDefsField, DC, L, Id, T,
+ : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
/*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ?
BW, /*Mutable=*/false) {}
public:
static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- IdentifierInfo *Id, QualType T,
- Expr *BW);
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ QualType T, Expr *BW);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -773,7 +783,7 @@ public:
/// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols
/// declare a pure abstract type (i.e no instance variables are permitted).
-/// Protocols orginally drew inspiration from C++ pure virtual functions (a C++
+/// Protocols originally drew inspiration from C++ pure virtual functions (a C++
/// feature with nice semantics and lousy syntax:-). Here is an example:
///
/// @protocol NSDraggingInfo <refproto1, refproto2>
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index f41859c85790..ddbe344cdffd 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -771,9 +771,20 @@ protected:
/// \brief Data that is common to all of the declarations of a given
/// function template.
struct Common : CommonBase {
+ Common() : InjectedArgs(0) { }
+
/// \brief The function template specializations for this function
/// template, including explicit specializations and instantiations.
llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations;
+
+ /// \brief The set of "injected" template arguments used within this
+ /// function template.
+ ///
+ /// This pointer refers to the template arguments (there are as
+ /// many template arguments as template parameaters) for the function
+ /// template, and is allocated lazily, since most function templates do not
+ /// require the use of this information.
+ TemplateArgument *InjectedArgs;
};
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
@@ -793,6 +804,13 @@ protected:
llvm::FoldingSet<FunctionTemplateSpecializationInfo> &getSpecializations() {
return getCommonPtr()->Specializations;
}
+
+ /// \brief Add a specialization of this function template.
+ ///
+ /// \param InsertPos Insert position in the FoldingSet, must have been
+ /// retrieved by an earlier call to findSpecialization().
+ void addSpecialization(FunctionTemplateSpecializationInfo* Info,
+ void *InsertPos);
public:
/// Get the underlying function declaration of the template.
@@ -844,13 +862,25 @@ public:
return makeSpecIterator(getSpecializations(), true);
}
- /// Create a template function node.
+ /// \brief Retrieve the "injected" template arguments that correspond to the
+ /// template parameters of this function template.
+ ///
+ /// Although the C++ standard has no notion of the "injected" template
+ /// arguments for a function template, the notion is convenient when
+ /// we need to perform substitutions inside the definition of a function
+ /// template.
+ std::pair<const TemplateArgument *, unsigned> getInjectedTemplateArgs();
+
+ /// \brief Create a function template node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl);
+ /// \brief Create an empty function template node.
+ static FunctionTemplateDecl *Create(ASTContext &C, EmptyShell);
+
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FunctionTemplateDecl *D) { return true; }
@@ -915,25 +945,23 @@ class TemplateTypeParmDecl : public TypeDecl {
/// default argument.
bool InheritedDefault : 1;
- /// \brief Whether this is a parameter pack.
- bool ParameterPack : 1;
-
/// \brief The default template argument, if any.
TypeSourceInfo *DefaultArgument;
- TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
- bool Typename, QualType Type, bool ParameterPack)
- : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
- InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() {
- TypeForDecl = Type.getTypePtrOrNull();
- }
+ TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ bool Typename)
+ : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename),
+ InheritedDefault(false), DefaultArgument() { }
/// Sema creates these on the stack during auto type deduction.
friend class Sema;
public:
static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
+ SourceLocation KeyLoc,
+ SourceLocation NameLoc,
+ unsigned D, unsigned P,
IdentifierInfo *Id, bool Typename,
bool ParameterPack);
static TemplateTypeParmDecl *Create(const ASTContext &C, EmptyShell Empty);
@@ -978,9 +1006,6 @@ public:
/// the 'typename' or 'class' keyword.
void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; }
- /// \brief Set whether this is a parameter pack.
- void setParameterPack(bool isParamPack) { ParameterPack = isParamPack; }
-
/// \brief Retrieve the depth of the template parameter.
unsigned getDepth() const;
@@ -988,7 +1013,9 @@ public:
unsigned getIndex() const;
/// \brief Returns whether this is a parameter pack.
- bool isParameterPack() const { return ParameterPack; }
+ bool isParameterPack() const;
+
+ SourceRange getSourceRange() const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -1021,17 +1048,19 @@ class NonTypeTemplateParmDecl
/// \brief The number of types in an expanded parameter pack.
unsigned NumExpandedTypes;
- NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id, QualType T,
+ NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, unsigned D, unsigned P,
+ IdentifierInfo *Id, QualType T,
bool ParameterPack, TypeSourceInfo *TInfo)
- : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo),
+ : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
ParameterPack(ParameterPack), ExpandedParameterPack(false),
NumExpandedTypes(0)
{ }
- NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id, QualType T,
+ NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, unsigned D, unsigned P,
+ IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
const QualType *ExpandedTypes,
unsigned NumExpandedTypes,
@@ -1041,13 +1070,14 @@ class NonTypeTemplateParmDecl
public:
static NonTypeTemplateParmDecl *
- Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack,
- TypeSourceInfo *TInfo);
+ Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
+ QualType T, bool ParameterPack, TypeSourceInfo *TInfo);
static NonTypeTemplateParmDecl *
- Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
+ Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
+ QualType T, TypeSourceInfo *TInfo,
const QualType *ExpandedTypes, unsigned NumExpandedTypes,
TypeSourceInfo **ExpandedTInfos);
@@ -1057,7 +1087,6 @@ public:
using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
- SourceLocation getInnerLocStart() const;
SourceRange getSourceRange() const;
/// \brief Determine whether this template parameter has a default
@@ -1316,7 +1345,8 @@ class ClassTemplateSpecializationDecl
protected:
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
- DeclContext *DC, SourceLocation L,
+ DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
@@ -1326,7 +1356,8 @@ protected:
public:
static ClassTemplateSpecializationDecl *
- Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L,
+ Create(ASTContext &Context, TagKind TK, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
@@ -1488,7 +1519,7 @@ public:
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
}
- SourceLocation getInnerLocStart() const { return getTemplateKeywordLoc(); }
+ SourceRange getSourceRange() const;
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
@@ -1544,7 +1575,9 @@ class ClassTemplatePartialSpecializationDecl
InstantiatedFromMember;
ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
- DeclContext *DC, SourceLocation L,
+ DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
@@ -1552,14 +1585,7 @@ class ClassTemplatePartialSpecializationDecl
TemplateArgumentLoc *ArgInfos,
unsigned NumArgInfos,
ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber)
- : ClassTemplateSpecializationDecl(Context,
- ClassTemplatePartialSpecialization,
- TK, DC, L, SpecializedTemplate,
- Args, NumArgs, PrevDecl),
- TemplateParams(Params), ArgsAsWritten(ArgInfos),
- NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
- InstantiatedFromMember(0, false) { }
+ unsigned SequenceNumber);
ClassTemplatePartialSpecializationDecl()
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
@@ -1569,7 +1595,8 @@ class ClassTemplatePartialSpecializationDecl
public:
static ClassTemplatePartialSpecializationDecl *
- Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
+ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
@@ -1742,6 +1769,10 @@ protected:
TemplateParameterList *Params, NamedDecl *Decl)
: RedeclarableTemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { }
+ ClassTemplateDecl(EmptyShell Empty)
+ : RedeclarableTemplateDecl(ClassTemplate, 0, SourceLocation(),
+ DeclarationName(), 0, 0) { }
+
CommonBase *newCommon(ASTContext &C);
Common *getCommonPtr() {
@@ -1768,6 +1799,9 @@ public:
NamedDecl *Decl,
ClassTemplateDecl *PrevDecl);
+ /// Create an empty class template node.
+ static ClassTemplateDecl *Create(ASTContext &C, EmptyShell);
+
/// \brief Return the specialization with the provided arguments if it exists,
/// otherwise return the insertion point.
ClassTemplateSpecializationDecl *
diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h
index 035f57c12ea7..bab1606dcee4 100644
--- a/include/clang/AST/EvaluatedExprVisitor.h
+++ b/include/clang/AST/EvaluatedExprVisitor.h
@@ -37,7 +37,8 @@ public:
// other sub-expressions).
void VisitDeclRefExpr(DeclRefExpr *E) { }
void VisitOffsetOfExpr(OffsetOfExpr *E) { }
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { }
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { }
+ void VisitExpressionTraitExpr(ExpressionTraitExpr *E) { }
void VisitBlockExpr(BlockExpr *E) { }
void VisitCXXUuidofExpr(CXXUuidofExpr *E) { }
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { }
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 95bfad5a16c2..5f2d144eb544 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -21,12 +21,12 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ASTVector.h"
#include "clang/AST/UsuallyTinyPtrVector.h"
+#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <cctype>
-#include <vector>
namespace clang {
class ASTContext;
@@ -172,6 +172,7 @@ public:
LV_IncompleteVoidType,
LV_DuplicateVectorComponents,
LV_InvalidExpression,
+ LV_InvalidMessageExpression,
LV_MemberFunction,
LV_SubObjCPropertySetting,
LV_ClassTemporary
@@ -203,6 +204,7 @@ public:
MLV_NoSetterProperty,
MLV_MemberFunction,
MLV_SubObjCPropertySetting,
+ MLV_InvalidMessageExpression,
MLV_ClassTemporary
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
@@ -218,10 +220,12 @@ public:
CL_XValue,
CL_Function, // Functions cannot be lvalues in C.
CL_Void, // Void cannot be an lvalue in C.
+ CL_AddressableVoid, // Void expression whose address can be taken in C.
CL_DuplicateVectorComponents, // A vector shuffle with dupes.
CL_MemberFunction, // An expression referring to a member function
CL_SubObjCPropertySetting,
CL_ClassTemporary, // A prvalue of class type
+ CL_ObjCMessageRValue, // ObjC message is an rvalue
CL_PRValue // A prvalue for any other reason, of any other type
};
/// \brief The results of modification testing.
@@ -482,6 +486,11 @@ public:
/// \brief Returns true if this expression is a bound member function.
bool isBoundMemberFunction(ASTContext &Ctx) const;
+ /// \brief Given an expression of bound-member type, find the type
+ /// of the member. Returns null if this is an *overloaded* bound
+ /// member expression.
+ static QualType findBoundMemberType(const Expr *expr);
+
/// \brief Result type of CanThrow().
enum CanThrowResult {
CT_Cannot,
@@ -536,6 +545,9 @@ public:
/// temporary object of the given class type.
bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const;
+ /// \brief Whether this expression is an implicit reference to 'this' in C++.
+ bool isImplicitCXXThis() const;
+
const Expr *IgnoreParens() const {
return const_cast<Expr*>(this)->IgnoreParens();
}
@@ -618,16 +630,6 @@ public:
static bool classof(const OpaqueValueExpr *) { return true; }
};
-/// \brief Represents the qualifier that may precede a C++ name, e.g., the
-/// "std::" in "std::sort".
-struct NameQualifier {
- /// \brief The nested name specifier.
- NestedNameSpecifier *NNS;
-
- /// \brief The source range covered by the nested name specifier.
- SourceRange Range;
-};
-
/// \brief Represents an explicit template argument list in C++, e.g.,
/// the "<int>" in "sort<int>".
struct ExplicitTemplateArgumentList {
@@ -659,95 +661,118 @@ struct ExplicitTemplateArgumentList {
static std::size_t sizeFor(unsigned NumTemplateArgs);
static std::size_t sizeFor(const TemplateArgumentListInfo &List);
};
-
-/// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function,
-/// enum, etc.
+
+/// \brief A reference to a declared variable, function, enum, etc.
+/// [C99 6.5.1p2]
+///
+/// This encodes all the information about how a declaration is referenced
+/// within an expression.
+///
+/// There are several optional constructs attached to DeclRefExprs only when
+/// they apply in order to conserve memory. These are laid out past the end of
+/// the object, and flags in the DeclRefExprBitfield track whether they exist:
+///
+/// DeclRefExprBits.HasQualifier:
+/// Specifies when this declaration reference expression has a C++
+/// nested-name-specifier.
+/// DeclRefExprBits.HasFoundDecl:
+/// Specifies when this declaration reference expression has a record of
+/// a NamedDecl (different from the referenced ValueDecl) which was found
+/// during name lookup and/or overload resolution.
+/// DeclRefExprBits.HasExplicitTemplateArgs:
+/// Specifies when this declaration reference expression has an explicit
+/// C++ template argument list.
class DeclRefExpr : public Expr {
- enum {
- // Flag on DecoratedD that specifies when this declaration reference
- // expression has a C++ nested-name-specifier.
- HasQualifierFlag = 0x01,
- // Flag on DecoratedD that specifies when this declaration reference
- // expression has an explicit C++ template argument list.
- HasExplicitTemplateArgumentListFlag = 0x02
- };
-
- // DecoratedD - The declaration that we are referencing, plus two bits to
- // indicate whether (1) the declaration's name was explicitly qualified and
- // (2) the declaration's name was followed by an explicit template
- // argument list.
- llvm::PointerIntPair<ValueDecl *, 2> DecoratedD;
+ /// \brief The declaration that we are referencing.
+ ValueDecl *D;
- // Loc - The location of the declaration name itself.
+ /// \brief The location of the declaration name itself.
SourceLocation Loc;
- /// DNLoc - Provides source/type location info for the
- /// declaration name embedded in DecoratedD.
+ /// \brief Provides source/type location info for the declaration name
+ /// embedded in D.
DeclarationNameLoc DNLoc;
- /// \brief Retrieve the qualifier that preceded the declaration name, if any.
- NameQualifier *getNameQualifier() {
- if ((DecoratedD.getInt() & HasQualifierFlag) == 0)
- return 0;
-
- return reinterpret_cast<NameQualifier *> (this + 1);
+ /// \brief Helper to retrieve the optional NestedNameSpecifierLoc.
+ NestedNameSpecifierLoc &getInternalQualifierLoc() {
+ assert(hasQualifier());
+ return *reinterpret_cast<NestedNameSpecifierLoc *>(this + 1);
}
-
- /// \brief Retrieve the qualifier that preceded the member name, if any.
- const NameQualifier *getNameQualifier() const {
- return const_cast<DeclRefExpr *>(this)->getNameQualifier();
+
+ /// \brief Helper to retrieve the optional NestedNameSpecifierLoc.
+ const NestedNameSpecifierLoc &getInternalQualifierLoc() const {
+ return const_cast<DeclRefExpr *>(this)->getInternalQualifierLoc();
}
- DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange,
- ValueDecl *D, SourceLocation NameLoc,
- const TemplateArgumentListInfo *TemplateArgs,
- QualType T, ExprValueKind VK);
+ /// \brief Test whether there is a distinct FoundDecl attached to the end of
+ /// this DRE.
+ bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
- DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange,
+ /// \brief Helper to retrieve the optional NamedDecl through which this
+ /// reference occured.
+ NamedDecl *&getInternalFoundDecl() {
+ assert(hasFoundDecl());
+ if (hasQualifier())
+ return *reinterpret_cast<NamedDecl **>(&getInternalQualifierLoc() + 1);
+ return *reinterpret_cast<NamedDecl **>(this + 1);
+ }
+
+ /// \brief Helper to retrieve the optional NamedDecl through which this
+ /// reference occured.
+ NamedDecl *getInternalFoundDecl() const {
+ return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
+ }
+
+ DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D, const DeclarationNameInfo &NameInfo,
+ NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
QualType T, ExprValueKind VK);
/// \brief Construct an empty declaration reference expression.
explicit DeclRefExpr(EmptyShell Empty)
: Expr(DeclRefExprClass, Empty) { }
-
+
/// \brief Computes the type- and value-dependence flags for this
/// declaration reference expression.
void computeDependence();
public:
- DeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK, SourceLocation l) :
- Expr(DeclRefExprClass, t, VK, OK_Ordinary, false, false, false),
- DecoratedD(d, 0), Loc(l) {
+ DeclRefExpr(ValueDecl *D, QualType T, ExprValueKind VK, SourceLocation L)
+ : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
+ D(D), Loc(L) {
+ DeclRefExprBits.HasQualifier = 0;
+ DeclRefExprBits.HasExplicitTemplateArgs = 0;
+ DeclRefExprBits.HasFoundDecl = 0;
computeDependence();
}
static DeclRefExpr *Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D,
SourceLocation NameLoc,
QualType T, ExprValueKind VK,
+ NamedDecl *FoundD = 0,
const TemplateArgumentListInfo *TemplateArgs = 0);
static DeclRefExpr *Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D,
const DeclarationNameInfo &NameInfo,
QualType T, ExprValueKind VK,
+ NamedDecl *FoundD = 0,
const TemplateArgumentListInfo *TemplateArgs = 0);
/// \brief Construct an empty declaration reference expression.
static DeclRefExpr *CreateEmpty(ASTContext &Context,
- bool HasQualifier,
+ bool HasQualifier,
+ bool HasFoundDecl,
bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs);
-
- ValueDecl *getDecl() { return DecoratedD.getPointer(); }
- const ValueDecl *getDecl() const { return DecoratedD.getPointer(); }
- void setDecl(ValueDecl *NewD) { DecoratedD.setPointer(NewD); }
+
+ ValueDecl *getDecl() { return D; }
+ const ValueDecl *getDecl() const { return D; }
+ void setDecl(ValueDecl *NewD) { D = NewD; }
DeclarationNameInfo getNameInfo() const {
return DeclarationNameInfo(getDecl()->getDeclName(), Loc, DNLoc);
@@ -759,43 +784,62 @@ public:
/// \brief Determine whether this declaration reference was preceded by a
/// C++ nested-name-specifier, e.g., \c N::foo.
- bool hasQualifier() const { return DecoratedD.getInt() & HasQualifierFlag; }
-
- /// \brief If the name was qualified, retrieves the source range of
- /// the nested-name-specifier that precedes the name. Otherwise,
- /// returns an empty source range.
- SourceRange getQualifierRange() const {
- if (!hasQualifier())
- return SourceRange();
-
- return getNameQualifier()->Range;
- }
-
- /// \brief If the name was qualified, retrieves the nested-name-specifier
+ bool hasQualifier() const { return DeclRefExprBits.HasQualifier; }
+
+ /// \brief If the name was qualified, retrieves the nested-name-specifier
/// that precedes the name. Otherwise, returns NULL.
NestedNameSpecifier *getQualifier() const {
if (!hasQualifier())
return 0;
-
- return getNameQualifier()->NNS;
+
+ return getInternalQualifierLoc().getNestedNameSpecifier();
}
-
+
+ /// \brief If the name was qualified, retrieves the nested-name-specifier
+ /// that precedes the name, with source-location information.
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ if (!hasQualifier())
+ return NestedNameSpecifierLoc();
+
+ return getInternalQualifierLoc();
+ }
+
+ /// \brief Get the NamedDecl through which this reference occured.
+ ///
+ /// This Decl may be different from the ValueDecl actually referred to in the
+ /// presence of using declarations, etc. It always returns non-NULL, and may
+ /// simple return the ValueDecl when appropriate.
+ NamedDecl *getFoundDecl() {
+ return hasFoundDecl() ? getInternalFoundDecl() : D;
+ }
+
+ /// \brief Get the NamedDecl through which this reference occurred.
+ /// See non-const variant.
+ const NamedDecl *getFoundDecl() const {
+ return hasFoundDecl() ? getInternalFoundDecl() : D;
+ }
+
+ /// \brief Determines whether this declaration reference was followed by an
+ /// explict template argument list.
bool hasExplicitTemplateArgs() const {
- return (DecoratedD.getInt() & HasExplicitTemplateArgumentListFlag);
+ return DeclRefExprBits.HasExplicitTemplateArgs;
}
-
+
/// \brief Retrieve the explicit template argument list that followed the
/// member template name.
ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
assert(hasExplicitTemplateArgs());
+ if (hasFoundDecl())
+ return *reinterpret_cast<ExplicitTemplateArgumentList *>(
+ &getInternalFoundDecl() + 1);
- if ((DecoratedD.getInt() & HasQualifierFlag) == 0)
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
-
- return *reinterpret_cast<ExplicitTemplateArgumentList *>(
- getNameQualifier() + 1);
+ if (hasQualifier())
+ return *reinterpret_cast<ExplicitTemplateArgumentList *>(
+ &getInternalQualifierLoc() + 1);
+
+ return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
}
-
+
/// \brief Retrieve the explicit template argument list that followed the
/// member template name.
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
@@ -809,50 +853,50 @@ public:
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
-
+
/// \brief Copies the template arguments (if present) into the given
/// structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
if (hasExplicitTemplateArgs())
getExplicitTemplateArgs().copyInto(List);
}
-
+
/// \brief Retrieve the location of the left angle bracket following the
/// member name ('<'), if any.
SourceLocation getLAngleLoc() const {
if (!hasExplicitTemplateArgs())
return SourceLocation();
-
+
return getExplicitTemplateArgs().LAngleLoc;
}
-
+
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
if (!hasExplicitTemplateArgs())
return 0;
-
+
return getExplicitTemplateArgs().getTemplateArgs();
}
-
+
/// \brief Retrieve the number of template arguments provided as part of this
/// template-id.
unsigned getNumTemplateArgs() const {
if (!hasExplicitTemplateArgs())
return 0;
-
+
return getExplicitTemplateArgs().NumTemplateArgs;
}
-
+
/// \brief Retrieve the location of the right angle bracket following the
/// template arguments ('>').
SourceLocation getRAngleLoc() const {
if (!hasExplicitTemplateArgs())
return SourceLocation();
-
+
return getExplicitTemplateArgs().RAngleLoc;
}
-
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass;
}
@@ -860,7 +904,7 @@ public:
// Iterators
child_range children() { return child_range(); }
-
+
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
@@ -1133,9 +1177,12 @@ public:
/// In this case, getByteLength() will return 6, but the string literal will
/// have type "char[2]".
class StringLiteral : public Expr {
+ friend class ASTStmtReader;
+
const char *StrData;
unsigned ByteLength;
bool IsWide;
+ bool IsPascal;
unsigned NumConcatenated;
SourceLocation TokLocs[1];
@@ -1146,14 +1193,15 @@ public:
/// This is the "fully general" constructor that allows representation of
/// strings formed from multiple concatenated tokens.
static StringLiteral *Create(ASTContext &C, const char *StrData,
- unsigned ByteLength, bool Wide, QualType Ty,
+ unsigned ByteLength, bool Wide, bool Pascal,
+ QualType Ty,
const SourceLocation *Loc, unsigned NumStrs);
/// Simple constructor for string literals made from one token.
static StringLiteral *Create(ASTContext &C, const char *StrData,
- unsigned ByteLength,
- bool Wide, QualType Ty, SourceLocation Loc) {
- return Create(C, StrData, ByteLength, Wide, Ty, &Loc, 1);
+ unsigned ByteLength, bool Wide,
+ bool Pascal, QualType Ty, SourceLocation Loc) {
+ return Create(C, StrData, ByteLength, Wide, Pascal, Ty, &Loc, 1);
}
/// \brief Construct an empty string literal.
@@ -1169,8 +1217,8 @@ public:
void setString(ASTContext &C, llvm::StringRef Str);
bool isWide() const { return IsWide; }
- void setWide(bool W) { IsWide = W; }
-
+ bool isPascal() const { return IsPascal; }
+
bool containsNonAsciiOrNull() const {
llvm::StringRef Str = getString();
for (unsigned i = 0, e = Str.size(); i != e; ++i)
@@ -1458,7 +1506,7 @@ public:
/// the square brackets. For a field or identifier node, the source range
/// contains the location of the period (if there is one) and the
/// identifier.
- SourceRange getRange() const { return Range; }
+ SourceRange getSourceRange() const { return Range; }
};
private:
@@ -1556,10 +1604,11 @@ public:
}
};
-/// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of
-/// types and expressions.
-class SizeOfAlignOfExpr : public Expr {
- bool isSizeof : 1; // true if sizeof, false if alignof.
+/// UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated)
+/// expression operand. Used for sizeof/alignof (C99 6.5.3.4) and
+/// vec_step (OpenCL 1.1 6.11.12).
+class UnaryExprOrTypeTraitExpr : public Expr {
+ unsigned Kind : 2;
bool isType : 1; // true if operand is a type, false if an expression
union {
TypeSourceInfo *Ty;
@@ -1568,36 +1617,38 @@ class SizeOfAlignOfExpr : public Expr {
SourceLocation OpLoc, RParenLoc;
public:
- SizeOfAlignOfExpr(bool issizeof, TypeSourceInfo *TInfo,
- QualType resultType, SourceLocation op,
- SourceLocation rp) :
- Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary,
+ UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, TypeSourceInfo *TInfo,
+ QualType resultType, SourceLocation op,
+ SourceLocation rp) :
+ Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary,
false, // Never type-dependent (C++ [temp.dep.expr]p3).
// Value-dependent if the argument is type-dependent.
TInfo->getType()->isDependentType(),
TInfo->getType()->containsUnexpandedParameterPack()),
- isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) {
+ Kind(ExprKind), isType(true), OpLoc(op), RParenLoc(rp) {
Argument.Ty = TInfo;
}
- SizeOfAlignOfExpr(bool issizeof, Expr *E,
- QualType resultType, SourceLocation op,
- SourceLocation rp) :
- Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary,
+ UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, Expr *E,
+ QualType resultType, SourceLocation op,
+ SourceLocation rp) :
+ Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary,
false, // Never type-dependent (C++ [temp.dep.expr]p3).
// Value-dependent if the argument is type-dependent.
E->isTypeDependent(),
E->containsUnexpandedParameterPack()),
- isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) {
+ Kind(ExprKind), isType(false), OpLoc(op), RParenLoc(rp) {
Argument.Ex = E;
}
/// \brief Construct an empty sizeof/alignof expression.
- explicit SizeOfAlignOfExpr(EmptyShell Empty)
- : Expr(SizeOfAlignOfExprClass, Empty) { }
+ explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty)
+ : Expr(UnaryExprOrTypeTraitExprClass, Empty) { }
- bool isSizeOf() const { return isSizeof; }
- void setSizeof(bool S) { isSizeof = S; }
+ UnaryExprOrTypeTrait getKind() const {
+ return static_cast<UnaryExprOrTypeTrait>(Kind);
+ }
+ void setKind(UnaryExprOrTypeTrait K) { Kind = K; }
bool isArgumentType() const { return isType; }
QualType getArgumentType() const {
@@ -1612,7 +1663,7 @@ public:
return static_cast<Expr*>(Argument.Ex);
}
const Expr *getArgumentExpr() const {
- return const_cast<SizeOfAlignOfExpr*>(this)->getArgumentExpr();
+ return const_cast<UnaryExprOrTypeTraitExpr*>(this)->getArgumentExpr();
}
void setArgument(Expr *E) { Argument.Ex = E; isType = false; }
@@ -1638,9 +1689,9 @@ public:
}
static bool classof(const Stmt *T) {
- return T->getStmtClass() == SizeOfAlignOfExprClass;
+ return T->getStmtClass() == UnaryExprOrTypeTraitExprClass;
}
- static bool classof(const SizeOfAlignOfExpr *) { return true; }
+ static bool classof(const UnaryExprOrTypeTraitExpr *) { return true; }
// Iterators
child_range children();
@@ -1862,7 +1913,13 @@ public:
///
class MemberExpr : public Expr {
/// Extra data stored in some member expressions.
- struct MemberNameQualifier : public NameQualifier {
+ struct MemberNameQualifier {
+ /// \brief The nested-name-specifier that qualifies the name, including
+ /// source-location information.
+ NestedNameSpecifierLoc QualifierLoc;
+
+ /// \brief The DeclAccessPair through which the MemberDecl was found due to
+ /// name qualifiers.
DeclAccessPair FoundDecl;
};
@@ -1936,7 +1993,7 @@ public:
HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {}
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
- NestedNameSpecifier *qual, SourceRange qualrange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *memberdecl, DeclAccessPair founddecl,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *targs,
@@ -1965,16 +2022,6 @@ public:
/// x->Base::foo.
bool hasQualifier() const { return getQualifier() != 0; }
- /// \brief If the member name was qualified, retrieves the source range of
- /// the nested-name-specifier that precedes the member name. Otherwise,
- /// returns an empty source range.
- SourceRange getQualifierRange() const {
- if (!HasQualifierOrFoundDecl)
- return SourceRange();
-
- return getMemberQualifier()->Range;
- }
-
/// \brief If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name. Otherwise, returns
/// NULL.
@@ -1982,7 +2029,17 @@ public:
if (!HasQualifierOrFoundDecl)
return 0;
- return getMemberQualifier()->NNS;
+ return getMemberQualifier()->QualifierLoc.getNestedNameSpecifier();
+ }
+
+ /// \brief If the member name was qualified, retrieves the
+ /// nested-name-specifier that precedes the member name, with source-location
+ /// information.
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ if (!hasQualifier())
+ return NestedNameSpecifierLoc();
+
+ return getMemberQualifier()->QualifierLoc;
}
/// \brief Determines whether this member expression actually had a C++
@@ -2075,20 +2132,15 @@ public:
SourceLocation getMemberLoc() const { return MemberLoc; }
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
- SourceRange getSourceRange() const {
- // If we have an implicit base (like a C++ implicit this),
- // make sure not to return its location
- SourceLocation EndLoc = (HasExplicitTemplateArgumentList)
- ? getRAngleLoc() : getMemberNameInfo().getEndLoc();
-
- SourceLocation BaseLoc = getBase()->getLocStart();
- if (BaseLoc.isInvalid())
- return SourceRange(MemberLoc, EndLoc);
- return SourceRange(BaseLoc, EndLoc);
- }
-
+ SourceRange getSourceRange() const;
+
SourceLocation getExprLoc() const { return MemberLoc; }
+ /// \brief Determine whether the base of this explicit is implicit.
+ bool isImplicitAccess() const {
+ return getBase() && getBase()->isImplicitCXXThis();
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == MemberExprClass;
}
@@ -2234,6 +2286,12 @@ private:
}
CXXBaseSpecifier **path_buffer();
+ void setBasePathSize(unsigned basePathSize) {
+ CastExprBits.BasePathSize = basePathSize;
+ assert(CastExprBits.BasePathSize == basePathSize &&
+ "basePathSize doesn't fit in bits of CastExprBits.BasePathSize!");
+ }
+
protected:
CastExpr(StmtClass SC, QualType ty, ExprValueKind VK,
const CastKind kind, Expr *op, unsigned BasePathSize) :
@@ -2249,14 +2307,14 @@ protected:
Op(op) {
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
CastExprBits.Kind = kind;
- CastExprBits.BasePathSize = BasePathSize;
+ setBasePathSize(BasePathSize);
CheckCastConsistency();
}
/// \brief Construct an empty cast.
CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize)
: Expr(SC, Empty) {
- CastExprBits.BasePathSize = BasePathSize;
+ setBasePathSize(BasePathSize);
}
public:
@@ -3173,9 +3231,14 @@ class InitListExpr : public Expr {
/// written in the source code.
InitListExpr *SyntacticForm;
- /// If this initializer list initializes a union, specifies which
- /// field within the union will be initialized.
- FieldDecl *UnionFieldInit;
+ /// \brief Either:
+ /// If this initializer list initializes an array with more elements than
+ /// there are initializers in the list, specifies an expression to be used
+ /// for value initialization of the rest of the elements.
+ /// Or
+ /// If this initializer list initializes a union, specifies which
+ /// field within the union will be initialized.
+ llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
/// Whether this initializer list originally had a GNU array-range
/// designator in it. This is a temporary marker used by CodeGen.
@@ -3227,17 +3290,29 @@ public:
///
/// When @p Init is out of range for this initializer list, the
/// initializer list will be extended with NULL expressions to
- /// accomodate the new entry.
+ /// accommodate the new entry.
Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr);
+ /// \brief If this initializer list initializes an array with more elements
+ /// than there are initializers in the list, specifies an expression to be
+ /// used for value initialization of the rest of the elements.
+ Expr *getArrayFiller() {
+ return ArrayFillerOrUnionFieldInit.dyn_cast<Expr *>();
+ }
+ void setArrayFiller(Expr *filler);
+
/// \brief If this initializes a union, specifies which field in the
/// union to initialize.
///
/// Typically, this field is the first named field within the
/// union. However, a designated initializer can specify the
/// initialization of a different field within the union.
- FieldDecl *getInitializedFieldInUnion() { return UnionFieldInit; }
- void setInitializedFieldInUnion(FieldDecl *FD) { UnionFieldInit = FD; }
+ FieldDecl *getInitializedFieldInUnion() {
+ return ArrayFillerOrUnionFieldInit.dyn_cast<FieldDecl *>();
+ }
+ void setInitializedFieldInUnion(FieldDecl *FD) {
+ ArrayFillerOrUnionFieldInit = FD;
+ }
// Explicit InitListExpr's originate from source code (and have valid source
// locations). Implicit InitListExpr's are created by the semantic analyzer.
@@ -3288,6 +3363,9 @@ public:
const_reverse_iterator rbegin() const { return InitExprs.rbegin(); }
reverse_iterator rend() { return InitExprs.rend(); }
const_reverse_iterator rend() const { return InitExprs.rend(); }
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
};
/// @brief Represents a C99 designated initializer expression.
@@ -3492,6 +3570,12 @@ public:
else
return getLBracketLoc();
}
+ SourceLocation getEndLocation() const {
+ return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc();
+ }
+ SourceRange getSourceRange() const {
+ return SourceRange(getStartLocation(), getEndLocation());
+ }
};
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
@@ -3574,6 +3658,8 @@ public:
void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First,
const Designator *Last);
+ SourceRange getDesignatorsSourceRange() const;
+
SourceRange getSourceRange() const;
static bool classof(const Stmt *T) {
@@ -3667,6 +3753,118 @@ public:
};
+/// \brief Represents a C1X generic selection.
+///
+/// A generic selection (C1X 6.5.1.1) contains an unevaluated controlling
+/// expression, followed by one or more generic associations. Each generic
+/// association specifies a type name and an expression, or "default" and an
+/// expression (in which case it is known as a default generic association).
+/// The type and value of the generic selection are identical to those of its
+/// result expression, which is defined as the expression in the generic
+/// association with a type name that is compatible with the type of the
+/// controlling expression, or the expression in the default generic association
+/// if no types are compatible. For example:
+///
+/// @code
+/// _Generic(X, double: 1, float: 2, default: 3)
+/// @endcode
+///
+/// The above expression evaluates to 1 if 1.0 is substituted for X, 2 if 1.0f
+/// or 3 if "hello".
+///
+/// As an extension, generic selections are allowed in C++, where the following
+/// additional semantics apply:
+///
+/// Any generic selection whose controlling expression is type-dependent or
+/// which names a dependent type in its association list is result-dependent,
+/// which means that the choice of result expression is dependent.
+/// Result-dependent generic associations are both type- and value-dependent.
+class GenericSelectionExpr : public Expr {
+ enum { CONTROLLING, END_EXPR };
+ TypeSourceInfo **AssocTypes;
+ Stmt **SubExprs;
+ unsigned NumAssocs, ResultIndex;
+ SourceLocation GenericLoc, DefaultLoc, RParenLoc;
+
+public:
+ GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack,
+ unsigned ResultIndex);
+
+ /// This constructor is used in the result-dependent case.
+ GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack);
+
+ explicit GenericSelectionExpr(EmptyShell Empty)
+ : Expr(GenericSelectionExprClass, Empty) { }
+
+ unsigned getNumAssocs() const { return NumAssocs; }
+
+ SourceLocation getGenericLoc() const { return GenericLoc; }
+ SourceLocation getDefaultLoc() const { return DefaultLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+
+ const Expr *getAssocExpr(unsigned i) const {
+ return cast<Expr>(SubExprs[END_EXPR+i]);
+ }
+ Expr *getAssocExpr(unsigned i) { return cast<Expr>(SubExprs[END_EXPR+i]); }
+
+ const TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) const {
+ return AssocTypes[i];
+ }
+ TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) { return AssocTypes[i]; }
+
+ QualType getAssocType(unsigned i) const {
+ if (const TypeSourceInfo *TS = getAssocTypeSourceInfo(i))
+ return TS->getType();
+ else
+ return QualType();
+ }
+
+ const Expr *getControllingExpr() const {
+ return cast<Expr>(SubExprs[CONTROLLING]);
+ }
+ Expr *getControllingExpr() { return cast<Expr>(SubExprs[CONTROLLING]); }
+
+ /// Whether this generic selection is result-dependent.
+ bool isResultDependent() const { return ResultIndex == -1U; }
+
+ /// The zero-based index of the result expression's generic association in
+ /// the generic selection's association list. Defined only if the
+ /// generic selection is not result-dependent.
+ unsigned getResultIndex() const {
+ assert(!isResultDependent() && "Generic selection is result-dependent");
+ return ResultIndex;
+ }
+
+ /// The generic selection's result expression. Defined only if the
+ /// generic selection is not result-dependent.
+ const Expr *getResultExpr() const { return getAssocExpr(getResultIndex()); }
+ Expr *getResultExpr() { return getAssocExpr(getResultIndex()); }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(GenericLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == GenericSelectionExprClass;
+ }
+ static bool classof(const GenericSelectionExpr *) { return true; }
+
+ child_range children() {
+ return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
+ }
+
+ friend class ASTStmtReader;
+};
+
//===----------------------------------------------------------------------===//
// Clang Extensions
//===----------------------------------------------------------------------===//
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 225db3c11fd0..a97057973745 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_EXPRCXX_H
#include "clang/Basic/TypeTraits.h"
+#include "clang/Basic/ExpressionTraits.h"
#include "clang/AST/Expr.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/AST/TemplateBase.h"
@@ -99,7 +100,10 @@ public:
/// getImplicitObjectArgument - Retrieves the implicit object
/// argument for the member call. For example, in "x.f(5)", this
/// operation would return "x".
- Expr *getImplicitObjectArgument();
+ Expr *getImplicitObjectArgument() const;
+
+ /// Retrieves the declaration of the called method.
+ CXXMethodDecl *getMethodDecl() const;
/// getRecordDecl - Retrieves the CXXRecordDecl for the underlying type of
/// the implicit object argument. Note that this is may not be the same
@@ -250,6 +254,8 @@ public:
static CXXDynamicCastExpr *CreateEmpty(ASTContext &Context,
unsigned pathSize);
+ bool isAlwaysNull() const;
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDynamicCastExprClass;
}
@@ -774,7 +780,8 @@ public:
enum ConstructionKind {
CK_Complete,
CK_NonVirtualBase,
- CK_VirtualBase
+ CK_VirtualBase,
+ CK_Delegating
};
private:
@@ -1080,6 +1087,17 @@ public:
TypeSourceInfo *getAllocatedTypeSourceInfo() const {
return AllocatedTypeInfo;
}
+
+ /// \brief True if the allocation result needs to be null-checked.
+ /// C++0x [expr.new]p13:
+ /// If the allocation function returns null, initialization shall
+ /// not be done, the deallocation function shall not be called,
+ /// and the value of the new-expression shall be null.
+ /// An allocation function is not allowed to return null unless it
+ /// has a non-throwing exception-specification. The '03 rule is
+ /// identical except that the definition of a non-throwing
+ /// exception specification is just "is it throw()?".
+ bool shouldNullCheckAllocation(ASTContext &Ctx) const;
FunctionDecl *getOperatorNew() const { return OperatorNew; }
void setOperatorNew(FunctionDecl *D) { OperatorNew = D; }
@@ -1577,6 +1595,122 @@ public:
friend class ASTStmtReader;
};
+/// ArrayTypeTraitExpr - An Embarcadero array type trait, as used in the
+/// implementation of __array_rank and __array_extent.
+/// Example:
+/// __array_rank(int[10][20]) == 2
+/// __array_extent(int, 1) == 20
+class ArrayTypeTraitExpr : public Expr {
+ /// ATT - The trait. An ArrayTypeTrait enum in MSVC compat unsigned.
+ unsigned ATT : 2;
+
+ /// The value of the type trait. Unspecified if dependent.
+ uint64_t Value;
+
+ /// The array dimension being queried, or -1 if not used
+ Expr *Dimension;
+
+ /// Loc - The location of the type trait keyword.
+ SourceLocation Loc;
+
+ /// RParen - The location of the closing paren.
+ SourceLocation RParen;
+
+ /// The type being queried.
+ TypeSourceInfo *QueriedType;
+
+public:
+ ArrayTypeTraitExpr(SourceLocation loc, ArrayTypeTrait att,
+ TypeSourceInfo *queried, uint64_t value,
+ Expr *dimension, SourceLocation rparen, QualType ty)
+ : Expr(ArrayTypeTraitExprClass, ty, VK_RValue, OK_Ordinary,
+ false, queried->getType()->isDependentType(),
+ queried->getType()->containsUnexpandedParameterPack()),
+ ATT(att), Value(value), Dimension(dimension),
+ Loc(loc), RParen(rparen), QueriedType(queried) { }
+
+
+ explicit ArrayTypeTraitExpr(EmptyShell Empty)
+ : Expr(ArrayTypeTraitExprClass, Empty), ATT(0), Value(false),
+ QueriedType() { }
+
+ virtual ~ArrayTypeTraitExpr() { }
+
+ virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen); }
+
+ ArrayTypeTrait getTrait() const { return static_cast<ArrayTypeTrait>(ATT); }
+
+ QualType getQueriedType() const { return QueriedType->getType(); }
+
+ TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; }
+
+ uint64_t getValue() const { assert(!isTypeDependent()); return Value; }
+
+ Expr *getDimensionExpression() const { return Dimension; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ArrayTypeTraitExprClass;
+ }
+ static bool classof(const ArrayTypeTraitExpr *) { return true; }
+
+ // Iterators
+ child_range children() { return child_range(); }
+
+ friend class ASTStmtReader;
+};
+
+/// ExpressionTraitExpr - An expression trait intrinsic
+/// Example:
+/// __is_lvalue_expr(std::cout) == true
+/// __is_lvalue_expr(1) == false
+class ExpressionTraitExpr : public Expr {
+ /// ET - The trait. A ExpressionTrait enum in MSVC compat unsigned.
+ unsigned ET : 31;
+ /// The value of the type trait. Unspecified if dependent.
+ bool Value : 1;
+
+ /// Loc - The location of the type trait keyword.
+ SourceLocation Loc;
+
+ /// RParen - The location of the closing paren.
+ SourceLocation RParen;
+
+ Expr* QueriedExpression;
+public:
+ ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et,
+ Expr *queried, bool value,
+ SourceLocation rparen, QualType resultType)
+ : Expr(ExpressionTraitExprClass, resultType, VK_RValue, OK_Ordinary,
+ false, // Not type-dependent
+ // Value-dependent if the argument is type-dependent.
+ queried->isTypeDependent(),
+ queried->containsUnexpandedParameterPack()),
+ ET(et), Value(value), Loc(loc), RParen(rparen), QueriedExpression(queried) { }
+
+ explicit ExpressionTraitExpr(EmptyShell Empty)
+ : Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false),
+ QueriedExpression() { }
+
+ SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
+
+ ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); }
+
+ Expr *getQueriedExpression() const { return QueriedExpression; }
+
+ bool getValue() const { return Value; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ExpressionTraitExprClass;
+ }
+ static bool classof(const ExpressionTraitExpr *) { return true; }
+
+ // Iterators
+ child_range children() { return child_range(); }
+
+ friend class ASTStmtReader;
+};
+
+
/// \brief A reference to an overloaded function set, either an
/// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr.
class OverloadExpr : public Expr {
@@ -1590,18 +1724,15 @@ class OverloadExpr : public Expr {
/// The common name of these declarations.
DeclarationNameInfo NameInfo;
- /// The scope specifier, if any.
- NestedNameSpecifier *Qualifier;
-
- /// The source range of the scope specifier.
- SourceRange QualifierRange;
+ /// \brief The nested-name-specifier that qualifies the name, if any.
+ NestedNameSpecifierLoc QualifierLoc;
protected:
/// True if the name was a template-id.
bool HasExplicitTemplateArgs;
OverloadExpr(StmtClass K, ASTContext &C,
- NestedNameSpecifier *Qualifier, SourceRange QRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
@@ -1610,7 +1741,7 @@ protected:
OverloadExpr(StmtClass K, EmptyShell Empty)
: Expr(K, Empty), Results(0), NumResults(0),
- Qualifier(0), HasExplicitTemplateArgs(false) { }
+ QualifierLoc(), HasExplicitTemplateArgs(false) { }
void initializeResults(ASTContext &C,
UnresolvedSetIterator Begin,
@@ -1665,23 +1796,21 @@ public:
/// Gets the full name info.
const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
- void setNameInfo(const DeclarationNameInfo &N) { NameInfo = N; }
/// Gets the name looked up.
DeclarationName getName() const { return NameInfo.getName(); }
- void setName(DeclarationName N) { NameInfo.setName(N); }
/// Gets the location of the name.
SourceLocation getNameLoc() const { return NameInfo.getLoc(); }
- void setNameLoc(SourceLocation Loc) { NameInfo.setLoc(Loc); }
/// Fetches the nested-name qualifier, if one was given.
- NestedNameSpecifier *getQualifier() const { return Qualifier; }
- void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; }
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
+ }
- /// Fetches the range of the nested-name qualifier.
- SourceRange getQualifierRange() const { return QualifierRange; }
- void setQualifierRange(SourceRange R) { QualifierRange = R; }
+ /// Fetches the nested-name qualifier with source-location information, if
+ /// one was given.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// \brief Determines whether this expression had an explicit
/// template argument list, e.g. f<int>.
@@ -1727,6 +1856,10 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// call.
bool RequiresADL;
+ /// True if namespace ::std should be considered an associated namespace
+ /// for the purposes of argument-dependent lookup. See C++0x [stmt.ranged]p1.
+ bool StdIsAssociatedNamespace;
+
/// True if these lookup results are overloaded. This is pretty
/// trivially rederivable if we urgently need to kill this field.
bool Overloaded;
@@ -1740,39 +1873,46 @@ class UnresolvedLookupExpr : public OverloadExpr {
UnresolvedLookupExpr(ASTContext &C,
CXXRecordDecl *NamingClass,
- NestedNameSpecifier *Qualifier, SourceRange QRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool RequiresADL, bool Overloaded,
const TemplateArgumentListInfo *TemplateArgs,
- UnresolvedSetIterator Begin, UnresolvedSetIterator End)
- : OverloadExpr(UnresolvedLookupExprClass, C, Qualifier, QRange, NameInfo,
+ UnresolvedSetIterator Begin, UnresolvedSetIterator End,
+ bool StdIsAssociatedNamespace)
+ : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, NameInfo,
TemplateArgs, Begin, End),
- RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass)
+ RequiresADL(RequiresADL),
+ StdIsAssociatedNamespace(StdIsAssociatedNamespace),
+ Overloaded(Overloaded), NamingClass(NamingClass)
{}
UnresolvedLookupExpr(EmptyShell Empty)
: OverloadExpr(UnresolvedLookupExprClass, Empty),
- RequiresADL(false), Overloaded(false), NamingClass(0)
+ RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false),
+ NamingClass(0)
{}
+ friend class ASTStmtReader;
+
public:
static UnresolvedLookupExpr *Create(ASTContext &C,
CXXRecordDecl *NamingClass,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool ADL, bool Overloaded,
UnresolvedSetIterator Begin,
- UnresolvedSetIterator End) {
- return new(C) UnresolvedLookupExpr(C, NamingClass, Qualifier,
- QualifierRange, NameInfo, ADL,
- Overloaded, 0, Begin, End);
+ UnresolvedSetIterator End,
+ bool StdIsAssociatedNamespace = false) {
+ assert((ADL || !StdIsAssociatedNamespace) &&
+ "std considered associated namespace when not performing ADL");
+ return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
+ ADL, Overloaded, 0, Begin, End,
+ StdIsAssociatedNamespace);
}
static UnresolvedLookupExpr *Create(ASTContext &C,
CXXRecordDecl *NamingClass,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool ADL,
const TemplateArgumentListInfo &Args,
@@ -1786,17 +1926,18 @@ public:
/// True if this declaration should be extended by
/// argument-dependent lookup.
bool requiresADL() const { return RequiresADL; }
- void setRequiresADL(bool V) { RequiresADL = V; }
+
+ /// True if namespace ::std should be artificially added to the set of
+ /// associated namespaecs for argument-dependent lookup purposes.
+ bool isStdAssociatedNamespace() const { return StdIsAssociatedNamespace; }
/// True if this lookup is overloaded.
bool isOverloaded() const { return Overloaded; }
- void setOverloaded(bool V) { Overloaded = V; }
/// Gets the 'naming class' (in the sense of C++0x
/// [class.access.base]p5) of the lookup. This is the scope
/// that was looked in to find these results.
CXXRecordDecl *getNamingClass() const { return NamingClass; }
- void setNamingClass(CXXRecordDecl *D) { NamingClass = D; }
// Note that, inconsistently with the explicit-template-argument AST
// nodes, users are *forbidden* from calling these methods on objects
@@ -1845,8 +1986,10 @@ public:
SourceRange getSourceRange() const {
SourceRange Range(getNameInfo().getSourceRange());
- if (getQualifier()) Range.setBegin(getQualifierRange().getBegin());
- if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc());
+ if (getQualifierLoc())
+ Range.setBegin(getQualifierLoc().getBeginLoc());
+ if (hasExplicitTemplateArgs())
+ Range.setEnd(getRAngleLoc());
return Range;
}
@@ -2186,16 +2329,13 @@ class CXXDependentScopeMemberExpr : public Expr {
SourceLocation OperatorLoc;
/// \brief The nested-name-specifier that precedes the member name, if any.
- NestedNameSpecifier *Qualifier;
-
- /// \brief The source range covering the nested name specifier.
- SourceRange QualifierRange;
+ NestedNameSpecifierLoc QualifierLoc;
/// \brief In a qualified member access expression such as t->Base::f, this
/// member stores the resolves of name lookup in the context of the member
/// access expression, to be used at instantiation time.
///
- /// FIXME: This member, along with the Qualifier and QualifierRange, could
+ /// FIXME: This member, along with the QualifierLoc, could
/// be stuck into a structure that is optionally allocated at the end of
/// the CXXDependentScopeMemberExpr, to save space in the common case.
NamedDecl *FirstQualifierFoundInScope;
@@ -2208,8 +2348,7 @@ class CXXDependentScopeMemberExpr : public Expr {
CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
@@ -2219,8 +2358,7 @@ public:
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo);
@@ -2228,8 +2366,7 @@ public:
Create(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
@@ -2241,7 +2378,7 @@ public:
/// \brief True if this is an implicit access, i.e. one in which the
/// member being accessed was not written in the source. The source
/// location of the operator is invalid in this case.
- bool isImplicitAccess() const { return Base == 0; }
+ bool isImplicitAccess() const;
/// \brief Retrieve the base object of this member expressions,
/// e.g., the \c x in \c x.m.
@@ -2249,30 +2386,27 @@ public:
assert(!isImplicitAccess());
return cast<Expr>(Base);
}
- void setBase(Expr *E) { Base = E; }
QualType getBaseType() const { return BaseType; }
- void setBaseType(QualType T) { BaseType = T; }
/// \brief Determine whether this member expression used the '->'
/// operator; otherwise, it used the '.' operator.
bool isArrow() const { return IsArrow; }
- void setArrow(bool A) { IsArrow = A; }
/// \brief Retrieve the location of the '->' or '.' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
- void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
/// \brief Retrieve the nested-name-specifier that qualifies the member
/// name.
- NestedNameSpecifier *getQualifier() const { return Qualifier; }
- void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; }
-
- /// \brief Retrieve the source range covering the nested-name-specifier
- /// that qualifies the member name.
- SourceRange getQualifierRange() const { return QualifierRange; }
- void setQualifierRange(SourceRange R) { QualifierRange = R; }
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
+ }
+ /// \brief Retrieve the nested-name-specifier that qualifies the member
+ /// name, with source location information.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+
+
/// \brief Retrieve the first part of the nested-name-specifier that was
/// found in the scope of the member access expression when the member access
/// was initially parsed.
@@ -2287,26 +2421,20 @@ public:
NamedDecl *getFirstQualifierFoundInScope() const {
return FirstQualifierFoundInScope;
}
- void setFirstQualifierFoundInScope(NamedDecl *D) {
- FirstQualifierFoundInScope = D;
- }
/// \brief Retrieve the name of the member that this expression
/// refers to.
const DeclarationNameInfo &getMemberNameInfo() const {
return MemberNameInfo;
}
- void setMemberNameInfo(const DeclarationNameInfo &N) { MemberNameInfo = N; }
/// \brief Retrieve the name of the member that this expression
/// refers to.
DeclarationName getMember() const { return MemberNameInfo.getName(); }
- void setMember(DeclarationName N) { MemberNameInfo.setName(N); }
// \brief Retrieve the location of the name of the member that this
// expression refers to.
SourceLocation getMemberLoc() const { return MemberNameInfo.getLoc(); }
- void setMemberLoc(SourceLocation L) { MemberNameInfo.setLoc(L); }
/// \brief Determines whether this member expression actually had a C++
/// template argument list explicitly specified, e.g., x.f<int>.
@@ -2376,7 +2504,7 @@ public:
if (!isImplicitAccess())
Range.setBegin(Base->getSourceRange().getBegin());
else if (getQualifier())
- Range.setBegin(getQualifierRange().getBegin());
+ Range.setBegin(getQualifierLoc().getBeginLoc());
else
Range.setBegin(MemberNameInfo.getBeginLoc());
@@ -2438,8 +2566,7 @@ class UnresolvedMemberExpr : public OverloadExpr {
UnresolvedMemberExpr(ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
@@ -2448,13 +2575,14 @@ class UnresolvedMemberExpr : public OverloadExpr {
: OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false),
HasUnresolvedUsing(false), Base(0) { }
+ friend class ASTStmtReader;
+
public:
static UnresolvedMemberExpr *
Create(ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
@@ -2466,7 +2594,7 @@ public:
/// \brief True if this is an implicit access, i.e. one in which the
/// member being accessed was not written in the source. The source
/// location of the operator is invalid in this case.
- bool isImplicitAccess() const { return Base == 0; }
+ bool isImplicitAccess() const;
/// \brief Retrieve the base object of this member expressions,
/// e.g., the \c x in \c x.m.
@@ -2478,24 +2606,19 @@ public:
assert(!isImplicitAccess());
return cast<Expr>(Base);
}
- void setBase(Expr *E) { Base = E; }
QualType getBaseType() const { return BaseType; }
- void setBaseType(QualType T) { BaseType = T; }
/// \brief Determine whether the lookup results contain an unresolved using
/// declaration.
bool hasUnresolvedUsing() const { return HasUnresolvedUsing; }
- void setHasUnresolvedUsing(bool V) { HasUnresolvedUsing = V; }
/// \brief Determine whether this member expression used the '->'
/// operator; otherwise, it used the '.' operator.
bool isArrow() const { return IsArrow; }
- void setArrow(bool A) { IsArrow = A; }
/// \brief Retrieve the location of the '->' or '.' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
- void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
/// \brief Retrieves the naming class of this lookup.
CXXRecordDecl *getNamingClass() const;
@@ -2503,17 +2626,14 @@ public:
/// \brief Retrieve the full name info for the member that this expression
/// refers to.
const DeclarationNameInfo &getMemberNameInfo() const { return getNameInfo(); }
- void setMemberNameInfo(const DeclarationNameInfo &N) { setNameInfo(N); }
/// \brief Retrieve the name of the member that this expression
/// refers to.
DeclarationName getMemberName() const { return getName(); }
- void setMemberName(DeclarationName N) { setName(N); }
// \brief Retrieve the location of the name of the member that this
// expression refers to.
SourceLocation getMemberLoc() const { return getNameLoc(); }
- void setMemberLoc(SourceLocation L) { setNameLoc(L); }
/// \brief Retrieve the explicit template argument list that followed the
/// member template name.
@@ -2570,8 +2690,8 @@ public:
SourceRange Range = getMemberNameInfo().getSourceRange();
if (!isImplicitAccess())
Range.setBegin(Base->getSourceRange().getBegin());
- else if (getQualifier())
- Range.setBegin(getQualifierRange().getBegin());
+ else if (getQualifierLoc())
+ Range.setBegin(getQualifierLoc().getBeginLoc());
if (hasExplicitTemplateArgs())
Range.setEnd(getRAngleLoc());
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 285efb757bbb..8163923d62d1 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -337,6 +337,39 @@ public:
QualType getSuperReceiverType() const {
return QualType(Receiver.get<const Type*>(), 0);
}
+ QualType getGetterResultType() const {
+ QualType ResultType;
+ if (isExplicitProperty()) {
+ const ObjCPropertyDecl *PDecl = getExplicitProperty();
+ if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
+ ResultType = Getter->getResultType();
+ else
+ ResultType = getType();
+ } else {
+ const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
+ ResultType = Getter->getResultType(); // with reference!
+ }
+ return ResultType;
+ }
+
+ QualType getSetterArgType() const {
+ QualType ArgType;
+ if (isImplicitProperty()) {
+ const ObjCMethodDecl *Setter = getImplicitPropertySetter();
+ ObjCMethodDecl::param_iterator P = Setter->param_begin();
+ ArgType = (*P)->getType();
+ } else {
+ if (ObjCPropertyDecl *PDecl = getExplicitProperty())
+ if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) {
+ ObjCMethodDecl::param_iterator P = Setter->param_begin();
+ ArgType = (*P)->getType();
+ }
+ if (ArgType.isNull())
+ ArgType = getType();
+ }
+ return ArgType;
+ }
+
ObjCInterfaceDecl *getClassReceiver() const {
return Receiver.get<ObjCInterfaceDecl*>();
}
@@ -741,6 +774,11 @@ public:
SelectorOrMethod = reinterpret_cast<uintptr_t>(MD);
}
+ ObjCMethodFamily getMethodFamily() const {
+ if (HasMethod) return getMethodDecl()->getMethodFamily();
+ return getSelector().getMethodFamily();
+ }
+
/// \brief Return the number of actual arguments in this message,
/// not counting the receiver.
unsigned getNumArgs() const { return NumArgs; }
@@ -808,7 +846,7 @@ public:
};
/// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type.
-/// (similiar in spirit to MemberExpr).
+/// (similar in spirit to MemberExpr).
class ObjCIsaExpr : public Expr {
/// Base - the expression for the base object pointer.
Stmt *Base;
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 7b23766b0714..6db233641220 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines the ExternalASTSource interface, which enables
-// construction of AST nodes from some external source.x
+// construction of AST nodes from some external source.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
@@ -16,7 +16,6 @@
#include "clang/AST/DeclBase.h"
#include <cassert>
-#include <vector>
namespace llvm {
template <class T> class SmallVectorImpl;
@@ -26,9 +25,6 @@ namespace clang {
class ASTConsumer;
class CXXBaseSpecifier;
-class Decl;
-class DeclContext;
-class DeclContextLookupResult;
class DeclarationName;
class ExternalSemaSource; // layering violation required for downcasting
class NamedDecl;
@@ -74,17 +70,23 @@ public:
///
/// This method only needs to be implemented if the AST source ever
/// passes back decl sets as VisibleDeclaration objects.
- virtual Decl *GetExternalDecl(uint32_t ID) = 0;
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual Decl *GetExternalDecl(uint32_t ID);
/// \brief Resolve a selector ID into a selector.
///
/// This operation only needs to be implemented if the AST source
/// returns non-zero for GetNumKnownSelectors().
- virtual Selector GetExternalSelector(uint32_t ID) = 0;
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual Selector GetExternalSelector(uint32_t ID);
/// \brief Returns the number of selectors known to the external AST
/// source.
- virtual uint32_t GetNumExternalSelectors() = 0;
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual uint32_t GetNumExternalSelectors();
/// \brief Resolve the offset of a statement in the decl stream into
/// a statement.
@@ -92,21 +94,26 @@ public:
/// This operation is meant to be used via a LazyOffsetPtr. It only
/// needs to be implemented if the AST source uses methods like
/// FunctionDecl::setLazyBody when building decls.
- virtual Stmt *GetExternalDeclStmt(uint64_t Offset) = 0;
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
/// \brief Resolve the offset of a set of C++ base specifiers in the decl
/// stream into an array of specifiers.
- virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) = 0;
-
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
+
/// \brief Finds all declarations with the given name in the
/// given context.
///
/// Generally the final step of this method is either to call
/// SetExternalVisibleDeclsForName or to recursively call lookup on
/// the DeclContext after calling SetExternalVisibleDecls.
+ ///
+ /// The default implementation of this method is a no-op.
virtual DeclContextLookupResult
- FindExternalVisibleDeclsByName(const DeclContext *DC,
- DeclarationName Name) = 0;
+ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
/// \brief Deserialize all the visible declarations from external storage.
///
@@ -114,7 +121,9 @@ public:
/// may not have a complete name lookup table. This function deserializes
/// the rest of visible declarations from the external storage and completes
/// the name lookup table of the DeclContext.
- virtual void MaterializeVisibleDecls(const DeclContext *DC) = 0;
+ ///
+ /// The default implementation of this method is a no-op.
+ virtual void MaterializeVisibleDecls(const DeclContext *DC);
/// \brief Finds all declarations lexically contained within the given
/// DeclContext, after applying an optional filter predicate.
@@ -124,9 +133,11 @@ public:
/// are returned.
///
/// \return true if an error occurred
+ ///
+ /// The default implementation of this method is a no-op.
virtual bool FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
- llvm::SmallVectorImpl<Decl*> &Result) = 0;
+ llvm::SmallVectorImpl<Decl*> &Result);
/// \brief Finds all declarations lexically contained within the given
/// DeclContext.
@@ -154,7 +165,7 @@ public:
/// set on the ObjCInterfaceDecl via the function
/// \c ObjCInterfaceDecl::setExternallyCompleted().
virtual void CompleteType(ObjCInterfaceDecl *Class) { }
-
+
/// \brief Notify ExternalASTSource that we started deserialization of
/// a decl or type so until FinishedDeserializing is called there may be
/// decls that are initializing. Must be paired with FinishedDeserializing.
@@ -179,6 +190,28 @@ public:
///
/// The default implementation of this method is a no-op.
virtual void PrintStats();
+
+ //===--------------------------------------------------------------------===//
+ // Queries for performance analysis.
+ //===--------------------------------------------------------------------===//
+
+ struct MemoryBufferSizes {
+ size_t malloc_bytes;
+ size_t mmap_bytes;
+
+ MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
+ : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
+ };
+
+ /// Return the amount of memory used by memory buffers, breaking down
+ /// by heap-backed versus mmap'ed memory.
+ MemoryBufferSizes getMemoryBufferSizes() const {
+ MemoryBufferSizes sizes(0, 0);
+ getMemoryBufferSizes(sizes);
+ return sizes;
+ }
+
+ virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const = 0;
protected:
static DeclContextLookupResult
@@ -270,7 +303,7 @@ typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
&ExternalASTSource::GetExternalCXXBaseSpecifiers>
LazyCXXBaseSpecifiersPtr;
-
+
} // end namespace clang
#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index 024bf402894b..c21c76b006ff 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -312,6 +312,146 @@ public:
}
};
+/// \brief Class that aids in the construction of nested-name-specifiers along
+/// with source-location information for all of the components of the
+/// nested-name-specifier.
+class NestedNameSpecifierLocBuilder {
+ /// \brief The current representation of the nested-name-specifier we're
+ /// building.
+ NestedNameSpecifier *Representation;
+
+ /// \brief Buffer used to store source-location information for the
+ /// nested-name-specifier.
+ ///
+ /// Note that we explicitly manage the buffer (rather than using a
+ /// SmallVector) because \c Declarator expects it to be possible to memcpy()
+ /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
+ char *Buffer;
+
+ /// \brief The size of the buffer used to store source-location information
+ /// for the nested-name-specifier.
+ unsigned BufferSize;
+
+ /// \brief The capacity of the buffer used to store source-location
+ /// information for the nested-name-specifier.
+ unsigned BufferCapacity;
+
+public:
+ NestedNameSpecifierLocBuilder();
+
+ NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
+
+ NestedNameSpecifierLocBuilder &
+ operator=(const NestedNameSpecifierLocBuilder &Other);
+
+ ~NestedNameSpecifierLocBuilder();
+
+ /// \brief Retrieve the representation of the nested-name-specifier.
+ NestedNameSpecifier *getRepresentation() const { return Representation; }
+
+ /// \brief Extend the current nested-name-specifier by another
+ /// nested-name-specifier component of the form 'type::'.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param TemplateKWLoc The location of the 'template' keyword, if present.
+ ///
+ /// \param TL The TypeLoc that describes the type preceding the '::'.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL,
+ SourceLocation ColonColonLoc);
+
+ /// \brief Extend the current nested-name-specifier by another
+ /// nested-name-specifier component of the form 'identifier::'.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param Identifier The identifier.
+ ///
+ /// \param IdentifierLoc The location of the identifier.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void Extend(ASTContext &Context, IdentifierInfo *Identifier,
+ SourceLocation IdentifierLoc, SourceLocation ColonColonLoc);
+
+ /// \brief Extend the current nested-name-specifier by another
+ /// nested-name-specifier component of the form 'namespace::'.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param Namespace The namespace.
+ ///
+ /// \param NamespaceLoc The location of the namespace name.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void Extend(ASTContext &Context, NamespaceDecl *Namespace,
+ SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
+
+ /// \brief Extend the current nested-name-specifier by another
+ /// nested-name-specifier component of the form 'namespace-alias::'.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param Alias The namespace alias.
+ ///
+ /// \param AliasLoc The location of the namespace alias
+ /// name.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
+ SourceLocation AliasLoc, SourceLocation ColonColonLoc);
+
+ /// \brief Turn this (empty) nested-name-specifier into the global
+ /// nested-name-specifier '::'.
+ void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
+
+ /// \brief Make a new nested-name-specifier from incomplete source-location
+ /// information.
+ ///
+ /// This routine should be used very, very rarely, in cases where we
+ /// need to synthesize a nested-name-specifier. Most code should instead use
+ /// \c Adopt() with a proper \c NestedNameSpecifierLoc.
+ void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
+ SourceRange R);
+
+ /// \brief Adopt an existing nested-name-specifier (with source-range
+ /// information).
+ void Adopt(NestedNameSpecifierLoc Other);
+
+ /// \brief Retrieve the source range covered by this nested-name-specifier.
+ SourceRange getSourceRange() const {
+ return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
+ }
+
+ /// \brief Retrieve a nested-name-specifier with location information,
+ /// copied into the given AST context.
+ ///
+ /// \param Context The context into which this nested-name-specifier will be
+ /// copied.
+ NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const;
+
+ /// \brief Clear out this builder, and prepare it to build another
+ /// nested-name-specifier with source-location information.
+ void Clear() {
+ Representation = 0;
+ BufferSize = 0;
+ }
+
+ /// \brief Retrieve the underlying buffer.
+ ///
+ /// \returns A pair containing a pointer to the buffer of source-location
+ /// data and the size of the source-location data that resides in that
+ /// buffer.
+ std::pair<char *, unsigned> getBuffer() const {
+ return std::make_pair(Buffer, BufferSize);
+ }
+};
+
/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers
/// into a diagnostic with <<.
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index a59c302ffc1e..cf5fadbd1850 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -38,7 +38,8 @@ struct PrintingPolicy {
/// \brief Create a default printing policy for C.
PrintingPolicy(const LangOptions &LO)
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
- SuppressTag(false), SuppressScope(false),
+ SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
+ SuppressInitializers(false),
Dump(false), ConstantArraySizeAsWritten(false),
AnonymousTagLocations(true) { }
@@ -64,6 +65,16 @@ struct PrintingPolicy {
/// "const int" type specifier and instead only print the "*y".
bool SuppressSpecifiers : 1;
+ /// \brief Whether type printing should skip printing the tag keyword.
+ ///
+ /// This is used when printing the inner type of elaborated types,
+ /// (as the tag keyword is part of the elaborated type):
+ ///
+ /// \code
+ /// struct Geometry::Point;
+ /// \endcode
+ bool SuppressTagKeyword : 1;
+
/// \brief Whether type printing should skip printing the actual tag type.
///
/// This is used when the caller needs to print a tag definition in front
@@ -77,6 +88,19 @@ struct PrintingPolicy {
/// \brief Suppresses printing of scope specifiers.
bool SuppressScope : 1;
+ /// \brief Suppress printing of variable initializers.
+ ///
+ /// This flag is used when printing the loop variable in a for-range
+ /// statement. For example, given:
+ ///
+ /// \code
+ /// for (auto x : coll)
+ /// \endcode
+ ///
+ /// SuppressInitializers will be true when printing "auto x", so that the
+ /// internal initializer constructed for x will not be printed.
+ bool SuppressInitializers : 1;
+
/// \brief True when we are "dumping" rather than "pretty-printing",
/// where dumping involves printing the internal details of the AST
/// and pretty-printing involves printing something similar to
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index e85b6dcd279a..930d19373cdc 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -600,12 +600,15 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
// FIXME: how can TSI ever be NULL?
if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo())
return getDerived().TraverseTypeLoc(TSI->getTypeLoc());
- else
- return true;
+ else
+ return getDerived().TraverseType(Arg.getAsType());
}
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
+ if (ArgLoc.getTemplateQualifierLoc())
+ TRY_TO(getDerived().TraverseNestedNameSpecifierLoc(
+ ArgLoc.getTemplateQualifierLoc()));
return getDerived().TraverseTemplateName(
Arg.getAsTemplateOrTemplatePattern());
@@ -933,7 +936,11 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
const FunctionProtoType *T = TL.getTypePtr();
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
- TRY_TO(TraverseDecl(TL.getArg(I)));
+ if (TL.getArg(I)) {
+ TRY_TO(TraverseDecl(TL.getArg(I)));
+ } else if (I < T->getNumArgs()) {
+ TRY_TO(TraverseType(T->getArgType(I)));
+ }
}
for (FunctionProtoType::exception_iterator E = T->exception_begin(),
@@ -987,21 +994,22 @@ DEF_TRAVERSE_TYPELOC(AttributedType, {
TRY_TO(TraverseTypeLoc(TL.getModifiedLoc()));
})
-// FIXME: use the sourceloc on qualifier?
DEF_TRAVERSE_TYPELOC(ElaboratedType, {
- if (TL.getTypePtr()->getQualifier()) {
- TRY_TO(TraverseNestedNameSpecifier(TL.getTypePtr()->getQualifier()));
+ if (TL.getQualifierLoc()) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
}
TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc()));
})
-// FIXME: use the sourceloc on qualifier?
DEF_TRAVERSE_TYPELOC(DependentNameType, {
- TRY_TO(TraverseNestedNameSpecifier(TL.getTypePtr()->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
})
DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
- TRY_TO(TraverseNestedNameSpecifier(TL.getTypePtr()->getQualifier()));
+ if (TL.getQualifierLoc()) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+ }
+
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
}
@@ -1041,7 +1049,9 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) {
for (DeclContext::decl_iterator Child = DC->decls_begin(),
ChildEnd = DC->decls_end();
Child != ChildEnd; ++Child) {
- TRY_TO(TraverseDecl(*Child));
+ // BlockDecls are traversed through BlockExprs.
+ if (!isa<BlockDecl>(*Child))
+ TRY_TO(TraverseDecl(*Child));
}
return true;
@@ -1060,10 +1070,12 @@ bool RecursiveASTVisitor<Derived>::Traverse##DECL (DECL *D) { \
DEF_TRAVERSE_DECL(AccessSpecDecl, { })
DEF_TRAVERSE_DECL(BlockDecl, {
- // We don't traverse nodes in param_begin()/param_end(), as they
- // appear in decls_begin()/decls_end() and thus are handled by the
- // DEF_TRAVERSE_DECL macro already.
+ TRY_TO(TraverseTypeLoc(D->getSignatureAsWritten()->getTypeLoc()));
TRY_TO(TraverseStmt(D->getBody()));
+ // This return statement makes sure the traversal of nodes in
+ // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
+ // is skipped - don't remove it.
+ return true;
})
DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
@@ -1164,9 +1176,17 @@ DEF_TRAVERSE_DECL(ObjCProtocolDecl, {
})
DEF_TRAVERSE_DECL(ObjCMethodDecl, {
- // We don't traverse nodes in param_begin()/param_end(), as they
- // appear in decls_begin()/decls_end() and thus are handled.
- TRY_TO(TraverseStmt(D->getBody()));
+ if (D->getResultTypeSourceInfo()) {
+ TRY_TO(TraverseTypeLoc(D->getResultTypeSourceInfo()->getTypeLoc()));
+ }
+ for (ObjCMethodDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ if (D->isThisDeclarationADefinition()) {
+ TRY_TO(TraverseStmt(D->getBody()));
+ }
+ return true;
})
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
@@ -1341,6 +1361,13 @@ DEF_TRAVERSE_DECL(TypedefDecl, {
// source.
})
+DEF_TRAVERSE_DECL(TypeAliasDecl, {
+ TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the type alias, not something that was written in the
+ // source.
+ })
+
DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
// A dependent using declaration which was marked with 'typename'.
// template<class T> class A : public B<T> { using typename B<T>::foo; };
@@ -1354,7 +1381,7 @@ DEF_TRAVERSE_DECL(EnumDecl, {
if (D->getTypeForDecl())
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
- TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
// The enumerators are already traversed by
// decls_begin()/decls_end().
})
@@ -1367,7 +1394,7 @@ bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(
// We shouldn't traverse D->getTypeForDecl(); it's a result of
// declaring the type, not something that was written in the source.
- TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
return true;
}
@@ -1464,9 +1491,11 @@ DEF_TRAVERSE_DECL(IndirectFieldDecl, {})
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) {
- TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
if (D->getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+ else
+ TRY_TO(TraverseType(D->getType()));
return true;
}
@@ -1492,7 +1521,7 @@ DEF_TRAVERSE_DECL(ObjCIvarDecl, {
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
- TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
// If we're an explicit template specialization, iterate over the
// template args that were explicitly specified. If we were doing
@@ -1678,13 +1707,14 @@ DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { })
DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
+DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
DEF_TRAVERSE_STMT(ReturnStmt, { })
DEF_TRAVERSE_STMT(SwitchStmt, { })
DEF_TRAVERSE_STMT(WhileStmt, { })
DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
- TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (S->hasExplicitTemplateArgs()) {
TRY_TO(TraverseTemplateArgumentLocsHelper(
S->getTemplateArgs(), S->getNumTemplateArgs()));
@@ -1692,7 +1722,7 @@ DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
})
DEF_TRAVERSE_STMT(DeclRefExpr, {
- TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
TRY_TO(TraverseTemplateArgumentLocsHelper(
S->getTemplateArgs(), S->getNumTemplateArgs()));
})
@@ -1707,10 +1737,9 @@ DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
})
DEF_TRAVERSE_STMT(MemberExpr, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
TRY_TO(TraverseTemplateArgumentLocsHelper(
S->getTemplateArgs(), S->getNumTemplateArgs()));
- // FIXME: Should we be recursing on the qualifier?
- TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
})
DEF_TRAVERSE_STMT(ImplicitCastExpr, {
@@ -1759,6 +1788,22 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
return true;
}
+// GenericSelectionExpr is a special case because the types and expressions
+// are interleaved. We also need to watch out for null types (default
+// generic associations).
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::
+TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
+ TRY_TO(WalkUpFromGenericSelectionExpr(S));
+ TRY_TO(TraverseStmt(S->getControllingExpr()));
+ for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
+ if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i))
+ TRY_TO(TraverseTypeLoc(TS->getTypeLoc()));
+ TRY_TO(TraverseStmt(S->getAssocExpr(i)));
+ }
+ return true;
+}
+
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
// This is called for code like 'return T()' where T is a built-in
// (i.e. non-class) type.
@@ -1778,7 +1823,7 @@ DEF_TRAVERSE_STMT(OffsetOfExpr, {
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
})
-DEF_TRAVERSE_STMT(SizeOfAlignOfExpr, {
+DEF_TRAVERSE_STMT(UnaryExprOrTypeTraitExpr, {
// The child-iterator will pick up the arg if it's an expression,
// but not if it's a type.
if (S->isArgumentType())
@@ -1808,6 +1853,14 @@ DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, {
TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc()));
})
+DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
+ TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
+ })
+
+DEF_TRAVERSE_STMT(ExpressionTraitExpr, {
+ TRY_TO(TraverseStmt(S->getQueriedExpression()));
+ })
+
DEF_TRAVERSE_STMT(VAArgExpr, {
// The child-iterator will pick up the expression argument.
TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc()));
@@ -1834,7 +1887,10 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
DEF_TRAVERSE_STMT(AddrLabelExpr, { })
DEF_TRAVERSE_STMT(ArraySubscriptExpr, { })
DEF_TRAVERSE_STMT(BlockDeclRefExpr, { })
-DEF_TRAVERSE_STMT(BlockExpr, { })
+DEF_TRAVERSE_STMT(BlockExpr, {
+ TRY_TO(TraverseDecl(S->getBlockDecl()));
+ return true; // no child statements to loop through.
+})
DEF_TRAVERSE_STMT(ChooseExpr, { })
DEF_TRAVERSE_STMT(CompoundLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
@@ -1869,7 +1925,7 @@ DEF_TRAVERSE_STMT(PredefinedExpr, { })
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
DEF_TRAVERSE_STMT(StmtExpr, { })
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
- TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (S->hasExplicitTemplateArgs()) {
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
S->getNumTemplateArgs()));
@@ -1877,13 +1933,17 @@ DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
})
DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
- TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (S->hasExplicitTemplateArgs()) {
TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
S->getNumTemplateArgs()));
}
})
+DEF_TRAVERSE_STMT(SEHTryStmt, {})
+DEF_TRAVERSE_STMT(SEHExceptStmt, {})
+DEF_TRAVERSE_STMT(SEHFinallyStmt,{})
+
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
DEF_TRAVERSE_STMT(OpaqueValueExpr, { })
DEF_TRAVERSE_STMT(CUDAKernelCallExpr, { })
@@ -1921,7 +1981,7 @@ DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
// Candidates:
//
// http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html
-// http://clang.llvm.org/doxygen/classclang_1_1SizeOfAlignOfExpr.html
+// http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html
// http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html
// Every class that has getQualifier.
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index d1f7d667f33d..695fb0403ead 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -158,6 +158,16 @@ protected:
};
enum { NumExprBits = 15 };
+ class DeclRefExprBitfields {
+ friend class DeclRefExpr;
+ friend class ASTStmtReader; // deserialization
+ unsigned : NumExprBits;
+
+ unsigned HasQualifier : 1;
+ unsigned HasExplicitTemplateArgs : 1;
+ unsigned HasFoundDecl : 1;
+ };
+
class CastExprBitfields {
friend class CastExpr;
unsigned : NumExprBits;
@@ -180,6 +190,7 @@ protected:
StmtBitfields StmtBits;
CompoundStmtBitfields CompoundStmtBits;
ExprBitfields ExprBits;
+ DeclRefExprBitfields DeclRefExprBits;
CastExprBitfields CastExprBits;
CallExprBitfields CallExprBits;
};
@@ -383,14 +394,15 @@ public:
class NullStmt : public Stmt {
SourceLocation SemiLoc;
- /// \brief Whether the null statement was preceded by an empty macro, e.g:
+ /// \brief If the null statement was preceded by an empty macro this is
+ /// its instantiation source location, e.g:
/// @code
/// #define CALL(x)
/// CALL(0);
/// @endcode
- bool LeadingEmptyMacro;
+ SourceLocation LeadingEmptyMacro;
public:
- NullStmt(SourceLocation L, bool LeadingEmptyMacro = false)
+ NullStmt(SourceLocation L, SourceLocation LeadingEmptyMacro =SourceLocation())
: Stmt(NullStmtClass), SemiLoc(L), LeadingEmptyMacro(LeadingEmptyMacro) {}
/// \brief Build an empty null statement.
@@ -399,7 +411,8 @@ public:
SourceLocation getSemiLoc() const { return SemiLoc; }
void setSemiLoc(SourceLocation L) { SemiLoc = L; }
- bool hasLeadingEmptyMacro() const { return LeadingEmptyMacro; }
+ bool hasLeadingEmptyMacro() const { return LeadingEmptyMacro.isValid(); }
+ SourceLocation getLeadingEmptyMacroLoc() const { return LeadingEmptyMacro; }
SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
@@ -424,6 +437,8 @@ public:
SourceLocation LB, SourceLocation RB)
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
CompoundStmtBits.NumStmts = NumStmts;
+ assert(CompoundStmtBits.NumStmts == NumStmts &&
+ "NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
if (NumStmts == 0) {
Body = 0;
@@ -516,6 +531,9 @@ public:
void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; }
Stmt *getSubStmt();
+ const Stmt *getSubStmt() const {
+ return const_cast<SwitchCase*>(this)->getSubStmt();
+ }
SourceRange getSourceRange() const { return SourceRange(); }
@@ -527,7 +545,7 @@ public:
};
class CaseStmt : public SwitchCase {
- enum { SUBSTMT, LHS, RHS, END_EXPR };
+ enum { LHS, RHS, SUBSTMT, END_EXPR };
Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for
// GNU "case 1 ... 4" extension
SourceLocation CaseLoc;
@@ -688,6 +706,12 @@ public:
VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V);
+ /// If this IfStmt has a condition variable, return the faux DeclStmt
+ /// associated with the creation of that condition variable.
+ const DeclStmt *getConditionVariableDeclStmt() const {
+ return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+ }
+
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
const Stmt *getThen() const { return SubExprs[THEN]; }
@@ -754,6 +778,12 @@ public:
/// \endcode
VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V);
+
+ /// If this SwitchStmt has a condition variable, return the faux DeclStmt
+ /// associated with the creation of that condition variable.
+ const DeclStmt *getConditionVariableDeclStmt() const {
+ return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+ }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
const Stmt *getBody() const { return SubExprs[BODY]; }
@@ -835,6 +865,12 @@ public:
VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V);
+ /// If this WhileStmt has a condition variable, return the faux DeclStmt
+ /// associated with the creation of that condition variable.
+ const DeclStmt *getConditionVariableDeclStmt() const {
+ return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+ }
+
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
@@ -939,6 +975,12 @@ public:
VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V);
+ /// If this ForStmt has a condition variable, return the faux DeclStmt
+ /// associated with the creation of that condition variable.
+ const DeclStmt *getConditionVariableDeclStmt() const {
+ return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]);
+ }
+
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); }
Stmt *getBody() { return SubExprs[BODY]; }
@@ -1406,6 +1448,122 @@ public:
}
};
+class SEHExceptStmt : public Stmt {
+ SourceLocation Loc;
+ Stmt *Children[2];
+
+ enum { FILTER_EXPR, BLOCK };
+
+ SEHExceptStmt(SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block);
+
+public:
+ static SEHExceptStmt* Create(ASTContext &C,
+ SourceLocation ExceptLoc,
+ Expr *FilterExpr,
+ Stmt *Block);
+ SourceRange getSourceRange() const {
+ return SourceRange(getExceptLoc(), getEndLoc());
+ }
+
+ SourceLocation getExceptLoc() const { return Loc; }
+ SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); }
+
+ Expr *getFilterExpr() const { return reinterpret_cast<Expr*>(Children[FILTER_EXPR]); }
+ CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Children[BLOCK]); }
+
+ child_range children() {
+ return child_range(Children,Children+2);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == SEHExceptStmtClass;
+ }
+
+ static bool classof(SEHExceptStmt *) { return true; }
+
+};
+
+class SEHFinallyStmt : public Stmt {
+ SourceLocation Loc;
+ Stmt *Block;
+
+ SEHFinallyStmt(SourceLocation Loc,
+ Stmt *Block);
+
+public:
+ static SEHFinallyStmt* Create(ASTContext &C,
+ SourceLocation FinallyLoc,
+ Stmt *Block);
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getFinallyLoc(), getEndLoc());
+ }
+
+ SourceLocation getFinallyLoc() const { return Loc; }
+ SourceLocation getEndLoc() const { return Block->getLocEnd(); }
+
+ CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Block); }
+
+ child_range children() {
+ return child_range(&Block,&Block+1);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == SEHFinallyStmtClass;
+ }
+
+ static bool classof(SEHFinallyStmt *) { return true; }
+
+};
+
+class SEHTryStmt : public Stmt {
+ bool IsCXXTry;
+ SourceLocation TryLoc;
+ Stmt *Children[2];
+
+ enum { TRY = 0, HANDLER = 1 };
+
+ SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try'
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler);
+
+public:
+ static SEHTryStmt* Create(ASTContext &C,
+ bool isCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler);
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getTryLoc(), getEndLoc());
+ }
+
+ SourceLocation getTryLoc() const { return TryLoc; }
+ SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); }
+
+ bool getIsCXXTry() const { return IsCXXTry; }
+ CompoundStmt* getTryBlock() const { return llvm::cast<CompoundStmt>(Children[TRY]); }
+ Stmt *getHandler() const { return Children[HANDLER]; }
+
+ /// Returns 0 if not defined
+ SEHExceptStmt *getExceptHandler() const;
+ SEHFinallyStmt *getFinallyHandler() const;
+
+ child_range children() {
+ return child_range(Children,Children+2);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == SEHTryStmtClass;
+ }
+
+ static bool classof(SEHTryStmt *) { return true; }
+
+};
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index f08815fd562d..42dcf2bb7b79 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -119,6 +119,88 @@ public:
friend class ASTStmtReader;
};
+/// CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for
+/// statement, represented as 'for (range-declarator : range-expression)'.
+///
+/// This is stored in a partially-desugared form to allow full semantic
+/// analysis of the constituent components. The original syntactic components
+/// can be extracted using getLoopVariable and getRangeInit.
+class CXXForRangeStmt : public Stmt {
+ enum { RANGE, BEGINEND, COND, INC, LOOPVAR, BODY, END };
+ // SubExprs[RANGE] is an expression or declstmt.
+ // SubExprs[COND] and SubExprs[INC] are expressions.
+ Stmt *SubExprs[END];
+ SourceLocation ForLoc;
+ SourceLocation ColonLoc;
+ SourceLocation RParenLoc;
+public:
+ CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd,
+ Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
+ SourceLocation FL, SourceLocation CL, SourceLocation RPL);
+ CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { }
+
+
+ VarDecl *getLoopVariable();
+ Expr *getRangeInit();
+
+ const VarDecl *getLoopVariable() const;
+ const Expr *getRangeInit() const;
+
+
+ DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); }
+ DeclStmt *getBeginEndStmt() { return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); }
+ Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); }
+ Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); }
+ DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
+ Stmt *getBody() { return SubExprs[BODY]; }
+
+ const DeclStmt *getRangeStmt() const {
+ return cast<DeclStmt>(SubExprs[RANGE]);
+ }
+ const DeclStmt *getBeginEndStmt() const {
+ return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
+ }
+ const Expr *getCond() const {
+ return cast_or_null<Expr>(SubExprs[COND]);
+ }
+ const Expr *getInc() const {
+ return cast_or_null<Expr>(SubExprs[INC]);
+ }
+ const DeclStmt *getLoopVarStmt() const {
+ return cast<DeclStmt>(SubExprs[LOOPVAR]);
+ }
+ const Stmt *getBody() const { return SubExprs[BODY]; }
+
+ void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); }
+ void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; }
+ void setBeginEndStmt(Stmt *S) { SubExprs[BEGINEND] = S; }
+ void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
+ void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
+ void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; }
+ void setBody(Stmt *S) { SubExprs[BODY] = S; }
+
+
+ SourceLocation getForLoc() const { return ForLoc; }
+ void setForLoc(SourceLocation Loc) { ForLoc = Loc; }
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXForRangeStmtClass;
+ }
+ static bool classof(const CXXForRangeStmt *) { return true; }
+
+ // Iterators
+ child_range children() {
+ return child_range(&SubExprs[0], &SubExprs[END]);
+ }
+};
+
} // end namespace clang
diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h
index 851c001adc54..05b50db7def7 100644
--- a/include/clang/AST/StmtIterator.h
+++ b/include/clang/AST/StmtIterator.h
@@ -18,6 +18,7 @@
#include <cassert>
#include <cstddef>
#include <iterator>
+#include <utility>
namespace clang {
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index a4e074e083f6..821b4fcbb168 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -362,7 +362,10 @@ private:
Expr *Expression;
TypeSourceInfo *Declarator;
struct {
- unsigned QualifierRange[2];
+ // FIXME: We'd like to just use the qualifier in the TemplateName,
+ // but template arguments get canonicalized too quickly.
+ NestedNameSpecifier *Qualifier;
+ void *QualifierLocData;
unsigned TemplateNameLoc;
unsigned EllipsisLoc;
} Template;
@@ -375,12 +378,12 @@ public:
TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
- TemplateArgumentLocInfo(SourceRange QualifierRange,
+ TemplateArgumentLocInfo(NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateNameLoc,
SourceLocation EllipsisLoc)
{
- Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding();
- Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding();
+ Template.Qualifier = QualifierLoc.getNestedNameSpecifier();
+ Template.QualifierLocData = QualifierLoc.getOpaqueData();
Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding();
Template.EllipsisLoc = EllipsisLoc.getRawEncoding();
}
@@ -393,10 +396,9 @@ public:
return Expression;
}
- SourceRange getTemplateQualifierRange() const {
- return SourceRange(
- SourceLocation::getFromRawEncoding(Template.QualifierRange[0]),
- SourceLocation::getFromRawEncoding(Template.QualifierRange[1]));
+ NestedNameSpecifierLoc getTemplateQualifierLoc() const {
+ return NestedNameSpecifierLoc(Template.Qualifier,
+ Template.QualifierLocData);
}
SourceLocation getTemplateNameLoc() const {
@@ -433,11 +435,10 @@ public:
}
TemplateArgumentLoc(const TemplateArgument &Argument,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateNameLoc,
SourceLocation EllipsisLoc = SourceLocation())
- : Argument(Argument),
- LocInfo(QualifierRange, TemplateNameLoc, EllipsisLoc) {
+ : Argument(Argument), LocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc) {
assert(Argument.getKind() == TemplateArgument::Template ||
Argument.getKind() == TemplateArgument::TemplateExpansion);
}
@@ -477,10 +478,10 @@ public:
return LocInfo.getAsExpr();
}
- SourceRange getTemplateQualifierRange() const {
+ NestedNameSpecifierLoc getTemplateQualifierLoc() const {
assert(Argument.getKind() == TemplateArgument::Template ||
Argument.getKind() == TemplateArgument::TemplateExpansion);
- return LocInfo.getTemplateQualifierRange();
+ return LocInfo.getTemplateQualifierLoc();
}
SourceLocation getTemplateNameLoc() const {
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 9b177cceed96..975a66fefa89 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_TYPE_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Linkage.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -72,7 +73,7 @@ namespace llvm {
namespace clang {
class ASTContext;
- class TypedefDecl;
+ class TypedefNameDecl;
class TemplateDecl;
class TemplateTypeParmDecl;
class NonTypeTemplateParmDecl;
@@ -212,6 +213,11 @@ public:
assert(type);
setObjCGCAttr(type);
}
+ Qualifiers withoutObjCGCAttr() const {
+ Qualifiers qs = *this;
+ qs.removeObjCGCAttr();
+ return qs;
+ }
bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
@@ -293,8 +299,10 @@ public:
(((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
}
- bool isSupersetOf(Qualifiers Other) const;
-
+ /// \brief Determine whether this set of qualifiers is a strict superset of
+ /// another set of qualifiers, not considering qualifier compatibility.
+ bool isStrictSupersetOf(Qualifiers Other) const;
+
bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
@@ -354,7 +362,9 @@ enum CallingConv {
CC_X86StdCall, // __attribute__((stdcall))
CC_X86FastCall, // __attribute__((fastcall))
CC_X86ThisCall, // __attribute__((thiscall))
- CC_X86Pascal // __attribute__((pascal))
+ CC_X86Pascal, // __attribute__((pascal))
+ CC_AAPCS, // __attribute__((pcs("aapcs")))
+ CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp")))
};
typedef std::pair<const Type*, Qualifiers> SplitQualType;
@@ -598,8 +608,14 @@ public:
/// ASTContext::getUnqualifiedArrayType.
inline SplitQualType getSplitUnqualifiedType() const;
+ /// \brief Determine whether this type is more qualified than the other
+ /// given type, requiring exact equality for non-CVR qualifiers.
bool isMoreQualifiedThan(QualType Other) const;
+
+ /// \brief Determine whether this type is at least as qualified as the other
+ /// given type, requiring exact equality for non-CVR qualifiers.
bool isAtLeastAsQualifiedAs(QualType Other) const;
+
QualType getNonReferenceType() const;
/// \brief Determine the type of a (typically non-lvalue) expression with the
@@ -1163,6 +1179,20 @@ public:
/// (C++0x [basic.types]p10)
bool isLiteralType() const;
+ /// isTrivialType - Return true if this is a trivial type
+ /// (C++0x [basic.types]p9)
+ bool isTrivialType() const;
+
+ /// \brief Test if this type is a standard-layout type.
+ /// (C++0x [basic.type]p9)
+ bool isStandardLayoutType() const;
+
+ /// isCXX11PODType() - Return true if this is a POD type according to the
+ /// more relaxed rules of the C++11 standard, regardless of the current
+ /// compilation's language.
+ /// (C++0x [basic.types]p9)
+ bool isCXX11PODType() const;
+
/// Helper methods to distinguish type categories. All type predicates
/// operate on the canonical type, ignoring typedefs and qualifiers.
@@ -1178,6 +1208,9 @@ public:
/// BuiltinTypes.
bool isPlaceholderType() const;
+ /// isSpecificPlaceholderType - Test for a specific placeholder type.
+ bool isSpecificPlaceholderType(unsigned K) const;
+
/// isIntegerType() does *not* include complex integers (a GCC extension).
/// isComplexIntegerType() can be used to test for complex integers.
bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
@@ -1207,6 +1240,8 @@ public:
bool isDerivedType() const; // C99 6.2.5p20
bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
bool isAggregateType() const;
+ bool isFundamentalType() const;
+ bool isCompoundType() const;
// Type Predicates: Check to see if this type is structurally the specified
// type, ignoring typedefs and qualifiers.
@@ -1321,6 +1356,7 @@ public:
// for object declared using an interface.
const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
+ const ObjCObjectPointerType *getAsObjCQualifiedClassType() const;
const ObjCObjectType *getAsObjCQualifiedInterfaceType() const;
const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
@@ -1475,25 +1511,52 @@ public:
NullPtr, // This is the type of C++0x 'nullptr'.
+ /// The primitive Objective C 'id' type. The user-visible 'id'
+ /// type is a typedef of an ObjCObjectPointerType to an
+ /// ObjCObjectType with this as its base. In fact, this only ever
+ /// shows up in an AST as the base type of an ObjCObjectType.
+ ObjCId,
+
+ /// The primitive Objective C 'Class' type. The user-visible
+ /// 'Class' type is a typedef of an ObjCObjectPointerType to an
+ /// ObjCObjectType with this as its base. In fact, this only ever
+ /// shows up in an AST as the base type of an ObjCObjectType.
+ ObjCClass,
+
+ /// The primitive Objective C 'SEL' type. The user-visible 'SEL'
+ /// type is a typedef of a PointerType to this.
+ ObjCSel,
+
/// This represents the type of an expression whose type is
/// totally unknown, e.g. 'T::foo'. It is permitted for this to
/// appear in situations where the structure of the type is
/// theoretically deducible.
Dependent,
- Overload, // This represents the type of an overloaded function declaration.
-
- /// The primitive Objective C 'id' type. The type pointed to by the
- /// user-visible 'id' type. Only ever shows up in an AST as the base
- /// type of an ObjCObjectType.
- ObjCId,
-
- /// The primitive Objective C 'Class' type. The type pointed to by the
- /// user-visible 'Class' type. Only ever shows up in an AST as the
- /// base type of an ObjCObjectType.
- ObjCClass,
-
- ObjCSel // This represents the ObjC 'SEL' type.
+ /// The type of an unresolved overload set. A placeholder type.
+ /// Expressions with this type have one of the following basic
+ /// forms, with parentheses generally permitted:
+ /// foo # possibly qualified, not if an implicit access
+ /// foo # possibly qualified, not if an implicit access
+ /// &foo # possibly qualified, not if an implicit access
+ /// x->foo # only if might be a static member function
+ /// &x->foo # only if might be a static member function
+ /// &Class::foo # when a pointer-to-member; sub-expr also has this type
+ /// OverloadExpr::find can be used to analyze the expression.
+ Overload,
+
+ /// The type of a bound C++ non-static member function.
+ /// A placeholder type. Expressions with this type have one of the
+ /// following basic forms:
+ /// foo # if an implicit access
+ /// x->foo # if only contains non-static members
+ BoundMember,
+
+ /// __builtin_any_type. A placeholder type. Useful for clients
+ /// like debuggers that don't know what type to give something.
+ /// Only a small number of operations are valid on expressions of
+ /// unknown type, most notably explicit casts.
+ UnknownAny
};
public:
@@ -1526,11 +1589,11 @@ public:
return getKind() >= Float && getKind() <= LongDouble;
}
- /// Determines whether this type is a "forbidden" placeholder type,
- /// i.e. a type which cannot appear in arbitrary positions in a
- /// fully-formed expression.
+ /// Determines whether this type is a placeholder type, i.e. a type
+ /// which cannot appear in arbitrary positions in a fully-formed
+ /// expression.
bool isPlaceholderType() const {
- return getKind() == Overload;
+ return getKind() >= Overload;
}
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
@@ -1991,7 +2054,7 @@ public:
friend class StmtIteratorBase;
void Profile(llvm::FoldingSetNodeID &ID) {
- assert(0 && "Cannnot unique VariableArrayTypes.");
+ assert(0 && "Cannot unique VariableArrayTypes.");
}
};
@@ -2257,12 +2320,13 @@ class FunctionType : public Type {
// you'll need to adjust both the Bits field below and
// Type::FunctionTypeBitfields.
- // | CC |noreturn|regparm
- // |0 .. 2| 3 |4 .. 6
+ // | CC |noreturn|hasregparm|regparm
+ // |0 .. 2| 3 | 4 |5 .. 7
enum { CallConvMask = 0x7 };
enum { NoReturnMask = 0x8 };
+ enum { HasRegParmMask = 0x10 };
enum { RegParmMask = ~(CallConvMask | NoReturnMask),
- RegParmOffset = 4 };
+ RegParmOffset = 5 };
unsigned char Bits;
@@ -2273,9 +2337,10 @@ class FunctionType : public Type {
public:
// Constructor with no defaults. Use this when you know that you
// have all the elements (when reading an AST file for example).
- ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) {
+ ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc) {
Bits = ((unsigned) cc) |
(noReturn ? NoReturnMask : 0) |
+ (hasRegParm ? HasRegParmMask : 0) |
(regParm << RegParmOffset);
}
@@ -2284,6 +2349,7 @@ class FunctionType : public Type {
ExtInfo() : Bits(0) {}
bool getNoReturn() const { return Bits & NoReturnMask; }
+ bool getHasRegParm() const { return Bits & HasRegParmMask; }
unsigned getRegParm() const { return Bits >> RegParmOffset; }
CallingConv getCC() const { return CallingConv(Bits & CallConvMask); }
@@ -2305,7 +2371,7 @@ class FunctionType : public Type {
}
ExtInfo withRegParm(unsigned RegParm) const {
- return ExtInfo((Bits & ~RegParmMask) | (RegParm << RegParmOffset));
+ return ExtInfo(HasRegParmMask | (Bits & ~RegParmMask) | (RegParm << RegParmOffset));
}
ExtInfo withCallingConv(CallingConv cc) const {
@@ -2341,7 +2407,8 @@ protected:
public:
QualType getResultType() const { return ResultType; }
-
+
+ bool getHasRegParm() const { return getExtInfo().getHasRegParm(); }
unsigned getRegParmType() const { return getExtInfo().getRegParm(); }
bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); }
CallingConv getCallConv() const { return getExtInfo().getCC(); }
@@ -2403,17 +2470,17 @@ public:
/// ExtProtoInfo - Extra information about a function prototype.
struct ExtProtoInfo {
ExtProtoInfo() :
- Variadic(false), HasExceptionSpec(false), HasAnyExceptionSpec(false),
- TypeQuals(0), RefQualifier(RQ_None), NumExceptions(0), Exceptions(0) {}
+ Variadic(false), ExceptionSpecType(EST_None), TypeQuals(0),
+ RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0) {}
FunctionType::ExtInfo ExtInfo;
bool Variadic;
- bool HasExceptionSpec;
- bool HasAnyExceptionSpec;
+ ExceptionSpecificationType ExceptionSpecType;
unsigned char TypeQuals;
RefQualifierKind RefQualifier;
unsigned NumExceptions;
const QualType *Exceptions;
+ Expr *NoexceptExpr;
};
private:
@@ -2435,13 +2502,10 @@ private:
unsigned NumArgs : 20;
/// NumExceptions - The number of types in the exception spec, if any.
- unsigned NumExceptions : 10;
+ unsigned NumExceptions : 9;
- /// HasExceptionSpec - Whether this function has an exception spec at all.
- unsigned HasExceptionSpec : 1;
-
- /// HasAnyExceptionSpec - Whether this function has a throw(...) spec.
- unsigned HasAnyExceptionSpec : 1;
+ /// ExceptionSpecType - The type of exception specification this function has.
+ unsigned ExceptionSpecType : 3;
/// ArgInfo - There is an variable size array after the class in memory that
/// holds the argument types.
@@ -2449,6 +2513,9 @@ private:
/// Exceptions - There is another variable size array after ArgInfo that
/// holds the exception types.
+ /// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
+ /// to the expression in the noexcept() specifier.
+
friend class ASTContext; // ASTContext creates these.
public:
@@ -2462,29 +2529,66 @@ public:
ExtProtoInfo EPI;
EPI.ExtInfo = getExtInfo();
EPI.Variadic = isVariadic();
- EPI.HasExceptionSpec = hasExceptionSpec();
- EPI.HasAnyExceptionSpec = hasAnyExceptionSpec();
+ EPI.ExceptionSpecType = getExceptionSpecType();
EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
EPI.RefQualifier = getRefQualifier();
- EPI.NumExceptions = NumExceptions;
- EPI.Exceptions = exception_begin();
+ if (EPI.ExceptionSpecType == EST_Dynamic) {
+ EPI.NumExceptions = NumExceptions;
+ EPI.Exceptions = exception_begin();
+ } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ EPI.NoexceptExpr = getNoexceptExpr();
+ }
return EPI;
}
- bool hasExceptionSpec() const { return HasExceptionSpec; }
- bool hasAnyExceptionSpec() const { return HasAnyExceptionSpec; }
+ /// \brief Get the kind of exception specification on this function.
+ ExceptionSpecificationType getExceptionSpecType() const {
+ return static_cast<ExceptionSpecificationType>(ExceptionSpecType);
+ }
+ /// \brief Return whether this function has any kind of exception spec.
+ bool hasExceptionSpec() const {
+ return getExceptionSpecType() != EST_None;
+ }
+ /// \brief Return whether this function has a dynamic (throw) exception spec.
+ bool hasDynamicExceptionSpec() const {
+ return isDynamicExceptionSpec(getExceptionSpecType());
+ }
+ /// \brief Return whether this function has a noexcept exception spec.
+ bool hasNoexceptExceptionSpec() const {
+ return isNoexceptExceptionSpec(getExceptionSpecType());
+ }
+ /// \brief Result type of getNoexceptSpec().
+ enum NoexceptResult {
+ NR_NoNoexcept, ///< There is no noexcept specifier.
+ NR_BadNoexcept, ///< The noexcept specifier has a bad expression.
+ NR_Dependent, ///< The noexcept specifier is dependent.
+ NR_Throw, ///< The noexcept specifier evaluates to false.
+ NR_Nothrow ///< The noexcept specifier evaluates to true.
+ };
+ /// \brief Get the meaning of the noexcept spec on this function, if any.
+ NoexceptResult getNoexceptSpec(ASTContext &Ctx) const;
unsigned getNumExceptions() const { return NumExceptions; }
QualType getExceptionType(unsigned i) const {
assert(i < NumExceptions && "Invalid exception number!");
return exception_begin()[i];
}
- bool hasEmptyExceptionSpec() const {
- return hasExceptionSpec() && !hasAnyExceptionSpec() &&
- getNumExceptions() == 0;
+ Expr *getNoexceptExpr() const {
+ if (getExceptionSpecType() != EST_ComputedNoexcept)
+ return 0;
+ // NoexceptExpr sits where the arguments end.
+ return *reinterpret_cast<Expr *const *>(arg_type_end());
+ }
+ bool isNothrow(ASTContext &Ctx) const {
+ ExceptionSpecificationType EST = getExceptionSpecType();
+ if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
+ return true;
+ if (EST != EST_ComputedNoexcept)
+ return false;
+ return getNoexceptSpec(Ctx) == NR_Nothrow;
}
using FunctionType::isVariadic;
-
+
/// \brief Determines whether this function prototype contains a
/// parameter pack at the end.
///
@@ -2513,6 +2617,8 @@ public:
return arg_type_end();
}
exception_iterator exception_end() const {
+ if (getExceptionSpecType() != EST_Dynamic)
+ return exception_begin();
return exception_begin() + NumExceptions;
}
@@ -2524,10 +2630,10 @@ public:
}
static bool classof(const FunctionProtoType *) { return true; }
- void Profile(llvm::FoldingSetNodeID &ID);
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys, unsigned NumArgs,
- const ExtProtoInfo &EPI);
+ const ExtProtoInfo &EPI, const ASTContext &Context);
};
@@ -2566,18 +2672,18 @@ public:
class TypedefType : public Type {
- TypedefDecl *Decl;
+ TypedefNameDecl *Decl;
protected:
- TypedefType(TypeClass tc, const TypedefDecl *D, QualType can)
+ TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can)
: Type(tc, can, can->isDependentType(), can->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false),
- Decl(const_cast<TypedefDecl*>(D)) {
+ Decl(const_cast<TypedefNameDecl*>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
friend class ASTContext; // ASTContext creates these.
public:
- TypedefDecl *getDecl() const { return Decl; }
+ TypedefNameDecl *getDecl() const { return Decl; }
bool isSugared() const { return true; }
QualType desugar() const;
@@ -2807,9 +2913,10 @@ public:
// Enumerated operand (string or keyword).
attr_objc_gc,
+ attr_pcs,
FirstEnumOperandKind = attr_objc_gc,
- LastEnumOperandKind = attr_objc_gc,
+ LastEnumOperandKind = attr_pcs,
// No operand.
attr_noreturn,
@@ -2864,44 +2971,68 @@ public:
};
class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
- unsigned Depth : 15;
- unsigned ParameterPack : 1;
- unsigned Index : 16;
- IdentifierInfo *Name;
+ // Helper data collector for canonical types.
+ struct CanonicalTTPTInfo {
+ unsigned Depth : 15;
+ unsigned ParameterPack : 1;
+ unsigned Index : 16;
+ };
+
+ union {
+ // Info for the canonical type.
+ CanonicalTTPTInfo CanTTPTInfo;
+ // Info for the non-canonical type.
+ TemplateTypeParmDecl *TTPDecl;
+ };
- TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N,
- QualType Canon)
+ /// Build a non-canonical type.
+ TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon)
: Type(TemplateTypeParm, Canon, /*Dependent=*/true,
- /*VariablyModified=*/false, PP),
- Depth(D), ParameterPack(PP), Index(I), Name(N) { }
+ /*VariablyModified=*/false,
+ Canon->containsUnexpandedParameterPack()),
+ TTPDecl(TTPDecl) { }
+ /// Build the canonical type.
TemplateTypeParmType(unsigned D, unsigned I, bool PP)
: Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true,
- /*VariablyModified=*/false, PP),
- Depth(D), ParameterPack(PP), Index(I), Name(0) { }
+ /*VariablyModified=*/false, PP) {
+ CanTTPTInfo.Depth = D;
+ CanTTPTInfo.Index = I;
+ CanTTPTInfo.ParameterPack = PP;
+ }
friend class ASTContext; // ASTContext creates these
+ const CanonicalTTPTInfo& getCanTTPTInfo() const {
+ QualType Can = getCanonicalTypeInternal();
+ return Can->castAs<TemplateTypeParmType>()->CanTTPTInfo;
+ }
+
public:
- unsigned getDepth() const { return Depth; }
- unsigned getIndex() const { return Index; }
- bool isParameterPack() const { return ParameterPack; }
- IdentifierInfo *getName() const { return Name; }
+ unsigned getDepth() const { return getCanTTPTInfo().Depth; }
+ unsigned getIndex() const { return getCanTTPTInfo().Index; }
+ bool isParameterPack() const { return getCanTTPTInfo().ParameterPack; }
+
+ TemplateTypeParmDecl *getDecl() const {
+ return isCanonicalUnqualified() ? 0 : TTPDecl;
+ }
+
+ IdentifierInfo *getIdentifier() const;
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Depth, Index, ParameterPack, Name);
+ Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl());
}
static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth,
unsigned Index, bool ParameterPack,
- IdentifierInfo *Name) {
+ TemplateTypeParmDecl *TTPDecl) {
ID.AddInteger(Depth);
ID.AddInteger(Index);
ID.AddBoolean(ParameterPack);
- ID.AddPointer(Name);
+ ID.AddPointer(TTPDecl);
}
static bool classof(const Type *T) {
@@ -2930,8 +3061,6 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
friend class ASTContext;
public:
- IdentifierInfo *getName() const { return Replaced->getName(); }
-
/// Gets the template parameter that was substituted for.
const TemplateTypeParmType *getReplacedParameter() const {
return Replaced;
@@ -2992,7 +3121,7 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
friend class ASTContext;
public:
- IdentifierInfo *getName() const { return Replaced->getName(); }
+ IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); }
/// Gets the template parameter that was substituted for.
const TemplateTypeParmType *getReplacedParameter() const {
@@ -4064,12 +4193,6 @@ inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
return getFunctionExtInfo(*t);
}
-/// \brief Determine whether this set of qualifiers is a superset of the given
-/// set of qualifiers.
-inline bool Qualifiers::isSupersetOf(Qualifiers Other) const {
- return Mask != Other.Mask && (Mask | Other.Mask) == Mask;
-}
-
/// isMoreQualifiedThan - Determine whether this type is more
/// qualified than the Other type. For example, "const volatile int"
/// is more qualified than "const int", "volatile int", and
@@ -4105,6 +4228,40 @@ inline QualType QualType::getNonReferenceType() const {
return *this;
}
+/// \brief Tests whether the type is categorized as a fundamental type.
+///
+/// \returns True for types specified in C++0x [basic.fundamental].
+inline bool Type::isFundamentalType() const {
+ return isVoidType() ||
+ // FIXME: It's really annoying that we don't have an
+ // 'isArithmeticType()' which agrees with the standard definition.
+ (isArithmeticType() && !isEnumeralType());
+}
+
+/// \brief Tests whether the type is categorized as a compound type.
+///
+/// \returns True for types specified in C++0x [basic.compound].
+inline bool Type::isCompoundType() const {
+ // C++0x [basic.compound]p1:
+ // Compound types can be constructed in the following ways:
+ // -- arrays of objects of a given type [...];
+ return isArrayType() ||
+ // -- functions, which have parameters of given types [...];
+ isFunctionType() ||
+ // -- pointers to void or objects or functions [...];
+ isPointerType() ||
+ // -- references to objects or functions of a given type. [...]
+ isReferenceType() ||
+ // -- classes containing a sequence of objects of various types, [...];
+ isRecordType() ||
+ // -- unions, which ar classes capable of containing objects of different types at different times;
+ isUnionType() ||
+ // -- enumerations, which comprise a set of named constant values. [...];
+ isEnumeralType() ||
+ // -- pointers to non-static class members, [...].
+ isMemberPointerType();
+}
+
inline bool Type::isFunctionType() const {
return isa<FunctionType>(CanonicalType);
}
@@ -4236,6 +4393,12 @@ inline bool Type::isPlaceholderType() const {
return false;
}
+inline bool Type::isSpecificPlaceholderType(unsigned K) const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
+ return (BT->getKind() == (BuiltinType::Kind) K);
+ return false;
+}
+
/// \brief Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index c7f5ee76330c..a1df744c2a72 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -527,7 +527,7 @@ class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
TypedefTypeLoc,
TypedefType> {
public:
- TypedefDecl *getTypedefDecl() const {
+ TypedefNameDecl *getTypedefNameDecl() const {
return getTypePtr()->getDecl();
}
};
@@ -584,6 +584,8 @@ class TemplateTypeParmTypeLoc :
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
TemplateTypeParmTypeLoc,
TemplateTypeParmType> {
+public:
+ TemplateTypeParmDecl *getDecl() const { return getTypePtr()->getDecl(); }
};
/// \brief Wrapper for substituted template type parameters.
@@ -943,10 +945,14 @@ public:
}
};
+struct MemberPointerLocInfo : public PointerLikeLocInfo {
+ TypeSourceInfo *ClassTInfo;
+};
/// \brief Wrapper for source info for member pointers.
class MemberPointerTypeLoc : public PointerLikeTypeLoc<MemberPointerTypeLoc,
- MemberPointerType> {
+ MemberPointerType,
+ MemberPointerLocInfo> {
public:
SourceLocation getStarLoc() const {
return getSigilLoc();
@@ -954,6 +960,28 @@ public:
void setStarLoc(SourceLocation Loc) {
setSigilLoc(Loc);
}
+
+ const Type *getClass() const {
+ return getTypePtr()->getClass();
+ }
+ TypeSourceInfo *getClassTInfo() const {
+ return getLocalData()->ClassTInfo;
+ }
+ void setClassTInfo(TypeSourceInfo* TI) {
+ getLocalData()->ClassTInfo = TI;
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setSigilLoc(Loc);
+ setClassTInfo(0);
+ }
+
+ SourceRange getLocalSourceRange() const {
+ if (TypeSourceInfo *TI = getClassTInfo())
+ return SourceRange(TI->getTypeLoc().getBeginLoc(), getStarLoc());
+ else
+ return SourceRange(getStarLoc());
+ }
};
/// Wraps an ObjCPointerType with source location information.
@@ -1007,7 +1035,8 @@ public:
struct FunctionLocInfo {
- SourceLocation LParenLoc, RParenLoc;
+ SourceLocation LocalRangeBegin;
+ SourceLocation LocalRangeEnd;
bool TrailingReturn;
};
@@ -1017,18 +1046,18 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
FunctionType,
FunctionLocInfo> {
public:
- SourceLocation getLParenLoc() const {
- return getLocalData()->LParenLoc;
+ SourceLocation getLocalRangeBegin() const {
+ return getLocalData()->LocalRangeBegin;
}
- void setLParenLoc(SourceLocation Loc) {
- getLocalData()->LParenLoc = Loc;
+ void setLocalRangeBegin(SourceLocation L) {
+ getLocalData()->LocalRangeBegin = L;
}
- SourceLocation getRParenLoc() const {
- return getLocalData()->RParenLoc;
+ SourceLocation getLocalRangeEnd() const {
+ return getLocalData()->LocalRangeEnd;
}
- void setRParenLoc(SourceLocation Loc) {
- getLocalData()->RParenLoc = Loc;
+ void setLocalRangeEnd(SourceLocation L) {
+ getLocalData()->LocalRangeEnd = L;
}
bool getTrailingReturn() const {
@@ -1056,12 +1085,12 @@ public:
}
SourceRange getLocalSourceRange() const {
- return SourceRange(getLParenLoc(), getRParenLoc());
+ return SourceRange(getLocalRangeBegin(), getLocalRangeEnd());
}
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
- setLParenLoc(Loc);
- setRParenLoc(Loc);
+ setLocalRangeBegin(Loc);
+ setLocalRangeEnd(Loc);
setTrailingReturn(false);
for (unsigned i = 0, e = getNumArgs(); i != e; ++i)
setArg(i, NULL);
@@ -1388,7 +1417,10 @@ class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
struct ElaboratedLocInfo {
SourceLocation KeywordLoc;
- SourceRange QualifierRange;
+
+ /// \brief Opaque data pointer used to reconstruct a nested-name-specifier
+ /// from
+ void *QualifierData;
};
class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
@@ -1403,27 +1435,29 @@ public:
this->getLocalData()->KeywordLoc = Loc;
}
- SourceRange getQualifierRange() const {
- return this->getLocalData()->QualifierRange;
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
+ getLocalData()->QualifierData);
}
- void setQualifierRange(SourceRange Range) {
- this->getLocalData()->QualifierRange = Range;
+
+ void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
+ assert(QualifierLoc.getNestedNameSpecifier()
+ == getTypePtr()->getQualifier() &&
+ "Inconsistent nested-name-specifier pointer");
+ getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}
SourceRange getLocalSourceRange() const {
if (getKeywordLoc().isValid())
- if (getQualifierRange().getEnd().isValid())
- return SourceRange(getKeywordLoc(), getQualifierRange().getEnd());
+ if (getQualifierLoc())
+ return SourceRange(getKeywordLoc(), getQualifierLoc().getEndLoc());
else
return SourceRange(getKeywordLoc());
else
- return getQualifierRange();
+ return getQualifierLoc().getSourceRange();
}
- void initializeLocal(ASTContext &Context, SourceLocation Loc) {
- setKeywordLoc(Loc);
- setQualifierRange(SourceRange(Loc));
- }
+ void initializeLocal(ASTContext &Context, SourceLocation Loc);
TypeLoc getNamedTypeLoc() const {
return getInnerTypeLoc();
@@ -1444,6 +1478,9 @@ public:
// type is some sort of TypeDeclTypeLoc.
struct DependentNameLocInfo : ElaboratedLocInfo {
SourceLocation NameLoc;
+
+ /// \brief Data associated with the nested-name-specifier location.
+ void *QualifierData;
};
class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
@@ -1458,13 +1495,18 @@ public:
this->getLocalData()->KeywordLoc = Loc;
}
- SourceRange getQualifierRange() const {
- return this->getLocalData()->QualifierRange;
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
+ getLocalData()->QualifierData);
}
- void setQualifierRange(SourceRange Range) {
- this->getLocalData()->QualifierRange = Range;
+
+ void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
+ assert(QualifierLoc.getNestedNameSpecifier()
+ == getTypePtr()->getQualifier() &&
+ "Inconsistent nested-name-specifier pointer");
+ getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}
-
+
SourceLocation getNameLoc() const {
return this->getLocalData()->NameLoc;
}
@@ -1476,7 +1518,7 @@ public:
if (getKeywordLoc().isValid())
return SourceRange(getKeywordLoc(), getNameLoc());
else
- return SourceRange(getQualifierRange().getBegin(), getNameLoc());
+ return SourceRange(getQualifierLoc().getBeginLoc(), getNameLoc());
}
void copy(DependentNameTypeLoc Loc) {
@@ -1485,16 +1527,11 @@ public:
memcpy(Data, Loc.Data, size);
}
- void initializeLocal(ASTContext &Context, SourceLocation Loc) {
- setKeywordLoc(Loc);
- setQualifierRange(SourceRange(Loc));
- setNameLoc(Loc);
- }
+ void initializeLocal(ASTContext &Context, SourceLocation Loc);
};
-// This is exactly the structure of an ElaboratedTypeLoc whose inner
-// type is some sort of TemplateSpecializationTypeLoc.
struct DependentTemplateSpecializationLocInfo : DependentNameLocInfo {
+ SourceLocation KeywordLoc;
SourceLocation LAngleLoc;
SourceLocation RAngleLoc;
// followed by a TemplateArgumentLocInfo[]
@@ -1513,11 +1550,28 @@ public:
this->getLocalData()->KeywordLoc = Loc;
}
- SourceRange getQualifierRange() const {
- return this->getLocalData()->QualifierRange;
- }
- void setQualifierRange(SourceRange Range) {
- this->getLocalData()->QualifierRange = Range;
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ if (!getLocalData()->QualifierData)
+ return NestedNameSpecifierLoc();
+
+ return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
+ getLocalData()->QualifierData);
+ }
+
+ void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
+ if (!QualifierLoc) {
+ // Even if we have a nested-name-specifier in the dependent
+ // template specialization type, we won't record the nested-name-specifier
+ // location information when this type-source location information is
+ // part of a nested-name-specifier.
+ getLocalData()->QualifierData = 0;
+ return;
+ }
+
+ assert(QualifierLoc.getNestedNameSpecifier()
+ == getTypePtr()->getQualifier() &&
+ "Inconsistent nested-name-specifier pointer");
+ getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}
SourceLocation getNameLoc() const {
@@ -1559,8 +1613,10 @@ public:
SourceRange getLocalSourceRange() const {
if (getKeywordLoc().isValid())
return SourceRange(getKeywordLoc(), getRAngleLoc());
+ else if (getQualifierLoc())
+ return SourceRange(getQualifierLoc().getBeginLoc(), getRAngleLoc());
else
- return SourceRange(getQualifierRange().getBegin(), getRAngleLoc());
+ return SourceRange(getNameLoc(), getRAngleLoc());
}
void copy(DependentTemplateSpecializationTypeLoc Loc) {
@@ -1569,16 +1625,7 @@ public:
memcpy(Data, Loc.Data, size);
}
- void initializeLocal(ASTContext &Context, SourceLocation Loc) {
- setKeywordLoc(Loc);
- setQualifierRange(SourceRange(Loc));
- setNameLoc(Loc);
- setLAngleLoc(Loc);
- setRAngleLoc(Loc);
- TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
- getTypePtr()->getArgs(),
- getArgInfos(), Loc);
- }
+ void initializeLocal(ASTContext &Context, SourceLocation Loc);
unsigned getExtraLocalDataSize() const {
return getNumArgs() * sizeof(TemplateArgumentLocInfo);
diff --git a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
index 72f644aaf028..a61d9e47881d 100644
--- a/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
+++ b/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
@@ -29,13 +29,13 @@ class CFGBlock;
// tend to have a common destination, so we lazily do a predecessor search
// from the destination node and cache the results to prevent work
// duplication.
-class CFGReachabilityAnalysis {
+class CFGReverseBlockReachabilityAnalysis {
typedef llvm::BitVector ReachableSet;
typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap;
ReachableSet analyzed;
ReachableMap reachable;
public:
- CFGReachabilityAnalysis(const CFG &cfg);
+ CFGReverseBlockReachabilityAnalysis(const CFG &cfg);
/// Returns true if the block 'Dst' can be reached from block 'Src'.
bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index cd771acb06a5..b966f3a90fff 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -1,4 +1,4 @@
-//===- UninitializedValues.h - unintialized values analysis ----*- C++ --*-===//
+//= UninitializedValues.h - Finding uses of uninitialized values --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -7,71 +7,35 @@
//
//===----------------------------------------------------------------------===//
//
-// This file provides the interface for the Unintialized Values analysis,
-// a flow-sensitive analysis that detects when variable values are unintialized.
+// This file defines APIs for invoking and reported uninitialized values
+// warnings.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_UNITVALS_H
-#define LLVM_CLANG_UNITVALS_H
-
-#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
-#include "clang/Analysis/FlowSensitive/DataflowValues.h"
+#ifndef LLVM_CLANG_UNINIT_VALS_H
+#define LLVM_CLANG_UNINIT_VALS_H
namespace clang {
- class BlockVarDecl;
- class Expr;
- class DeclRefExpr;
- class VarDecl;
-
-/// UninitializedValues_ValueTypes - Utility class to wrap type declarations
-/// for dataflow values and dataflow analysis state for the
-/// Unitialized Values analysis.
-class UninitializedValues_ValueTypes {
-public:
-
- struct ObserverTy;
-
- struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
- AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {}
- virtual ~AnalysisDataTy() {}
-
- ObserverTy* Observer;
- bool FullUninitTaint;
- };
-
- typedef StmtDeclBitVector_Types::ValTy ValTy;
-
- //===--------------------------------------------------------------------===//
- // ObserverTy - Observer for querying DeclRefExprs that use an uninitalized
- // value.
- //===--------------------------------------------------------------------===//
-
- struct ObserverTy {
- virtual ~ObserverTy();
- virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD,
- DeclRefExpr* DR, VarDecl* VD) = 0;
- };
-};
-
-/// UninitializedValues - Objects of this class encapsulate dataflow analysis
-/// information regarding what variable declarations in a function are
-/// potentially unintialized.
-class UninitializedValues :
- public DataflowValues<UninitializedValues_ValueTypes> {
+class AnalysisContext;
+class CFG;
+class DeclContext;
+class Expr;
+class VarDecl;
+
+class UninitVariablesHandler {
public:
- typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy;
-
- UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); }
-
- /// IntializeValues - Create initial dataflow values and meta data for
- /// a given CFG. This is intended to be called by the dataflow solver.
- void InitializeValues(const CFG& cfg);
+ UninitVariablesHandler() {}
+ virtual ~UninitVariablesHandler();
+
+ virtual void handleUseOfUninitVariable(const Expr *ex,
+ const VarDecl *vd,
+ bool isAlwaysUninit) {}
};
+
+void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
+ AnalysisContext &ac,
+ UninitVariablesHandler &handler);
-
-void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
- bool FullUninitTaint=false);
-} // end namespace clang
+}
#endif
diff --git a/include/clang/Analysis/Analyses/UninitializedValuesV2.h b/include/clang/Analysis/Analyses/UninitializedValuesV2.h
deleted file mode 100644
index c1fe040793e1..000000000000
--- a/include/clang/Analysis/Analyses/UninitializedValuesV2.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//= UninitializedValuesV2.h - Finding uses of uninitialized 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 defines APIs for invoking and reported uninitialized values
-// warnings.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_UNINIT_VALS_H
-#define LLVM_CLANG_UNINIT_VALS_H
-
-namespace clang {
-
-class AnalysisContext;
-class CFG;
-class DeclContext;
-class Expr;
-class VarDecl;
-
-class UninitVariablesHandler {
-public:
- UninitVariablesHandler() {}
- virtual ~UninitVariablesHandler();
-
- virtual void handleUseOfUninitVariable(const Expr *ex,
- const VarDecl *vd) {}
-};
-
-void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
- AnalysisContext &ac,
- UninitVariablesHandler &handler);
-
-}
-#endif
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 851451457881..66c12a5384d4 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
+#include "clang/Analysis/CFG.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerUnion.h"
@@ -27,9 +28,7 @@ namespace clang {
class Decl;
class Stmt;
-class CFG;
-class CFGBlock;
-class CFGReachabilityAnalysis;
+class CFGReverseBlockReachabilityAnalysis;
class CFGStmtMap;
class LiveVariables;
class ParentMap;
@@ -48,33 +47,32 @@ class AnalysisContext {
// TranslationUnit is NULL if we don't have multiple translation units.
idx::TranslationUnit *TU;
- // AnalysisContext owns the following data.
- CFG *cfg, *completeCFG;
- CFGStmtMap *cfgStmtMap;
+ llvm::OwningPtr<CFG> cfg, completeCFG;
+ llvm::OwningPtr<CFGStmtMap> cfgStmtMap;
+
+ CFG::BuildOptions cfgBuildOptions;
+ CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
+
bool builtCFG, builtCompleteCFG;
- LiveVariables *liveness;
- LiveVariables *relaxedLiveness;
- ParentMap *PM;
- PseudoConstantAnalysis *PCA;
- CFGReachabilityAnalysis *CFA;
- llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
+ const bool useUnoptimizedCFG;
+
+ llvm::OwningPtr<LiveVariables> liveness;
+ llvm::OwningPtr<LiveVariables> relaxedLiveness;
+ llvm::OwningPtr<ParentMap> PM;
+ llvm::OwningPtr<PseudoConstantAnalysis> PCA;
+ llvm::OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
+
llvm::BumpPtrAllocator A;
- bool UseUnoptimizedCFG;
- bool AddEHEdges;
- bool AddImplicitDtors;
- bool AddInitializers;
+
+ // FIXME: remove.
+ llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
+
public:
AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
bool useUnoptimizedCFG = false,
bool addehedges = false,
bool addImplicitDtors = false,
- bool addInitializers = false)
- : D(d), TU(tu), cfg(0), completeCFG(0), cfgStmtMap(0),
- builtCFG(false), builtCompleteCFG(false),
- liveness(0), relaxedLiveness(0), PM(0), PCA(0), CFA(0),
- ReferencedBlockVars(0), UseUnoptimizedCFG(useUnoptimizedCFG),
- AddEHEdges(addehedges), AddImplicitDtors(addImplicitDtors),
- AddInitializers(addInitializers) {}
+ bool addInitializers = false);
~AnalysisContext();
@@ -87,18 +85,22 @@ public:
/// callExprs. If this is false, then try/catch statements and blocks
/// reachable from them can appear to be dead in the CFG, analysis passes must
/// cope with that.
- bool getAddEHEdges() const { return AddEHEdges; }
-
- bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
- bool getAddImplicitDtors() const { return AddImplicitDtors; }
- bool getAddInitializers() const { return AddInitializers; }
+ bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
+ bool getUseUnoptimizedCFG() const {
+ return cfgBuildOptions.PruneTriviallyFalseEdges;
+ }
+ bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; }
+ bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; }
+ void registerForcedBlockExpression(const Stmt *stmt);
+ const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
+
Stmt *getBody();
CFG *getCFG();
CFGStmtMap *getCFGStmtMap();
- CFGReachabilityAnalysis *getCFGReachablityAnalysis();
+ CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis();
/// Return a version of the CFG without any edges pruned.
CFG *getUnoptimizedCFG();
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index 295d0a2133d3..dbf4e4c9aefe 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -15,7 +15,8 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#define ANALYSISSTART
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index b337d74495c9..ca46459afd9a 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -19,6 +19,8 @@
#include "llvm/ADT/GraphTraits.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/DenseMap.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceLocation.h"
#include <cassert>
@@ -29,6 +31,7 @@ namespace llvm {
}
namespace clang {
+ class CXXDestructorDecl;
class Decl;
class Stmt;
class Expr;
@@ -47,45 +50,45 @@ class CFGElement {
public:
enum Kind {
// main kind
+ Invalid,
Statement,
Initializer,
- ImplicitDtor,
// dtor kind
AutomaticObjectDtor,
BaseDtor,
MemberDtor,
TemporaryDtor,
- DTOR_BEGIN = AutomaticObjectDtor
+ DTOR_BEGIN = AutomaticObjectDtor,
+ DTOR_END = TemporaryDtor
};
protected:
- // The int bits are used to mark the main kind.
+ // The int bits are used to mark the kind.
llvm::PointerIntPair<void *, 2> Data1;
- // The int bits are used to mark the dtor kind.
llvm::PointerIntPair<void *, 2> Data2;
- CFGElement(void *Ptr, unsigned Int) : Data1(Ptr, Int) {}
- CFGElement(void *Ptr1, unsigned Int1, void *Ptr2, unsigned Int2)
- : Data1(Ptr1, Int1), Data2(Ptr2, Int2) {}
+ CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = 0)
+ : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
+ Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {}
public:
CFGElement() {}
- Kind getKind() const { return static_cast<Kind>(Data1.getInt()); }
-
- Kind getDtorKind() const {
- assert(getKind() == ImplicitDtor);
- return static_cast<Kind>(Data2.getInt() + DTOR_BEGIN);
+ Kind getKind() const {
+ unsigned x = Data2.getInt();
+ x <<= 2;
+ x |= Data1.getInt();
+ return (Kind) x;
}
-
- bool isValid() const { return Data1.getPointer(); }
+
+ bool isValid() const { return getKind() != Invalid; }
operator bool() const { return isValid(); }
-
- template<class ElemTy> ElemTy getAs() const {
+
+ template<class ElemTy> const ElemTy *getAs() const {
if (llvm::isa<ElemTy>(this))
- return *static_cast<const ElemTy*>(this);
- return ElemTy();
+ return static_cast<const ElemTy*>(this);
+ return 0;
}
static bool classof(const CFGElement *E) { return true; }
@@ -93,13 +96,10 @@ public:
class CFGStmt : public CFGElement {
public:
- CFGStmt() {}
- CFGStmt(Stmt *S) : CFGElement(S, 0) {}
+ CFGStmt(Stmt *S) : CFGElement(Statement, S) {}
Stmt *getStmt() const { return static_cast<Stmt *>(Data1.getPointer()); }
- operator Stmt*() const { return getStmt(); }
-
static bool classof(const CFGElement *E) {
return E->getKind() == Statement;
}
@@ -109,14 +109,12 @@ public:
/// constructor's initialization list.
class CFGInitializer : public CFGElement {
public:
- CFGInitializer() {}
- CFGInitializer(CXXCtorInitializer* I)
- : CFGElement(I, Initializer) {}
+ CFGInitializer(CXXCtorInitializer *initializer)
+ : CFGElement(Initializer, initializer) {}
CXXCtorInitializer* getInitializer() const {
return static_cast<CXXCtorInitializer*>(Data1.getPointer());
}
- operator CXXCtorInitializer*() const { return getInitializer(); }
static bool classof(const CFGElement *E) {
return E->getKind() == Initializer;
@@ -127,14 +125,18 @@ public:
/// by compiler on various occasions.
class CFGImplicitDtor : public CFGElement {
protected:
- CFGImplicitDtor(unsigned K, void* P, void* S)
- : CFGElement(P, ImplicitDtor, S, K - DTOR_BEGIN) {}
+ CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0)
+ : CFGElement(kind, data1, data2) {
+ assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
+ }
public:
- CFGImplicitDtor() {}
+ const CXXDestructorDecl *getDestructorDecl(ASTContext &astContext) const;
+ bool isNoReturn(ASTContext &astContext) const;
static bool classof(const CFGElement *E) {
- return E->getKind() == ImplicitDtor;
+ Kind kind = E->getKind();
+ return kind >= DTOR_BEGIN && kind <= DTOR_END;
}
};
@@ -143,22 +145,20 @@ public:
/// of leaving its local scope.
class CFGAutomaticObjDtor: public CFGImplicitDtor {
public:
- CFGAutomaticObjDtor() {}
- CFGAutomaticObjDtor(VarDecl* VD, Stmt* S)
- : CFGImplicitDtor(AutomaticObjectDtor, VD, S) {}
+ CFGAutomaticObjDtor(const VarDecl *var, const Stmt *stmt)
+ : CFGImplicitDtor(AutomaticObjectDtor, var, stmt) {}
- VarDecl* getVarDecl() const {
+ const VarDecl *getVarDecl() const {
return static_cast<VarDecl*>(Data1.getPointer());
}
// Get statement end of which triggered the destructor call.
- Stmt* getTriggerStmt() const {
+ const Stmt *getTriggerStmt() const {
return static_cast<Stmt*>(Data2.getPointer());
}
- static bool classof(const CFGElement *E) {
- return E->getKind() == ImplicitDtor &&
- E->getDtorKind() == AutomaticObjectDtor;
+ static bool classof(const CFGElement *elem) {
+ return elem->getKind() == AutomaticObjectDtor;
}
};
@@ -166,16 +166,15 @@ public:
/// base object in destructor.
class CFGBaseDtor : public CFGImplicitDtor {
public:
- CFGBaseDtor() {}
- CFGBaseDtor(const CXXBaseSpecifier *BS)
- : CFGImplicitDtor(BaseDtor, const_cast<CXXBaseSpecifier*>(BS), NULL) {}
+ CFGBaseDtor(const CXXBaseSpecifier *base)
+ : CFGImplicitDtor(BaseDtor, base) {}
const CXXBaseSpecifier *getBaseSpecifier() const {
return static_cast<const CXXBaseSpecifier*>(Data1.getPointer());
}
static bool classof(const CFGElement *E) {
- return E->getKind() == ImplicitDtor && E->getDtorKind() == BaseDtor;
+ return E->getKind() == BaseDtor;
}
};
@@ -183,16 +182,15 @@ public:
/// member object in destructor.
class CFGMemberDtor : public CFGImplicitDtor {
public:
- CFGMemberDtor() {}
- CFGMemberDtor(FieldDecl *FD)
- : CFGImplicitDtor(MemberDtor, FD, NULL) {}
+ CFGMemberDtor(const FieldDecl *field)
+ : CFGImplicitDtor(MemberDtor, field, 0) {}
- FieldDecl *getFieldDecl() const {
- return static_cast<FieldDecl*>(Data1.getPointer());
+ const FieldDecl *getFieldDecl() const {
+ return static_cast<const FieldDecl*>(Data1.getPointer());
}
static bool classof(const CFGElement *E) {
- return E->getKind() == ImplicitDtor && E->getDtorKind() == MemberDtor;
+ return E->getKind() == MemberDtor;
}
};
@@ -200,16 +198,15 @@ public:
/// at the end of full expression for temporary object.
class CFGTemporaryDtor : public CFGImplicitDtor {
public:
- CFGTemporaryDtor() {}
- CFGTemporaryDtor(CXXBindTemporaryExpr *E)
- : CFGImplicitDtor(TemporaryDtor, E, NULL) {}
+ CFGTemporaryDtor(CXXBindTemporaryExpr *expr)
+ : CFGImplicitDtor(TemporaryDtor, expr, 0) {}
- CXXBindTemporaryExpr *getBindTemporaryExpr() const {
- return static_cast<CXXBindTemporaryExpr *>(Data1.getPointer());
+ const CXXBindTemporaryExpr *getBindTemporaryExpr() const {
+ return static_cast<const CXXBindTemporaryExpr *>(Data1.getPointer());
}
static bool classof(const CFGElement *E) {
- return E->getKind() == ImplicitDtor && E->getDtorKind() == TemporaryDtor;
+ return E->getKind() == TemporaryDtor;
}
};
@@ -267,6 +264,8 @@ public:
/// ? operator LHS expression; RHS expression
/// &&, || expression that uses result of && or ||, RHS
///
+/// But note that any of that may be NULL in case of optimized-out edges.
+///
class CFGBlock {
class ElementList {
typedef BumpVector<CFGElement> ImplTy;
@@ -471,8 +470,6 @@ public:
const Stmt *getLoopTarget() const { return LoopTarget; }
- bool hasBinaryBranchTerminator() const;
-
Stmt* getLabel() { return Label; }
const Stmt* getLabel() const { return Label; }
@@ -537,13 +534,16 @@ public:
class BuildOptions {
public:
+ typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
+ ForcedBlkExprs **forcedBlkExprs;
+
bool PruneTriviallyFalseEdges:1;
bool AddEHEdges:1;
bool AddInitializers:1;
bool AddImplicitDtors:1;
BuildOptions()
- : PruneTriviallyFalseEdges(true)
+ : forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
, AddEHEdges(false)
, AddInitializers(false)
, AddImplicitDtors(false) {}
@@ -552,7 +552,7 @@ public:
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
/// constructed CFG belongs to the caller.
static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C,
- BuildOptions BO = BuildOptions());
+ const BuildOptions &BO);
/// createBlock - Create a new block in the CFG. The CFG owns the block;
/// the caller should not directly free it.
@@ -607,8 +607,8 @@ public:
for (const_iterator I=begin(), E=end(); I != E; ++I)
for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
BI != BE; ++BI) {
- if (CFGStmt S = BI->getAs<CFGStmt>())
- O(S);
+ if (const CFGStmt *stmt = BI->getAs<CFGStmt>())
+ O(stmt->getStmt());
}
}
diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
index 7e6e3815400c..18e81fed79f8 100644
--- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h
+++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
@@ -22,7 +22,7 @@ namespace cocoa {
enum NamingConvention { NoConvention, CreateRule, InitRule };
- NamingConvention deriveNamingConvention(Selector S, bool ignorePrefix = true);
+ NamingConvention deriveNamingConvention(Selector S);
static inline bool followsFundamentalRule(Selector S) {
return deriveNamingConvention(S) == CreateRule;
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index d75d333db6b6..9561b964b5f8 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -277,8 +277,8 @@ private:
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
CFGElement El = *I;
- if (CFGStmt S = El.getAs<CFGStmt>())
- ProcessStmt(S, recordStmtValues, AnalysisDirTag());
+ if (const CFGStmt *S = El.getAs<CFGStmt>())
+ ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag());
}
TF.VisitTerminator(const_cast<CFGBlock*>(B));
@@ -293,8 +293,8 @@ private:
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
CFGElement El = *I;
- if (CFGStmt S = El.getAs<CFGStmt>())
- ProcessStmt(S, recordStmtValues, AnalysisDirTag());
+ if (const CFGStmt *S = El.getAs<CFGStmt>())
+ ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag());
}
}
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index 54cfc3dc0db6..07b4dea987de 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -43,6 +43,7 @@ public:
PostStoreKind,
PostPurgeDeadSymbolsKind,
PostStmtCustomKind,
+ PostConditionKind,
PostLValueKind,
PostInitializerKind,
CallEnterKind,
@@ -221,7 +222,17 @@ public:
}
};
-
+// PostCondition represents the post program point of a branch condition.
+class PostCondition : public PostStmt {
+public:
+ PostCondition(const Stmt* S, const LocationContext *L, const void *tag = 0)
+ : PostStmt(S, PostConditionKind, L, tag) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostConditionKind;
+ }
+};
+
class LocationCheck : public StmtPoint {
protected:
LocationCheck(const Stmt *S, const LocationContext *L,
diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
index d197e69babde..7fb4ab3ebad9 100644
--- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h
@@ -82,6 +82,7 @@ public:
DISPATCH_CASE(ConditionalOperator)
DISPATCH_CASE(BinaryConditionalOperator)
DISPATCH_CASE(ObjCForCollectionStmt)
+ DISPATCH_CASE(CXXForRangeStmt)
case Stmt::BinaryOperatorClass: {
BinaryOperator* B = cast<BinaryOperator>(S);
@@ -109,6 +110,10 @@ public:
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
}
+ RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt* S) {
+ return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
+ }
+
RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
}
diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h
new file mode 100644
index 000000000000..d44a9c3b0361
--- /dev/null
+++ b/include/clang/Basic/AddressSpaces.h
@@ -0,0 +1,44 @@
+//===--- AddressSpaces.h - Language-specific address spaces -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides definitions for the various language-specific address
+// spaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H
+#define LLVM_CLANG_BASIC_ADDRESSSPACES_H
+
+namespace clang {
+
+namespace LangAS {
+
+/// This enum defines the set of possible language-specific address spaces.
+/// It uses a high starting offset so as not to conflict with any address
+/// space used by a target.
+enum ID {
+ Offset = 0xFFFF00,
+
+ opencl_global = Offset,
+ opencl_local,
+ opencl_constant,
+
+ Last,
+ Count = Last-Offset
+};
+
+/// The type of a lookup table which maps from language-specific address spaces
+/// to target-specific ones.
+typedef unsigned Map[Count];
+
+}
+
+}
+
+#endif
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 3e62d411d51a..e4c6722e8378 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -46,6 +46,7 @@ class Argument<string name> {
string Name = name;
}
+class BoolArgument<string name> : Argument<name>;
class IdentifierArgument<string name> : Argument<name>;
class IntArgument<string name> : Argument<name>;
class StringArgument<string name> : Argument<name>;
@@ -55,6 +56,9 @@ class TypeArgument<string name> : Argument<name>;
class UnsignedArgument<string name> : Argument<name>;
class VariadicUnsignedArgument<string name> : Argument<name>;
+// A version of the form major.minor[.subminor].
+class VersionArgument<string name> : Argument<name>;
+
// This one's a doozy, so it gets its own special type
// It can be an unsigned integer, or a type. Either can
// be dependent.
@@ -89,8 +93,13 @@ class Attr {
code AdditionalMembers = [{}];
}
+/// An inheritable attribute is inherited by later redeclarations.
class InheritableAttr : Attr;
+/// An inheritable parameter attribute is inherited by later
+/// redeclarations, even when it's written on a parameter.
+class InheritableParamAttr : InheritableAttr;
+
//
// Attributes begin here
//
@@ -129,12 +138,26 @@ def AsmLabel : InheritableAttr {
let Args = [StringArgument<"Label">];
}
+def Availability : InheritableAttr {
+ let Spellings = ["availability"];
+ let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">,
+ VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
+ BoolArgument<"unavailable">];
+ let AdditionalMembers =
+[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
+ return llvm::StringSwitch<llvm::StringRef>(Platform)
+ .Case("ios", "iOS")
+ .Case("macosx", "Mac OS X")
+ .Default(llvm::StringRef());
+} }];
+}
+
def Blocks : InheritableAttr {
let Spellings = ["blocks"];
let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>];
}
-def CarriesDependency : InheritableAttr {
+def CarriesDependency : InheritableParamAttr {
let Spellings = ["carries_dependency"];
let Subjects = [ParmVar, Function];
let Namespaces = ["", "std"];
@@ -154,7 +177,7 @@ def CFReturnsNotRetained : InheritableAttr {
let Subjects = [ObjCMethod, Function];
}
-def CFConsumed : InheritableAttr {
+def CFConsumed : InheritableParamAttr {
let Spellings = ["cf_consumed"];
let Subjects = [ParmVar];
}
@@ -224,10 +247,6 @@ def DLLImport : InheritableAttr {
let Spellings = ["dllimport"];
}
-def Explicit : InheritableAttr {
- let Spellings = [];
-}
-
def FastCall : InheritableAttr {
let Spellings = ["fastcall", "__fastcall"];
}
@@ -236,6 +255,10 @@ def Final : InheritableAttr {
let Spellings = [];
}
+def MsStruct : InheritableAttr {
+ let Spellings = ["__ms_struct__"];
+}
+
def Format : InheritableAttr {
let Spellings = ["format"];
let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
@@ -261,7 +284,7 @@ def IBOutlet : InheritableAttr {
def IBOutletCollection : InheritableAttr {
let Spellings = ["iboutletcollection"];
- let Args = [TypeArgument<"Interface">];
+ let Args = [TypeArgument<"InterFace">];
}
def Malloc : InheritableAttr {
@@ -355,7 +378,7 @@ def NSConsumesSelf : InheritableAttr {
let Subjects = [ObjCMethod];
}
-def NSConsumed : InheritableAttr {
+def NSConsumed : InheritableParamAttr {
let Spellings = ["ns_consumed"];
let Subjects = [ParmVar];
}
@@ -364,6 +387,15 @@ def ObjCException : InheritableAttr {
let Spellings = ["objc_exception"];
}
+def ObjCMethodFamily : InheritableAttr {
+ let Spellings = ["objc_method_family"];
+ let Subjects = [ObjCMethod];
+ let Args = [EnumArgument<"Family", "FamilyKind",
+ ["none", "alloc", "copy", "init", "mutableCopy", "new"],
+ ["OMF_None", "OMF_alloc", "OMF_copy", "OMF_init",
+ "OMF_mutableCopy", "OMF_new"]>];
+}
+
def ObjCNSObject : InheritableAttr {
let Spellings = ["NSObject"];
}
@@ -388,6 +420,13 @@ def Packed : InheritableAttr {
let Spellings = ["packed"];
}
+def Pcs : InheritableAttr {
+ let Spellings = ["pcs"];
+ let Args = [EnumArgument<"PCS", "PCSType",
+ ["aapcs", "aapcs-vfp"],
+ ["AAPCS", "AAPCS_VFP"]>];
+}
+
def Pure : InheritableAttr {
let Spellings = ["pure"];
}
diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h
index 65c4f98c952c..9d5ae588c50f 100644
--- a/include/clang/Basic/AttrKinds.h
+++ b/include/clang/Basic/AttrKinds.h
@@ -22,6 +22,7 @@ namespace attr {
enum Kind {
#define ATTR(X) X,
#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X,
+#define LAST_INHERITABLE_PARAM_ATTR(X) X, LAST_INHERITABLE_PARAM = X,
#include "clang/Basic/AttrList.inc"
NUM_ATTRS
};
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index b73ac1f4dd45..9a4c768dc649 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -443,7 +443,7 @@ BUILTIN(__builtin_dwarf_sp_column, "Ui", "n")
BUILTIN(__builtin_extend_pointer, "ULLiv*", "n") // _Unwind_Word == uint64_t
// GCC Object size checking builtins
-BUILTIN(__builtin_object_size, "zv*i", "n")
+BUILTIN(__builtin_object_size, "zvC*i", "n")
BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF")
BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF")
BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF")
@@ -577,6 +577,13 @@ BUILTIN(__sync_lock_release_4, "viD*.", "n")
BUILTIN(__sync_lock_release_8, "vLLiD*.", "n")
BUILTIN(__sync_lock_release_16, "vLLLiD*.", "n")
+BUILTIN(__sync_swap, "v.", "")
+BUILTIN(__sync_swap_1, "ccD*c.", "n")
+BUILTIN(__sync_swap_2, "ssD*s.", "n")
+BUILTIN(__sync_swap_4, "iiD*i.", "n")
+BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "n")
+BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "n")
+
// Non-overloaded atomic builtins.
diff --git a/include/clang/Basic/BuiltinsPTX.def b/include/clang/Basic/BuiltinsPTX.def
new file mode 100644
index 000000000000..f90a43f7f404
--- /dev/null
+++ b/include/clang/Basic/BuiltinsPTX.def
@@ -0,0 +1,62 @@
+//===--- BuiltinsPTX.def - PTX Builtin function database ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the PTX-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+BUILTIN(__builtin_ptx_read_tid_x, "i", "nc")
+BUILTIN(__builtin_ptx_read_tid_y, "i", "nc")
+BUILTIN(__builtin_ptx_read_tid_z, "i", "nc")
+BUILTIN(__builtin_ptx_read_tid_w, "i", "nc")
+
+BUILTIN(__builtin_ptx_read_ntid_x, "i", "nc")
+BUILTIN(__builtin_ptx_read_ntid_y, "i", "nc")
+BUILTIN(__builtin_ptx_read_ntid_z, "i", "nc")
+BUILTIN(__builtin_ptx_read_ntid_w, "i", "nc")
+
+BUILTIN(__builtin_ptx_read_ctaid_x, "i", "nc")
+BUILTIN(__builtin_ptx_read_ctaid_y, "i", "nc")
+BUILTIN(__builtin_ptx_read_ctaid_z, "i", "nc")
+BUILTIN(__builtin_ptx_read_ctaid_w, "i", "nc")
+
+BUILTIN(__builtin_ptx_read_nctaid_x, "i", "nc")
+BUILTIN(__builtin_ptx_read_nctaid_y, "i", "nc")
+BUILTIN(__builtin_ptx_read_nctaid_z, "i", "nc")
+BUILTIN(__builtin_ptx_read_nctaid_w, "i", "nc")
+
+BUILTIN(__builtin_ptx_read_laneid, "i", "nc")
+BUILTIN(__builtin_ptx_read_warpid, "i", "nc")
+BUILTIN(__builtin_ptx_read_nwarpid, "i", "nc")
+
+BUILTIN(__builtin_ptx_read_smid, "i", "nc")
+BUILTIN(__builtin_ptx_read_nsmid, "i", "nc")
+BUILTIN(__builtin_ptx_read_gridid, "i", "nc")
+
+BUILTIN(__builtin_ptx_read_lanemask_eq, "i", "nc")
+BUILTIN(__builtin_ptx_read_lanemask_le, "i", "nc")
+BUILTIN(__builtin_ptx_read_lanemask_lt, "i", "nc")
+BUILTIN(__builtin_ptx_read_lanemask_ge, "i", "nc")
+BUILTIN(__builtin_ptx_read_lanemask_gt, "i", "nc")
+
+BUILTIN(__builtin_ptx_read_clock, "i", "n")
+BUILTIN(__builtin_ptx_read_clock64, "Li", "n")
+
+BUILTIN(__builtin_ptx_read_pm0, "i", "n")
+BUILTIN(__builtin_ptx_read_pm1, "i", "n")
+BUILTIN(__builtin_ptx_read_pm2, "i", "n")
+BUILTIN(__builtin_ptx_read_pm3, "i", "n")
+
+BUILTIN(__builtin_ptx_bar_sync, "vi", "n")
+
+
+#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index da106daf26ec..2c2a84ab30ae 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -24,6 +24,37 @@
// FIXME: Are these nothrow/const?
+// 3DNow!
+//
+BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "nc")
+BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "nc")
+BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "nc")
+// GCC has pfrsqrtit1, even though this is not the name of the instruction.
+BUILTIN(__builtin_ia32_pfrsqrtit1, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "nc")
+BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "nc")
+// 3DNow! Extensions.
+BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "nc")
+BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "nc")
+BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "nc")
+BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "nc")
+BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "nc")
+
// MMX
//
// FIXME: All MMX instructions will be generated via builtins. Any MMX vector
@@ -209,7 +240,6 @@ BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "")
BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "")
BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "")
BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "")
-BUILTIN(__builtin_ia32_loadups, "V4ffC*", "")
BUILTIN(__builtin_ia32_storeups, "vf*V4f", "")
BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "")
BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "")
@@ -223,7 +253,6 @@ BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "")
BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "")
BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "")
BUILTIN(__builtin_ia32_maskmovdqu, "vV16cV16cc*", "")
-BUILTIN(__builtin_ia32_loadupd, "V2ddC*", "")
BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "")
BUILTIN(__builtin_ia32_movmskpd, "iV2d", "")
BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "")
@@ -342,10 +371,10 @@ BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16cic","")
BUILTIN(__builtin_ia32_pcmpgtq, "V2LLiV2LLiV2LLi", "")
-BUILTIN(__builtin_ia32_crc32qi, "iic", "")
-BUILTIN(__builtin_ia32_crc32hi, "iis", "")
-BUILTIN(__builtin_ia32_crc32si, "iii", "")
-BUILTIN(__builtin_ia32_crc32di, "LLiLLiLLi", "")
+BUILTIN(__builtin_ia32_crc32qi, "UiUiUc", "")
+BUILTIN(__builtin_ia32_crc32hi, "UiUiUs", "")
+BUILTIN(__builtin_ia32_crc32si, "UiUiUi", "")
+BUILTIN(__builtin_ia32_crc32di, "ULLiULLiULLi", "")
// AES
BUILTIN(__builtin_ia32_aesenc128, "V2LLiV2LLiV2LLi", "")
diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt
index 19066e4c0eef..df49dc6a1c9f 100644
--- a/include/clang/Basic/CMakeLists.txt
+++ b/include/clang/Basic/CMakeLists.txt
@@ -17,6 +17,10 @@ clang_tablegen(DiagnosticGroups.inc -gen-clang-diag-groups
SOURCE Diagnostic.td
TARGET ClangDiagnosticGroups)
+clang_tablegen(DiagnosticIndexName.inc -gen-clang-diags-index-name
+ SOURCE Diagnostic.td
+ TARGET ClangDiagnosticIndexName)
+
clang_tablegen(AttrList.inc -gen-clang-attr-list
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h
index 4da2ad757223..d928f9d0f66b 100644
--- a/include/clang/Basic/ConvertUTF.h
+++ b/include/clang/Basic/ConvertUTF.h
@@ -87,6 +87,9 @@
------------------------------------------------------------------------ */
+#ifndef CLANG_BASIC_CONVERTUTF_H
+#define CLANG_BASIC_CONVERTUTF_H
+
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
@@ -156,4 +159,6 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
}
#endif
+#endif
+
/* --------------------------------------------------------------------- */
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index 2ec7427cf758..9e69492e13c7 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -17,7 +17,9 @@ def Named : Decl<1>;
def NamespaceAlias : DDecl<Named>;
def Label : DDecl<Named>;
def Type : DDecl<Named, 1>;
- def Typedef : DDecl<Type>;
+ def TypedefName : DDecl<Type, 1>;
+ def Typedef : DDecl<TypedefName>;
+ def TypeAlias : DDecl<TypedefName>;
def UnresolvedUsingTypename : DDecl<Type>;
def Tag : DDecl<Type, 1>, DeclContext;
def Enum : DDecl<Tag>;
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 3fc60d136b5c..7fc400f31bb0 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -585,7 +585,7 @@ private:
/// DiagArgumentsVal - The values for the various substitution positions. This
/// is used when the argument is not an std::string. The specific value is
- /// mangled into an intptr_t and the intepretation depends on exactly what
+ /// mangled into an intptr_t and the interpretation depends on exactly what
/// sort of argument kind it is.
intptr_t DiagArgumentsVal[MaxArguments];
@@ -741,9 +741,6 @@ public:
}
void AddFixItHint(const FixItHint &Hint) const {
- if (Hint.isNull())
- return;
-
assert(NumFixItHints < Diagnostic::MaxFixItHints &&
"Too many fix-it hints!");
if (DiagObj)
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index be510ed844e1..50a22c4a9120 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -18,6 +18,8 @@ def MAP_IGNORE : DiagMapping;
def MAP_WARNING : DiagMapping;
def MAP_ERROR : DiagMapping;
def MAP_FATAL : DiagMapping;
+def MAP_WARNING_NO_WERROR : DiagMapping;
+def MAP_WARNING_SHOW_IN_SYSTEM_HEADER : DiagMapping;
// Define the diagnostic classes.
class DiagClass;
@@ -60,6 +62,8 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
DiagMapping DefaultMapping = defaultmapping;
DiagGroup Group;
string CategoryName = "";
+ string Brief = "";
+ string Explanation = "";
}
class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
@@ -73,10 +77,20 @@ class DefaultIgnore { DiagMapping DefaultMapping = MAP_IGNORE; }
class DefaultWarn { DiagMapping DefaultMapping = MAP_WARNING; }
class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; }
class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; }
+class DefaultWarnNoWerror { DiagMapping DefaultMapping= MAP_WARNING_NO_WERROR; }
+class DefaultWarnShowInSystemHeader {
+ DiagMapping DefaultMapping = MAP_WARNING_SHOW_IN_SYSTEM_HEADER;
+}
class NoSFINAE { bit SFINAE = 0; }
class AccessControl { bit AccessControl = 1; }
+class Brief<string str> { string Brief = str; }
+class FullExplanation<string brief, string full> {
+ string Brief = brief;
+ string Explanation = full;
+}
+
// Definitions for Diagnostics.
include "DiagnosticASTKinds.td"
include "DiagnosticAnalysisKinds.td"
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 85c64c5cef65..0b0bca0395cb 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -45,6 +45,8 @@ def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
InGroup<MissingDeclarations>;
def err_param_redefinition : Error<"redefinition of parameter %0">;
def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">;
+def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">,
+ InGroup<DuplicateArgDecl>, DefaultIgnore;
def err_invalid_storage_class_in_func_decl : Error<
"invalid storage class specifier in function declarator">;
def err_expected_namespace_name : Error<"expected namespace name">;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index ef1c9e7d8b9a..908a69b162c4 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -39,8 +39,10 @@ def err_drv_invalid_darwin_version : Error<
"invalid Darwin version number: %0">;
def err_drv_missing_argument : Error<
"argument to '%0' is missing (expected %1 %plural{1:value|:values}1)">;
-def err_drv_invalid_Xarch_argument : Error<
- "invalid Xarch argument: '%0'">;
+def err_drv_invalid_Xarch_argument_with_args : Error<
+ "invalid Xarch argument: '%0', options requiring arguments are unsupported">;
+def err_drv_invalid_Xarch_argument_isdriver : Error<
+ "invalid Xarch argument: '%0', cannot change driver behavior inside Xarch argument">;
def err_drv_argument_only_allowed_with : Error<
"invalid argument '%0' only allowed with '%1'">;
def err_drv_argument_not_allowed_with : Error<
@@ -76,6 +78,10 @@ def err_drv_cc_print_options_failure : Error<
"unable to open CC_PRINT_OPTIONS file: %0">;
def err_drv_preamble_format : Error<
"incorrect format for -preamble-bytes=N,END">;
+def err_drv_conflicting_deployment_targets : Error<
+ "conflicting deployment targets, both '%0' and '%1' are present in environment">;
+def err_drv_invalid_arch_for_deployment_target : Error<
+ "invalid architecture '%0' for deployment target '%1'">;
def warn_c_kext : Warning<
"ignoring -fapple-kext which is valid for c++ and objective-c++ only">;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 30706769d45e..67fc22e410fe 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -79,6 +79,8 @@ def warn_fe_macro_contains_embedded_newline : Warning<
"macro '%0' contains embedded newline, text after the newline is ignored.">;
def warn_fe_cc_print_header_failure : Warning<
"unable to open CC_PRINT_HEADERS file: %0 (using stderr)">;
+def warn_fe_cc_log_diagnostics_failure : Warning<
+ "unable to open CC_LOG_DIAGNOSTICS file: %0 (using stderr)">;
def err_verify_missing_start : Error<
"cannot find start ('{{') of expected %0">;
@@ -113,6 +115,9 @@ def warn_pch_target_triple : Error<
def warn_pch_c99 : Error<
"C99 support was %select{disabled|enabled}0 in PCH file but is "
"currently %select{disabled|enabled}1">;
+def warn_pch_c1x : Error<
+ "C1X support was %select{disabled|enabled}0 in PCH file but is "
+ "currently %select{disabled|enabled}1">;
def warn_pch_cplusplus : Error<
"C++ support was %select{disabled|enabled}0 in PCH file but is "
"currently %select{disabled|enabled}1">;
@@ -230,6 +235,9 @@ def warn_pch_gnu_inline : Error<
def warn_pch_no_inline : Error<
"the macro '__NO_INLINE__' was %select{not defined|defined}0 in "
"the PCH file but is currently %select{undefined|defined}1">;
+def warn_pch_deprecated : Error<
+ "the macro '__DEPRECATED' was %select{not defined|defined}0 in "
+ "the PCH file but is currently %select{undefined|defined}1">;
def warn_pch_gc_mode : Error<
"the PCH file was built with %select{no||hybrid}0 garbage collection but "
"the current translation unit will compiled with %select{no||hybrid}1 "
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 412fb587108e..c85acc510770 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -24,6 +24,7 @@ def : DiagGroup<"aggregate-return">;
def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">;
def : DiagGroup<"attributes">;
def : DiagGroup<"bad-function-cast">;
+def Availability : DiagGroup<"availability">;
def BoolConversions : DiagGroup<"bool-conversions">;
def CXXCompat: DiagGroup<"c++-compat">;
def CastAlign : DiagGroup<"cast-align">;
@@ -54,6 +55,7 @@ def CXXHexFloats : DiagGroup<"c++-hex-floats">;
def : DiagGroup<"c++0x-compat", [CXXHexFloats]>;
def : DiagGroup<"effc++">;
+def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
def GlobalConstructors : DiagGroup<"global-constructors">;
def : DiagGroup<"idiomatic-parentheses">;
@@ -94,6 +96,8 @@ def Padded : DiagGroup<"padded">;
def PointerArith : DiagGroup<"pointer-arith">;
def PoundWarning : DiagGroup<"#warnings">,
DiagCategory<"#warning Directive">;
+def PoundPragmaMessage : DiagGroup<"#pragma messages">,
+ DiagCategory<"#pragma message Directive">;
def : DiagGroup<"pointer-to-int-cast">;
def : DiagGroup<"redundant-decls">;
def ReturnType : DiagGroup<"return-type">;
@@ -109,6 +113,7 @@ def : DiagGroup<"stack-protector">;
def : DiagGroup<"switch-default">;
def : DiagGroup<"synth">;
def TautologicalCompare : DiagGroup<"tautological-compare">;
+def HeaderHygiene : DiagGroup<"header-hygiene">;
// Preprocessor warnings.
def : DiagGroup<"builtin-macro-redefined">;
@@ -137,13 +142,17 @@ def Trigraphs : DiagGroup<"trigraphs">;
def : DiagGroup<"type-limits">;
def Uninitialized : DiagGroup<"uninitialized">;
+def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def UnknownAttributes : DiagGroup<"unknown-attributes">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args">;
def UnusedArgument : DiagGroup<"unused-argument">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
-def UnusedFunction : DiagGroup<"unused-function">;
-def UnusedMemberFunction : DiagGroup<"unused-member-function">;
+def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
+def UnneededMemberFunction : DiagGroup<"unneeded-member-function">;
+def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>;
+def UnusedMemberFunction : DiagGroup<"unused-member-function",
+ [UnneededMemberFunction]>;
def UnusedLabel : DiagGroup<"unused-label">;
def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedValue : DiagGroup<"unused-value">;
@@ -165,17 +174,22 @@ def VariadicMacros : DiagGroup<"variadic-macros">;
def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
def VLA : DiagGroup<"vla">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
-def : DiagGroup<"write-strings">;
+
+// GCC calls -Wdeprecated-writable-strings -Wwrite-strings.
+def GCCWriteStrings : DiagGroup<"write-strings" , [DeprecatedWritableStr]>;
+
def CharSubscript : DiagGroup<"char-subscripts">;
def LargeByValueCopy : DiagGroup<"large-by-value-copy">;
+def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">;
// Aggregation warning settings.
// -Widiomatic-parentheses contains warnings about 'idiomatic'
-// missing parentheses; it is off by default.
+// missing parentheses; it is off by default. We do not include it
+// in -Wparentheses because most users who use -Wparentheses explicitly
+// do not want these warnings.
def Parentheses : DiagGroup<"parentheses",
- [LogicalOpParentheses,
- DiagGroup<"idiomatic-parentheses">]>;
+ [LogicalOpParentheses]>;
// -Wconversion has its own warnings, but we split a few out for
// legacy reasons:
@@ -187,6 +201,7 @@ def Conversion : DiagGroup<"conversion",
[DiagGroup<"shorten-64-to-32">,
DiagGroup<"constant-conversion">,
DiagGroup<"literal-conversion">,
+ DiagGroup<"sign-conversion">,
BoolConversions]>,
DiagCategory<"Value Conversion Issue">;
@@ -253,7 +268,9 @@ def NonGCC : DiagGroup<"non-gcc",
// A warning group for warnings about using C++0x features as extensions in
// earlier C++ versions.
-def CXX0x : DiagGroup<"c++0x-extensions">;
+def CXX0xStaticNonIntegralInitializer :
+ DiagGroup<"c++0x-static-nonintegral-init">;
+def CXX0x : DiagGroup<"c++0x-extensions", [CXX0xStaticNonIntegralInitializer]>;
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 2b03cae565c8..0296b96d00f6 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -42,7 +42,8 @@ namespace clang {
// Get typedefs for common diagnostics.
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#include "clang/Basic/DiagnosticCommonKinds.inc"
NUM_BUILTIN_COMMON_DIAGNOSTICS
#undef DIAG
@@ -63,9 +64,12 @@ namespace clang {
/// Map this diagnostic to "warning", but make it immune to -Werror. This
/// happens when you specify -Wno-error=foo.
MAP_WARNING_NO_WERROR = 5,
+ /// Map this diagnostic to "warning", but make it immune to
+ /// -Wno-system-headers.
+ MAP_WARNING_SHOW_IN_SYSTEM_HEADER = 6,
/// Map this diagnostic to "error", but make it immune to -Wfatal-errors.
/// This happens for -Wno-fatal-errors=foo.
- MAP_ERROR_NO_WFATAL = 6
+ MAP_ERROR_NO_WFATAL = 7
};
}
@@ -99,7 +103,7 @@ public:
/// issue.
const char *getDescription(unsigned DiagID) const;
- /// isNoteWarningOrExtension - Return true if the unmapped diagnostic
+ /// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
/// level of the specified diagnostic ID is a Warning or Extension.
/// This only works on builtin diagnostics, not custom ones, and is not legal to
/// call on NOTEs.
@@ -130,7 +134,7 @@ public:
/// the diagnostic, this returns null.
static const char *getWarningOptionForDiag(unsigned DiagID);
- /// getWarningOptionForDiag - Return the category number that a specified
+ /// getCategoryNumberForDiag - Return the category number that a specified
/// DiagID belongs to, or 0 if no category.
static unsigned getCategoryNumberForDiag(unsigned DiagID);
@@ -174,6 +178,20 @@ public:
/// are not SFINAE errors.
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
+ /// getName - Given a diagnostic ID, return its name
+ static const char *getName(unsigned DiagID);
+
+ /// getIdFromName - Given a diagnostic name, return its ID, or 0
+ static unsigned getIdFromName(char const *Name);
+
+ /// getBriefExplanation - Given a diagnostic ID, return a brief explanation
+ /// of the issue
+ static const char *getBriefExplanation(unsigned DiagID);
+
+ /// getFullExplanation - Given a diagnostic ID, return a full explanation
+ /// of the issue
+ static const char *getFullExplanation(unsigned DiagID);
+
private:
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
/// "unknown-pragmas" to have the specified mapping. This returns true and
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 6d1d9b6ad869..3514ccace22a 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -114,7 +114,8 @@ def err_invalid_pth_file : Error<
//===----------------------------------------------------------------------===//
// Preprocessor Diagnostics
//===----------------------------------------------------------------------===//
-def pp_hash_warning : Warning<"#warning%0">, InGroup<PoundWarning>;
+def pp_hash_warning : Warning<"#warning%0">,
+ InGroup<PoundWarning>, DefaultWarnShowInSystemHeader;
def pp_include_next_in_primary : Warning<
"#include_next in primary source file">;
def pp_include_macros_out_of_predefines : Error<
@@ -239,7 +240,8 @@ def err_pragma_push_pop_macro_malformed : Error<
"pragma %0 requires a parenthesized string">;
def warn_pragma_pop_macro_no_push : Warning<
"pragma pop_macro could not pop '%0', no matching push_macro">;
-def warn_pragma_message : Warning<"%0">;
+def warn_pragma_message : Warning<"%0">,
+ InGroup<PoundPragmaMessage>, DefaultWarnNoWerror;
def warn_pragma_ignored : Warning<"unknown pragma ignored">,
InGroup<UnknownPragmas>, DefaultIgnore;
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
@@ -247,8 +249,8 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
def ext_on_off_switch_syntax :
ExtWarn<"expected 'ON' or 'OFF' or 'DEFAULT' in pragma">,
InGroup<UnknownPragmas>;
-def ext_pragma_syntax_eom :
- ExtWarn<"expected end of macro in pragma">,
+def ext_pragma_syntax_eod :
+ ExtWarn<"expected end of directive in pragma">,
InGroup<UnknownPragmas>;
def warn_stdc_fenv_access_not_supported :
Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 9a68af9c45ca..c37e510b3479 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -67,6 +67,13 @@ def ext_ms_enum_fixed_underlying_type : Extension<
"enumeration types with a fixed underlying type are a Microsoft extension">,
InGroup<Microsoft>;
+def ext_c1x_generic_selection : Extension<
+ "generic selections are a C1X-specific feature">;
+def err_duplicate_default_assoc : Error<
+ "duplicate default generic association">;
+def note_previous_default_assoc : Note<
+ "previous default generic association is here">;
+
def ext_gnu_indirect_goto : Extension<
"use of GNU indirect-goto extension">, InGroup<GNU>;
def ext_gnu_address_of_label : Extension<
@@ -111,7 +118,7 @@ def err_expected_semi_declaration : Error<
"expected ';' at end of declaration">;
def err_expected_semi_decl_list : Error<
"expected ';' at end of declaration list">;
-def ext_expected_semi_decl_list : Extension<
+def ext_expected_semi_decl_list : ExtWarn<
"expected ';' at end of declaration list">;
def err_expected_member_name_or_semi : Error<
"expected member name or ';' after declaration specifiers">;
@@ -119,6 +126,10 @@ def err_function_declared_typedef : Error<
"function definition declared 'typedef'">;
def err_iboutletcollection_builtintype : Error<
"type argument of iboutletcollection attribute cannot be a builtin type">;
+
+def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">;
+def err_at_in_class : Error<"unexpected '@' in member specification">;
+
def err_expected_fn_body : Error<
"expected function body after function declarator">;
def err_expected_method_body : Error<"expected method body">;
@@ -130,6 +141,7 @@ def err_expected_statement : Error<"expected statement">;
def err_expected_lparen_after : Error<"expected '(' after '%0'">;
def err_expected_lparen_after_id : Error<"expected '(' after %0">;
def err_expected_less_after : Error<"expected '<' after '%0'">;
+def err_expected_equal_after : Error<"expected '=' after %0">;
def err_expected_comma : Error<"expected ','">;
def err_expected_lbrace_in_compound_literal : Error<
"expected '{' in compound literal">;
@@ -178,6 +190,9 @@ def ext_ref_qualifier : ExtWarn<
"reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>;
def ext_inline_namespace : ExtWarn<
"inline namespaces are a C++0x feature">, InGroup<CXX0x>;
+def ext_generalized_initializer_lists : ExtWarn<
+ "generalized initializer lists are a C++0x extension unsupported in Clang">,
+ InGroup<CXX0x>;
def err_argument_required_after_attribute : Error<
"argument required after attribute">;
def err_missing_param : Error<"expected parameter declarator">;
@@ -189,6 +204,9 @@ def err_expected_class_name : Error<"expected class name">;
def err_unspecified_vla_size_with_static : Error<
"'static' may not be used with an unspecified variable length array size">;
+def err_expected_case_before_expression: Error<
+ "expected 'case' keyword before expression">;
+
// Declarations.
def err_typename_requires_specqual : Error<
"type name requires a specifier or qualifier">;
@@ -226,6 +244,8 @@ def err_unexected_colon_in_nested_name_spec : Error<
"unexpected ':' in nested name specifier">;
def err_bool_redeclaration : Error<
"redeclaration of C++ built-in type 'bool'">;
+def ext_c1x_static_assert : Extension<
+ "_Static_assert is a C1X-specific feature">;
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
@@ -266,7 +286,7 @@ def err_missing_id_definition : Error<"cannot find definition of 'id'">;
def err_missing_proto_definition : Error<
"cannot find definition of 'Protocol'">;
def err_missing_class_definition : Error<"cannot find definition of 'Class'">;
-def warn_expected_implementation : Warning<
+def err_expected_implementation : Error<
"@end must appear in an @implementation context">;
def error_property_ivar_decl : Error<
"property synthesize requires specification of an ivar">;
@@ -300,6 +320,8 @@ def err_expected_lbrace_after_base_specifiers : Error<
"expected '{' after base class list">;
def ext_ellipsis_exception_spec : Extension<
"exception specification of '...' is a Microsoft extension">;
+def err_dynamic_and_noexcept_specification : Error<
+ "cannot have both throw() and noexcept() clause on the same function">;
def err_expected_catch : Error<"expected catch">;
def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
def err_using_namespace_in_class : Error<
@@ -363,6 +385,8 @@ def err_enum_template : Error<"enumeration cannot be a template">;
def err_missing_dependent_template_keyword : Error<
"use 'template' keyword to treat '%0' as a dependent template name">;
+def warn_missing_dependent_template_keyword : ExtWarn<
+ "use 'template' keyword to treat '%0' as a dependent template name">;
def warn_static_inline_explicit_inst_ignored : Warning<
"ignoring '%select{static|inline}0' keyword on explicit template "
@@ -380,6 +404,8 @@ def err_out_of_line_type_names_constructor : Error<
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
+def warn_expected_qualified_after_typename : ExtWarn<
+ "expected a qualified name after 'typename'">;
def err_expected_semi_after_tagdecl : Error<
"expected ';' after %0">;
@@ -401,15 +427,23 @@ def err_ctor_init_missing_comma : Error<
// C++ declarations
def err_friend_decl_defines_class : Error<
"cannot define a type in a friend declaration">;
+def err_missing_whitespace_digraph : Error<
+ "found '<::' after a "
+ "%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0"
+ " which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">;
def warn_deleted_function_accepted_as_extension: ExtWarn<
"deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
+// C++0x alias-declaration
+def ext_alias_declaration : ExtWarn<
+ "alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
+def err_alias_declaration_not_identifier : Error<
+ "name defined in alias declaration must be an identifier">;
+
// C++0x override control
def ext_override_control_keyword : Extension<
"'%0' keyword accepted as a C++0x extension">, InGroup<CXX0x>;
-def ext_override_inline: Extension<
- "'%0' keyword only allowed in declarations, allowed as an extension">;
def err_duplicate_virt_specifier : Error<
"class member already marked '%0'">;
@@ -426,6 +460,23 @@ def err_paren_sizeof_parameter_pack : Error<
def err_sizeof_parameter_pack : Error<
"expected parenthesized parameter pack name in 'sizeof...' expression">;
+// Availability attribute
+def err_expected_version : Error<
+ "expected a version of the form 'major[.minor[.subminor]]'">;
+def err_zero_version : Error<
+ "version number must have non-zero major, minor, or sub-minor version">;
+def err_availability_expected_platform : Error<
+ "expected a platform name, e.g., 'macosx'">;
+def err_availability_expected_change : Error<
+ "expected 'introduced', 'deprecated', or 'obsoleted'">;
+def err_availability_unknown_change : Error<
+ "%0 is not an availability stage; use 'introduced', 'deprecated', or "
+ "'obsoleted'">;
+def err_availability_redundant : Error<
+ "redundant %0 availability change; only the last specified change will " "be used">;
+def warn_availability_and_unavailable : Warning<
+ "'unavailable' availability overrides all other availability information">;
+
// Language specific pragmas
// - Generic warnings
def warn_pragma_expected_lparen : Warning<
@@ -434,6 +485,8 @@ def warn_pragma_expected_rparen : Warning<
"missing ')' after '#pragma %0' - ignoring">;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">;
+def warn_pragma_ms_struct : Warning<
+ "incorrect use of '#pragma ms_struct on|off' - ignored">;
def warn_pragma_extra_tokens_at_eol : Warning<
"extra tokens at end of '#pragma %0' - ignored">;
// - #pragma options
@@ -468,5 +521,17 @@ def warn_pragma_expected_enable_disable : Warning<
def warn_pragma_unknown_extension : Warning<
"unknown OpenCL extension %0 - ignoring">;
+def err_seh_expected_handler : Error<
+ "expected '__except' or '__finally' block">;
+
+def err_seh___except_block : Error<
+ "%0 only allowed in __except block">;
+
+def err_seh___except_filter : Error<
+ "%0 only allowed in __except filter expression">;
+
+def err_seh___finally_block : Error<
+ "%0 only allowed in __finally block">;
+
} // end of Parse Issue category.
} // end of Parser diagnostics
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index a9fb2da00176..0a0c91ac9144 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -30,6 +30,8 @@ def warn_float_overflow : Warning<
def warn_float_underflow : Warning<
"magnitude of floating-point constant too small for type %0; minimum is %1">,
InGroup<LiteralRange>;
+def warn_double_const_requires_fp64 : Warning<
+ "double precision constant requires cl_khr_fp64, casting to single precision">;
// C99 variable-length arrays
def ext_vla : Extension<
@@ -57,6 +59,8 @@ def err_variably_modified_new_type : Error<
// C99 Designated Initializers
def ext_designated_init : Extension<
+ "designated initializers are a C99 feature">;
+def ext_designated_init_cxx : Extension<
"designated initializers are a C99 feature, accepted in C++ as an extension">;
def err_array_designator_negative : Error<
"array designator value '%0' is negative">;
@@ -114,6 +118,12 @@ def warn_unused_member_function : Warning<"unused member function %0">,
InGroup<UnusedMemberFunction>, DefaultIgnore;
def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">,
InGroup<UsedButMarkedUnused>, DefaultIgnore;
+def warn_unneeded_internal_decl : Warning<
+ "%select{function|variable}0 %1 is not needed and will not be emitted">,
+ InGroup<UnneededInternalDecl>, DefaultIgnore;
+def warn_unneeded_member_function : Warning<
+ "member function %0 is not needed and will not be emitted">,
+ InGroup<UnneededMemberFunction>, DefaultIgnore;
def warn_parameter_size: Warning<
"%0 is a large (%1 bytes) pass-by-value argument; "
@@ -202,6 +212,9 @@ def warn_global_constructor : Warning<
def warn_global_destructor : Warning<
"declaration requires a global destructor">,
InGroup<GlobalConstructors>, DefaultIgnore;
+def warn_exit_time_destructor : Warning<
+ "declaration requires an exit-time destructor">,
+ InGroup<ExitTimeDestructors>, DefaultIgnore;
def err_invalid_thread : Error<
"'__thread' is only allowed on variable declarations">;
@@ -248,6 +261,11 @@ def err_builtin_definition : Error<"definition of builtin function %0">;
def err_types_compatible_p_in_cplusplus : Error<
"__builtin_types_compatible_p is not valid in C++">;
def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError;
+def warn_non_pod_memset : Warning<
+ "destination for this memset call is a pointer to a non-POD type %0">,
+ InGroup<DiagGroup<"non-pod-memset">>, DefaultIgnore;
+def note_non_pod_memset_silence : Note<
+ "explicitly cast the pointer to silence this warning">;
/// main()
// static/inline main() are not errors in C, just in C++.
@@ -382,7 +400,7 @@ def note_declared_at : Note<"declared here">;
def note_method_declared_at : Note<"method declared here">;
def err_setter_type_void : Error<"type of setter must be void">;
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
-def warn_missing_atend : Warning<"'@end' is missing in implementation context">;
+def err_missing_atend : Error<"'@end' is missing in implementation context">;
def err_objc_var_decl_inclass :
Error<"cannot declare variable inside @interface or @protocol">;
def error_missing_method_context : Error<
@@ -540,7 +558,7 @@ def ext_using_undefined_std : ExtWarn<
// C++ exception specifications
def err_exception_spec_in_typedef : Error<
- "exception specifications are not allowed in typedefs">;
+ "exception specifications are not allowed in %select{typedefs|type aliases}0">;
def err_distant_exception_spec : Error<
"exception specifications are not allowed beyond a single level "
"of indirection">;
@@ -549,6 +567,8 @@ def err_incomplete_in_exception_spec : Error<
"in exception specification">;
def err_mismatched_exception_spec : Error<
"exception specification in declaration does not match previous declaration">;
+def warn_mismatched_exception_spec : ExtWarn<
+ "exception specification in declaration does not match previous declaration">;
def err_override_exception_spec : Error<
"exception specification of overriding function is more lax than "
"base version">;
@@ -558,6 +578,8 @@ def err_deep_exception_specs_differ : Error<
"exception specifications of %select{return|argument}0 types differ">;
def warn_missing_exception_specification : Warning<
"%0 is missing exception specification '%1'">;
+def err_noexcept_needs_constant_expression : Error<
+ "argument to noexcept specifier must be a constant expression">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
@@ -786,20 +808,28 @@ def err_destructor_redeclared : Error<"destructor cannot be redeclared">;
def err_destructor_with_params : Error<"destructor cannot have any parameters">;
def err_destructor_variadic : Error<"destructor cannot be variadic">;
def err_destructor_typedef_name : Error<
- "destructor cannot be declared using a typedef %0 of the class name">;
+ "destructor cannot be declared using a %select{typedef|type alias}1 %0 of the class name">;
def err_destructor_name : Error<
"expected the class name after '~' to name the enclosing class">;
def err_destructor_class_name : Error<
"expected the class name after '~' to name a destructor">;
-def err_ident_in_pseudo_dtor_not_a_type : Error<
- "identifier %0 in pseudo-destructor expression does not name a type">;
+def err_ident_in_dtor_not_a_type : Error<
+ "identifier %0 in object destruction expression does not name a type">;
+def err_destructor_expr_type_mismatch : Error<
+ "destructor type %0 in object destruction expression does not match the "
+ "type %1 of the object being destroyed">;
+def note_destructor_type_here : Note<
+ "type %0 is declared here">;
+
+def err_destructor_template : Error<
+ "destructor cannot be declared as a template">;
// C++ initialization
def err_init_conversion_failed : Error<
"cannot initialize %select{a variable|a parameter|return object|an "
"exception object|a member subobject|an array element|a new value|a value|a "
- "base class|a vector element}0 of type %1 with an %select{rvalue|lvalue}2 of "
- "type %3">;
+ "base class|a constructor delegation|a vector element}0 of type %1 with an "
+ "%select{rvalue|lvalue}2 of type %3">;
def err_lvalue_to_rvalue_ref : Error<"rvalue reference to type %0 cannot bind "
"to lvalue of type %1">;
@@ -854,13 +884,23 @@ def note_uninit_reference_member : Note<
"uninitialized reference member is here">;
def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
InGroup<Uninitialized>;
-def warn_uninit_var : Warning<"variable %0 is possibly uninitialized when used here">,
- InGroup<DiagGroup<"uninitialized-experimental">>, DefaultIgnore;
+def warn_uninit_self_reference_in_init : Warning<
+ "variable %0 is uninitialized when used within its own initialization">,
+ InGroup<Uninitialized>;
+def warn_uninit_var : Warning<
+ "variable %0 is uninitialized when used here">,
+ InGroup<Uninitialized>, DefaultIgnore;
+def warn_maybe_uninit_var :
+ Warning<"variable %0 may be uninitialized when used here">,
+ InGroup<UninitializedMaybe>, DefaultIgnore;
def note_uninit_var_def : Note<
"variable %0 is declared here">;
def warn_uninit_var_captured_by_block : Warning<
- "variable %0 is possibly uninitialized when captured by block">,
- InGroup<DiagGroup<"uninitialized-experimental">>, DefaultIgnore;
+ "variable %0 is uninitialized when captured by block">,
+ InGroup<Uninitialized>, DefaultIgnore;
+def warn_maybe_uninit_var_captured_by_block : Warning<
+ "variable %0 may be uninitialized when captured by block">,
+ InGroup<UninitializedMaybe>, DefaultIgnore;
def note_var_fixit_add_initialization : Note<
"add initialization to silence this warning">;
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
@@ -905,7 +945,7 @@ def err_auto_not_allowed : Error<
"'auto' not allowed %select{in function prototype|in struct member"
"|in union member|in class member|in exception declaration"
"|in template parameter|in block literal|in template argument"
- "|in typedef|in function return type|here}0">;
+ "|in typedef|in type alias|in function return type|here}0">;
def err_auto_var_requires_init : Error<
"declaration of variable %0 with type %1 requires an initializer">;
def err_auto_new_requires_ctor_arg : Error<
@@ -944,9 +984,6 @@ def err_final_function_overridden : Error<
def err_final_base : Error<
"derivation from 'final' %0">;
-def err_function_overriding_without_override : Error<
- "%0 overrides function%s1 without being marked 'override'">;
-
// C++0x scoped enumerations
def err_enum_invalid_underlying : Error<
"non-integral type %0 is an invalid underlying type">;
@@ -969,6 +1006,34 @@ def err_delegation_0x_only : Error<
"delegating constructors are permitted only in C++0x">;
def err_delegation_unimplemented : Error<
"delegating constructors are not fully implemented">;
+def err_delegating_initializer_alone : Error<
+ "an initializer for a delegating constructor must appear alone">;
+def err_delegating_ctor_loop : Error<
+ "constructor %0 delegates to itself (possibly indirectly)">;
+def err_delegating_codegen_not_implemented : Error<
+ "code generation for delegating constructors not implemented">;
+
+// C++0x range-based for loop
+def err_for_range_decl_must_be_var : Error<
+ "for range declaration must declare a variable">;
+def err_for_range_storage_class : Error<
+ "loop variable %0 may not be declared %select{'extern'|'static'|"
+ "'__private_extern__'|'auto'|'register'|'constexpr'}1">;
+def err_type_defined_in_for_range : Error<
+ "types may not be defined in a for range declaration">;
+def err_for_range_deduction_failure : Error<
+ "cannot use type %0 as a range">;
+def err_for_range_incomplete_type : Error<
+ "cannot use incomplete type %0 as a range">;
+def err_for_range_iter_deduction_failure : Error<
+ "cannot use type %0 as an iterator">;
+def err_for_range_member_begin_end_mismatch : Error<
+ "range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">;
+def err_for_range_begin_end_types_differ : Error<
+ "'begin' and 'end' must return the same type (got %0 and %1)">;
+def note_for_range_type : Note<"range has type %0">;
+def note_for_range_begin_end : Note<
+ "selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
@@ -982,7 +1047,10 @@ def err_attribute_can_be_applied_only_to_symbol_declaration : Error<
def err_attributes_are_not_compatible : Error<
"%0 and %1 attributes are not compatible">;
def err_attribute_wrong_number_arguments : Error<
- "attribute requires %0 argument(s)">;
+ "attribute %plural{0:takes no arguments|1:takes one argument|"
+ ":requires exactly %0 arguments}0">;
+def err_attribute_too_many_arguments : Error<
+ "attribute takes no more than %0 argument%s0">;
def err_iboutletcollection_type : Error<
"invalid type %0 as argument of iboutletcollection attribute">;
def err_iboutletcollection_object_type : Error<
@@ -1026,6 +1094,7 @@ def err_format_attribute_result_not : Error<"function does not return %0">;
def err_format_attribute_implicit_this_format_string : Error<
"format attribute cannot specify the implicit this argument as the format "
"string">;
+def warn_unknown_method_family : Warning<"unrecognized method family">;
def err_attribute_invalid_size : Error<
"vector size not an integral multiple of component size">;
def err_attribute_zero_size : Error<"zero vector size">;
@@ -1101,7 +1170,9 @@ def err_attribute_wrong_decl_type : Error<
"classes and virtual methods|functions, methods, and parameters|"
"classes|virtual methods|class members|variables|methods}1">;
def warn_function_attribute_wrong_type : Warning<
- "%0 only applies to function types; type here is %1">;
+ "'%0' only applies to function types; type here is %1">;
+def warn_pointer_attribute_wrong_type : Warning<
+ "'%0' only applies to pointer types; type here is %1">;
def warn_gnu_inline_attribute_requires_inline : Warning<
"'gnu_inline' attribute requires function to be marked 'inline',"
" attribute ignored">;
@@ -1119,6 +1190,15 @@ def err_cconv_varargs : Error<
def err_regparm_mismatch : Error<"function declared with with regparm(%0) "
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
+def err_invalid_pcs : Error<"Invalid PCS type">;
+
+// Availability attribute
+def warn_availability_unknown_platform : Warning<
+ "unknown platform %0 in availability macro">;
+def warn_availability_version_ordering : Warning<
+ "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version "
+ "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
+ "attribute ignored">;
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
@@ -1134,10 +1214,10 @@ def warn_impcast_float_integer : Warning<
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
def warn_impcast_integer_sign : Warning<
"implicit conversion changes signedness: %0 to %1">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ InGroup<DiagGroup<"sign-conversion">>, DefaultIgnore;
def warn_impcast_integer_sign_conditional : Warning<
"operand of ? changes signedness: %0 to %1">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ InGroup<DiagGroup<"sign-conversion">>, DefaultIgnore;
def warn_impcast_integer_precision : Warning<
"implicit conversion loses integer precision: %0 to %1">,
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
@@ -1154,9 +1234,15 @@ def warn_impcast_literal_float_to_integer : Warning<
"implicit conversion turns literal floating-point number into integer: "
"%0 to %1">,
InGroup<DiagGroup<"literal-conversion">>, DefaultIgnore;
+def note_fix_integral_float_as_integer : Note<
+ "this can be rewritten as an integer literal with the exact same value">;
def warn_impcast_different_enum_types : Warning<
"implicit conversion from enumeration type %0 to different enumeration type "
"%1">, InGroup<DiagGroup<"conversion">>;
+def warn_impcast_bool_to_null_pointer : Warning<
+ "initialization of pointer of type %0 to NULL from a constant boolean "
+ "expression">, InGroup<BoolConversions>;
+
def warn_cast_align : Warning<
"cast from %0 to %1 increases required alignment from %2 to %3">,
@@ -1252,11 +1338,13 @@ def err_ident_list_in_fn_declaration : Error<
def ext_param_not_declared : Extension<
"parameter %0 was not declared, defaulting to type 'int'">;
def err_param_typedef_of_void : Error<
- "empty parameter list defined with a typedef of 'void' not allowed in C++">;
+ "empty parameter list defined with a %select{typedef|type alias}0 of 'void' not allowed%select{ in C++|}0">;
def err_param_default_argument : Error<
"C does not support default arguments">;
def err_param_default_argument_redefinition : Error<
"redefinition of default argument">;
+def warn_param_default_argument_redefinition : ExtWarn<
+ "redefinition of default argument">;
def err_param_default_argument_missing : Error<
"missing default argument on parameter">;
def err_param_default_argument_missing_name : Error<
@@ -1311,11 +1399,11 @@ def err_ovl_no_viable_member_function_in_call : Error<
def err_ovl_ambiguous_call : Error<
"call to %0 is ambiguous">;
def err_ovl_deleted_call : Error<
- "call to %select{unavailable|deleted}0 function %1 %2">;
+ "call to %select{unavailable|deleted}0 function %1%2">;
def err_ovl_ambiguous_member_call : Error<
"call to member function %0 is ambiguous">;
def err_ovl_deleted_member_call : Error<
- "call to %select{unavailable|deleted}0 member function %1 %2">;
+ "call to %select{unavailable|deleted}0 member function %1%2">;
def note_ovl_too_many_candidates : Note<
"remaining %0 candidate%s0 omitted; "
"pass -fshow-overloads=all to show them">;
@@ -1327,10 +1415,6 @@ def note_ovl_candidate : Note<"candidate "
"is the implicit copy assignment operator|"
"is an inherited constructor}0%1">;
-def warn_init_pointer_from_false : Warning<
- "initialization of pointer of type %0 from literal 'false'">,
- InGroup<BoolConversions>;
-
def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
def note_ovl_candidate_bad_deduction : Note<
"candidate template ignored: failed template argument deduction">;
@@ -1408,6 +1492,15 @@ def note_ovl_candidate_bad_addrspace : Note<"candidate "
"constructor (inherited)}0%1 not viable: "
"%select{%ordinal6|'this'}5 argument (%2) is in "
"address space %3, but parameter must be in address space %4">;
+def note_ovl_candidate_bad_gc : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "function (the implicit copy assignment operator)|"
+ "constructor (inherited)}0%1 not viable: "
+ "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 "
+ "lifetime, but parameter has %select{no|__weak|__strong}4 lifetime">;
def note_ovl_candidate_bad_cvr_this : Note<"candidate "
"%select{|function|||function||||"
"function (the implicit copy assignment operator)|}0 not viable: "
@@ -1467,13 +1560,13 @@ def err_ovl_ambiguous_oper_binary : Error<
"use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">;
def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
def err_ovl_deleted_oper : Error<
- "overload resolution selected %select{unavailable|deleted}0 operator '%1' %2">;
+ "overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">;
def err_ovl_no_viable_subscript :
Error<"no viable overloaded operator[] for type %0">;
def err_ovl_no_oper :
Error<"type %0 does not provide a %select{subscript|call}1 operator">;
def err_ovl_unresolvable :
- Error<"cannot resolve overloaded function from context">;
+ Error<"cannot resolve overloaded function %0 from context">;
def err_ovl_no_viable_object_call : Error<
@@ -1481,7 +1574,7 @@ def err_ovl_no_viable_object_call : Error<
def err_ovl_ambiguous_object_call : Error<
"call to object of type %0 is ambiguous">;
def err_ovl_deleted_object_call : Error<
- "call to %select{unavailable|deleted}0 function call operator in type %1 %2">;
+ "call to %select{unavailable|deleted}0 function call operator in type %1%2">;
def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
def err_member_call_without_object : Error<
"call to non-static member function without an object argument">;
@@ -1707,6 +1800,8 @@ def err_template_spec_default_arg : Error<
def err_not_class_template_specialization : Error<
"cannot specialize a %select{dependent template|template template "
"parameter}0">;
+def err_function_specialization_in_class : Error<
+ "cannot specialize a function %0 within class scope">;
// C++ class template specializations and out-of-line definitions
def err_template_spec_needs_header : Error<
@@ -1777,6 +1872,9 @@ def err_template_recursion_depth_exceeded : Error<
def note_template_recursion_depth : Note<
"use -ftemplate-depth-N to increase recursive template instantiation depth">;
+def err_template_instantiate_within_definition : Error<
+ "%select{implicit|explicit}0 instantiation of template %1 within its"
+ " own definition">;
def err_template_instantiate_undefined : Error<
"%select{implicit|explicit}0 instantiation of undefined template %1">;
def err_implicit_instantiate_member_undefined : Error<
@@ -1900,6 +1998,8 @@ def note_typename_refers_here : Note<
"referenced member %0 is declared here">;
def err_typename_missing : Error<
"missing 'typename' prior to dependent type name '%0%1'">;
+def warn_typename_missing : ExtWarn<
+ "missing 'typename' prior to dependent type name '%0%1'">;
def ext_typename_outside_of_template : ExtWarn<
"'typename' occurs outside of a template">, InGroup<CXX0x>;
def err_typename_refers_to_using_value_decl : Error<
@@ -1921,6 +2021,14 @@ def err_template_kw_missing : Error<
def ext_template_outside_of_template : ExtWarn<
"'template' keyword outside of a template">, InGroup<CXX0x>;
+def err_non_type_template_in_nested_name_specifier : Error<
+ "qualified name refers into a specialization of function template '%0'">;
+def err_template_id_not_a_type : Error<
+ "template name refers to non-type template '%0'">;
+def note_template_declared_here : Note<
+ "%select{function template|class template|template template parameter}0 "
+ "%1 declared here">;
+
// C++0x Variadic Templates
def err_template_param_pack_default_arg : Error<
"template parameter pack cannot have a default argument">;
@@ -2039,6 +2147,8 @@ def err_inline_declaration_block_scope : Error<
"inline declaration of %0 not allowed in block scope">;
def err_static_non_static : Error<
"static declaration of %0 follows non-static declaration">;
+def warn_static_non_static : ExtWarn<
+ "static declaration of %0 follows non-static declaration">;
def err_non_static_static : Error<
"non-static declaration of %0 follows static declaration">;
def err_extern_non_extern : Error<
@@ -2054,17 +2164,17 @@ def err_redefinition_different_type : Error<
def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
def err_redefinition_different_typedef : Error<
- "typedef redefinition with different types (%0 vs %1)">;
+ "%select{typedef|type alias}0 redefinition with different types (%1 vs %2)">;
def err_tag_reference_non_tag : Error<
- "elaborated type refers to %select{a non-tag type|a typedef|a template}0">;
+ "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template}0">;
def err_tag_reference_conflict : Error<
"implicit declaration introduced by elaborated type conflicts with "
- "%select{a declaration|a typedef|a template}0 of the same name">;
+ "%select{a declaration|a typedef|a type alias|a template}0 of the same name">;
def err_dependent_tag_decl : Error<
"%select{declaration|definition}0 of %select{struct|union|class|enum}1 "
"in a dependent scope">;
def err_tag_definition_of_typedef : Error<
- "definition of type %0 conflicts with typedef of the same name">;
+ "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">;
def err_conflicting_types : Error<"conflicting types for %0">;
def err_nested_redefinition : Error<"nested redefinition of %0">;
def err_use_with_wrong_tag : Error<
@@ -2154,6 +2264,8 @@ def err_excess_initializers_in_char_array_initializer : Error<
"excess elements in char array initializer">;
def warn_excess_initializers_in_char_array_initializer : ExtWarn<
"excess elements in char array initializer">;
+def err_initializer_string_for_char_array_too_long : Error<
+ "initializer-string for char array is too long">;
def warn_initializer_string_for_char_array_too_long : ExtWarn<
"initializer-string for char array is too long">;
def warn_missing_field_initializers : Warning<
@@ -2180,6 +2292,8 @@ def err_bitfield_width_exceeds_type_size : Error<
"size of bit-field %0 (%1 bits) exceeds size of its type (%2 bits)">;
def err_anon_bitfield_width_exceeds_type_size : Error<
"size of anonymous bit-field (%0 bits) exceeds size of its type (%1 bits)">;
+def err_incorrect_number_of_vector_initializers : Error<
+ "number of elements must be either one or match the size of the vector">;
// Used by C++ which allows bit-fields that are wider than the type.
def warn_bitfield_width_exceeds_type_size: Warning<
@@ -2212,6 +2326,8 @@ def note_protected_by_cleanup : Note<
"jump bypasses initialization of variable with __attribute__((cleanup))">;
def note_protected_by_vla_typedef : Note<
"jump bypasses initialization of VLA typedef">;
+def note_protected_by_vla_type_alias : Note<
+ "jump bypasses initialization of VLA type alias">;
def note_protected_by_vla : Note<
"jump bypasses initialization of variable length array">;
def note_protected_by_objc_try : Note<
@@ -2266,12 +2382,17 @@ def ext_flexible_array_in_array : Extension<
"%0 may not be used as an array element due to flexible array member">;
def err_flexible_array_init_nonempty : Error<
"non-empty initialization of flexible array member inside subobject">;
-def ext_flexible_array_empty_aggregate : Extension<
+def ext_flexible_array_empty_aggregate_ms : Extension<
"flexible array member %0 in otherwise empty %select{struct|class}1 "
"is a Microsoft extension">, InGroup<Microsoft>;
-def ext_flexible_array_union : Extension<
+def ext_flexible_array_union_ms : Extension<
"flexible array member %0 in a union is a Microsoft extension">,
InGroup<Microsoft>;
+def ext_flexible_array_empty_aggregate_gnu : Extension<
+ "flexible array member %0 in otherwise empty %select{struct|class}1 "
+ "is a GNU extension">, InGroup<GNU>;
+def ext_flexible_array_union_gnu : Extension<
+ "flexible array member %0 in a union is a GNU extension">, InGroup<GNU>;
def err_flexible_array_init_needs_braces : Error<
"flexible array requires brace-enclosed initializer">;
@@ -2314,14 +2435,18 @@ def err_func_def_incomplete_result : Error<
def ext_sizeof_function_type : Extension<
"invalid application of 'sizeof' to a function type">, InGroup<PointerArith>;
def err_sizeof_alignof_overloaded_function_type : Error<
- "invalid application of '%select{sizeof|__alignof}0' to an overloaded "
- "function">;
+ "invalid application of '%select{sizeof|__alignof|vec_step}0' to an "
+ "overloaded function">;
def ext_sizeof_void_type : Extension<
- "invalid application of '%0' to a void type">, InGroup<PointerArith>;
+ "invalid application of '%select{sizeof|__alignof|vec_step}0' to a void "
+ "type">, InGroup<PointerArith>;
def err_sizeof_alignof_incomplete_type : Error<
- "invalid application of '%select{sizeof|__alignof}0' to an incomplete type %1">;
+ "invalid application of '%select{sizeof|__alignof|vec_step}0' to an "
+ "incomplete type %1">;
def err_sizeof_alignof_bitfield : Error<
"invalid application of '%select{sizeof|__alignof}0' to bit-field">;
+def err_vecstep_non_scalar_vector_type : Error<
+ "'vec_step' requires built-in scalar or vector type, %0 invalid">;
def err_offsetof_incomplete_type : Error<
"offsetof of incomplete type %0">;
def err_offsetof_record_type : Error<
@@ -2417,6 +2542,11 @@ def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
def err_no_member : Error<"no member named %0 in %1">;
+def err_member_not_yet_instantiated : Error<
+ "no member %0 in %1; it has not yet been instantiated">;
+def note_non_instantiated_member_here : Note<
+ "not-yet-instantiated member is declared here">;
+
def err_member_redeclared : Error<"class member cannot be redeclared">;
def err_member_name_of_class : Error<"member %0 has the same name as its class">;
def err_member_def_undefined_record : Error<
@@ -2483,6 +2613,7 @@ def err_typecheck_sclass_fscope : Error<
"illegal storage class on file-scoped variable">;
def err_unsupported_global_register : Error<
"global register variables are not supported">;
+def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">;
def err_typecheck_sclass_func : Error<"illegal storage class on function">;
def err_static_block_func : Error<
"function declared in block scope cannot have 'static' storage class">;
@@ -2618,6 +2749,8 @@ def err_ref_array_type : Error<
"cannot refer to declaration with an array type inside block">;
def err_property_not_found : Error<
"property %0 not found on object of type %1">;
+def err_invalid_property_name : Error<
+ "%0 is not a valid property name (accessing an object of type %1)">;
def err_getter_not_found : Error<
"expected getter method not found on object of type %0">;
def err_property_not_found_forward_class : Error<
@@ -2636,6 +2769,8 @@ def ext_gnu_ptr_func_arith : Extension<
InGroup<PointerArith>;
def error_readonly_property_assignment : Error<
"assigning to property with 'readonly' attribute not allowed">;
+def error_readonly_message_assignment : Error<
+ "assigning to 'readonly' return result of an objective-c message not allowed">;
def ext_integer_increment_complex : Extension<
"ISO C does not support '++'/'--' on complex integer type %0">;
def ext_integer_complement_complex : Extension<
@@ -2655,9 +2790,11 @@ def err_imaginary_not_supported : Error<"imaginary types are not supported">;
def warn_root_inst_method_not_found : Warning<
"instance method %0 is being used on 'Class' which is not in the root class">;
def warn_class_method_not_found : Warning<
- "method %objcclass0 not found (return type defaults to 'id')">;
+ "class method %objcclass0 not found (return type defaults to 'id')">;
+def warn_instance_method_on_class_found : Warning<
+ "instance method %0 found instead of class method %1">;
def warn_inst_method_not_found : Warning<
- "method %objcinstance0 not found (return type defaults to 'id')">;
+ "instance method %objcinstance0 not found (return type defaults to 'id')">;
def error_no_super_class_message : Error<
"no @interface declaration found in class messaging of %0">;
def error_root_class_cannot_use_super : Error<
@@ -2735,9 +2872,9 @@ def err_bad_cxx_cast_generic : Error<
def err_bad_cxx_cast_rvalue : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast}0 from rvalue to reference type %2">;
-def err_bad_cxx_cast_const_away : Error<
+def err_bad_cxx_cast_qualifiers_away : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
- "functional-style cast}0 from %1 to %2 casts away constness">;
+ "functional-style cast}0 from %1 to %2 casts away qualifiers">;
def err_bad_const_cast_dest : Error<
"%select{const_cast||||C-style cast|functional-style cast}0 to %2, "
"which is not a reference, pointer-to-object, or pointer-to-data-member">;
@@ -2765,6 +2902,8 @@ def err_bad_cxx_cast_member_pointer_size : Error<
"cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer "
"type %1 to member pointer type %2 of different size">;
def err_bad_static_cast_incomplete : Error<"%0 is an incomplete type">;
+def err_bad_reinterpret_cast_reference : Error<
+ "reinterpret_cast of a %0 to %1 needs its address which is not allowed">;
// These messages don't adhere to the pattern.
// FIXME: Display the path somehow better.
@@ -2823,7 +2962,11 @@ def ext_array_size_conversion : Extension<
"implicit conversion from array size expression of type %0 to "
"%select{integral|enumeration}1 type %2 is a C++0x extension">,
InGroup<CXX0x>;
-
+def err_address_space_qualified_new : Error<
+ "'new' cannot allocate objects of type %0 in address space '%1'">;
+def err_address_space_qualified_delete : Error<
+ "'delete' cannot delete objects of type %0 in address space '%1'">;
+
def err_default_init_const : Error<
"default initialization of an object of const type %0"
"%select{| requires a user-provided default constructor}1">;
@@ -2878,6 +3021,9 @@ def warn_overloaded_virtual : Warning<
InGroup<OverloadedVirtual>, DefaultIgnore;
def note_hidden_overloaded_virtual_declared_here : Note<
"hidden overloaded virtual function %q0 declared here">;
+def warn_using_directive_in_header : Warning<
+ "using namespace directive in global context in header">,
+ InGroup<HeaderHygiene>, DefaultIgnore;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
@@ -3067,11 +3213,6 @@ def err_typecheck_incompatible_address_space : Error<
" changes address space of pointer">;
def err_typecheck_convert_ambiguous : Error<
"ambiguity in initializing value of type %0 with initializer of type %1">;
-def err_cannot_initialize_decl_noname : Error<
- "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 "
- "of type %2">;
-def err_cannot_initialize_decl : Error<
- "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">;
def err_typecheck_comparison_of_distinct_blocks : Error<
"comparison of distinct block types (%0 and %1)">;
@@ -3109,6 +3250,8 @@ def err_typecheck_call_too_few_args_at_least : Error<
def err_typecheck_call_too_many_args : Error<
"too many arguments to %select{function|block|method}0 call, "
"expected %1, have %2">;
+def note_typecheck_call_too_many_args : Note<
+ "%0 declared here">;
def err_typecheck_call_too_many_args_at_most : Error<
"too many arguments to %select{function|block|method}0 call, "
"expected at most %1, have %2">;
@@ -3196,6 +3339,8 @@ def warn_unused_call : Warning<
def err_incomplete_type_used_in_type_trait_expr : Error<
"incomplete type %0 used in type trait expression">;
+def err_dimension_expr_not_constant_integer : Error<
+ "dimension expression does not evaluate to a constant unsigned int">;
def err_expected_ident_or_lparen : Error<"expected identifier or '('">;
def err_typecheck_cond_incompatible_operands_null : Error<
@@ -3278,7 +3423,7 @@ def err_in_class_initializer_bad_type : Error<
"static data member of type %0 must be initialized out of line">;
def ext_in_class_initializer_float_type : ExtWarn<
"in-class initializer for static data member of type %0 "
- "is a C++0x extension">, InGroup<CXX0x>;
+ "is a C++0x extension">, InGroup<CXX0xStaticNonIntegralInitializer>;
def err_in_class_initializer_non_constant : Error<
"in-class initializer is not a constant expression">;
@@ -3544,6 +3689,21 @@ def warn_stringcompare : Warning<
"result of comparison against %select{a string literal|@encode}0 is "
"unspecified (use strncmp instead)">;
+// Generic selections.
+def err_assoc_type_incomplete : Error<
+ "type %0 in generic association incomplete">;
+def err_assoc_type_nonobject : Error<
+ "type %0 in generic association not an object type">;
+def err_assoc_type_variably_modified : Error<
+ "type %0 in generic association is a variably modified type">;
+def err_assoc_compatible_types : Error<
+ "type %0 in generic association compatible with previously specified type %1">;
+def note_compat_assoc : Note<
+ "compatible type %0 specified here">;
+def err_generic_sel_no_match : Error<
+ "controlling expression type %0 not compatible with any generic association type">;
+def err_generic_sel_multi_match : Error<
+ "controlling expression type %0 compatible with %1 generic association types">;
// Blocks
@@ -3559,8 +3719,6 @@ def err_block_returning_array_function : Error<
// CFString checking
def err_cfstring_literal_not_string_constant : Error<
"CFString literal is not a string constant">;
-def warn_cfstring_literal_contains_nul_character : Warning<
- "CFString literal contains NUL character">;
def warn_cfstring_truncated : Warning<
"input conversion stopped due to an input byte that does not "
"belong to the input codeset UTF-8">;
@@ -3722,6 +3880,8 @@ def warn_ivar_use_hidden : Warning<
"local declaration of %0 hides instance variable">;
def error_ivar_use_in_class_method : Error<
"instance variable %0 accessed in class method">;
+def error_implicit_ivar_access : Error<
+ "instance variable %0 cannot be accessed because 'self' has been redeclared">;
def error_private_ivar_access : Error<"instance variable %0 is private">,
AccessControl;
def error_protected_ivar_access : Error<"instance variable %0 is protected">,
@@ -3776,6 +3936,26 @@ def err_sizeof_pack_no_pack_name_suggest : Error<
"%0 does not refer to the name of a parameter pack; did you mean %1?">;
def note_parameter_pack_here : Note<"parameter pack %0 declared here">;
+def err_uncasted_use_of_unknown_any : Error<
+ "%0 has unknown type; cast it to its declared type to use it">;
+def err_uncasted_call_of_unknown_any : Error<
+ "%0 has unknown return type; cast the call to its declared return type">;
+def err_unsupported_unknown_any_decl : Error<
+ "%0 has unknown type, which is unsupported for this kind of declaration">;
+def err_unsupported_unknown_any_expr : Error<
+ "unsupported expression with unknown type">;
+def err_unsupported_unknown_any_call : Error<
+ "call to unsupported expression with unknown type">;
+def err_unknown_any_addrof : Error<
+ "the address of a declaration with unknown type "
+ "can only be cast to a pointer type">;
+def err_unknown_any_var_function_type : Error<
+ "variable %0 with unknown type cannot be given a function type">;
+
+def err_filter_expression_integral : Error<
+ "filter expression type should be an integral value not %0">;
+
} // end of sema category
+
} // end of sema component.
diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h
new file mode 100644
index 000000000000..aecf6eb269b7
--- /dev/null
+++ b/include/clang/Basic/ExceptionSpecificationType.h
@@ -0,0 +1,39 @@
+//===--- ExceptionSpecificationType.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ExceptionSpecificationType enumeration and various
+// utility functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H
+#define LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H
+
+namespace clang {
+
+/// \brief The various types of exception specifications that exist in C++0x.
+enum ExceptionSpecificationType {
+ EST_None, ///< no exception specification
+ EST_DynamicNone, ///< throw()
+ EST_Dynamic, ///< throw(T1, T2)
+ EST_MSAny, ///< Microsoft throw(...) extension
+ EST_BasicNoexcept, ///< noexcept
+ EST_ComputedNoexcept ///< noexcept(expression)
+};
+
+inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
+ return ESpecType >= EST_DynamicNone && ESpecType <= EST_MSAny;
+}
+
+inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) {
+ return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept;
+}
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H
diff --git a/include/clang/Basic/ExpressionTraits.h b/include/clang/Basic/ExpressionTraits.h
new file mode 100644
index 000000000000..403a59a8d19c
--- /dev/null
+++ b/include/clang/Basic/ExpressionTraits.h
@@ -0,0 +1,25 @@
+//===--- ExpressionTraits.h - C++ Expression Traits Support Enumerations ----*- 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 enumerations for expression traits intrinsics.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_EXPRESSIONTRAITS_H
+#define LLVM_CLANG_EXPRESSIONTRAITS_H
+
+namespace clang {
+
+ enum ExpressionTrait {
+ ET_IsLValueExpr,
+ ET_IsRValueExpr
+ };
+}
+
+#endif
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index 563157fa8fbe..2ca344d55370 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_FILEMANAGER_H
#include "clang/Basic/FileSystemOptions.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -105,7 +106,7 @@ public:
/// properties, such as uniquing files based on "inode", so that a file with two
/// names (e.g. symlinked) will be treated as a single file.
///
-class FileManager {
+class FileManager : public llvm::RefCountedBase<FileManager> {
FileSystemOptions FileSystemOpts;
class UniqueDirContainer;
@@ -176,10 +177,11 @@ public:
///
const DirectoryEntry *getDirectory(llvm::StringRef DirName);
- /// getFile - Lookup, cache, and verify the specified file (real or
+ /// \brief Lookup, cache, and verify the specified file (real or
/// virtual). This returns NULL if the file doesn't exist.
///
- const FileEntry *getFile(llvm::StringRef Filename);
+ /// \param openFile if true and the file exists, it will be opened.
+ const FileEntry *getFile(llvm::StringRef Filename, bool openFile = false);
/// \brief Retrieve a file entry for a "virtual" file that acts as
/// if there were a file with the given name on disk. The file
@@ -194,13 +196,16 @@ public:
llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename,
std::string *ErrorStr = 0);
+ // getNoncachedStatValue - Will get the 'stat' information for the given path.
+ // If the path is relative, it will be resolved against the WorkingDir of the
+ // FileManager's FileSystemOptions.
+ bool getNoncachedStatValue(llvm::StringRef Path, struct stat &StatBuf);
+
/// \brief If path is not absolute and FileSystemOptions set the working
/// directory, the path is modified to be relative to the given
/// working directory.
- static void FixupRelativePath(llvm::sys::Path &path,
- const FileSystemOptions &FSOpts);
+ void FixupRelativePath(llvm::SmallVectorImpl<char> &path) const;
-
/// \brief Produce an array mapping from the unique IDs assigned to each
/// file to the corresponding FileEntry pointer.
void GetUniqueIDMapping(
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index d576643550bd..683ec8312e91 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -255,6 +255,25 @@ private:
}
};
+/// \brief an RAII object for [un]poisoning an identifier
+/// within a certain scope. II is allowed to be null, in
+/// which case, objects of this type have no effect.
+class PoisonIdentifierRAIIObject {
+ IdentifierInfo *const II;
+ const bool OldValue;
+public:
+ PoisonIdentifierRAIIObject(IdentifierInfo *II, bool NewValue)
+ : II(II), OldValue(II ? II->isPoisoned() : false) {
+ if(II)
+ II->setIsPoisoned(NewValue);
+ }
+
+ ~PoisonIdentifierRAIIObject() {
+ if(II)
+ II->setIsPoisoned(OldValue);
+ }
+};
+
/// \brief An iterator that walks over all of the known identifiers
/// in the lookup table.
///
@@ -325,7 +344,7 @@ public:
/// IdentifierTable - This table implements an efficient mapping from strings to
/// IdentifierInfo nodes. It has no other purpose, but this is an
-/// extremely performance-critical piece of the code, as each occurrance of
+/// extremely performance-critical piece of the code, as each occurrence of
/// every identifier goes through here when lexed.
class IdentifierTable {
// Shark shows that using MallocAllocator is *much* slower than using this
@@ -443,6 +462,52 @@ public:
void AddKeywords(const LangOptions &LangOpts);
};
+/// ObjCMethodFamily - A family of Objective-C methods. These
+/// families have no inherent meaning in the language, but are
+/// nonetheless central enough in the existing implementations to
+/// merit direct AST support. While, in theory, arbitrary methods can
+/// be considered to form families, we focus here on the methods
+/// involving allocation and retain-count management, as these are the
+/// most "core" and the most likely to be useful to diverse clients
+/// without extra information.
+///
+/// Both selectors and actual method declarations may be classified
+/// into families. Method families may impose additional restrictions
+/// beyond their selector name; for example, a method called '_init'
+/// that returns void is not considered to be in the 'init' family
+/// (but would be if it returned 'id'). It is also possible to
+/// explicitly change or remove a method's family. Therefore the
+/// method's family should be considered the single source of truth.
+enum ObjCMethodFamily {
+ /// \brief No particular method family.
+ OMF_None,
+
+ // Selectors in these families may have arbitrary arity, may be
+ // written with arbitrary leading underscores, and may have
+ // additional CamelCase "words" in their first selector chunk
+ // following the family name.
+ OMF_alloc,
+ OMF_copy,
+ OMF_init,
+ OMF_mutableCopy,
+ OMF_new,
+
+ // These families are singletons consisting only of the nullary
+ // selector with the given name.
+ OMF_autorelease,
+ OMF_dealloc,
+ OMF_release,
+ OMF_retain,
+ OMF_retainCount
+};
+
+/// Enough bits to store any enumerator in ObjCMethodFamily or
+/// InvalidObjCMethodFamily.
+enum { ObjCMethodFamilyBitWidth = 4 };
+
+/// An invalid value of ObjCMethodFamily.
+enum { InvalidObjCMethodFamily = (1 << ObjCMethodFamilyBitWidth) - 1 };
+
/// Selector - This smart pointer class efficiently represents Objective-C
/// method names. This class will either point to an IdentifierInfo or a
/// MultiKeywordSelector (which is private). This enables us to optimize
@@ -479,6 +544,8 @@ class Selector {
return InfoPtr & ArgFlags;
}
+ static ObjCMethodFamily getMethodFamilyImpl(Selector sel);
+
public:
friend class SelectorTable; // only the SelectorTable can create these
friend class DeclarationName; // and the AST's DeclarationName.
@@ -541,6 +608,11 @@ public:
/// it as an std::string.
std::string getAsString() const;
+ /// getMethodFamily - Derive the conventional family of this method.
+ ObjCMethodFamily getMethodFamily() const {
+ return getMethodFamilyImpl(*this);
+ }
+
static Selector getEmptyMarker() {
return Selector(uintptr_t(-1));
}
@@ -571,6 +643,9 @@ public:
return Selector(ID, 0);
}
+ /// Return the total amount of memory allocated for managing selectors.
+ size_t getTotalMemory() const;
+
/// constructSetterName - Return the setter name for the given
/// identifier, i.e. "set" + Name where the initial character of Name
/// has been capitalized.
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 0bd983e8e6c6..a5f6789b7d1f 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -34,6 +34,7 @@ public:
unsigned Digraphs : 1; // C94, C99 and C++
unsigned HexFloats : 1; // C99 Hexadecimal float constants.
unsigned C99 : 1; // C99 Support
+ unsigned C1X : 1; // C1X Support
unsigned Microsoft : 1; // Microsoft extensions.
unsigned Borland : 1; // Borland extensions.
unsigned CPlusPlus : 1; // C++ Support
@@ -56,6 +57,7 @@ public:
unsigned ObjCExceptions : 1; // Support Objective-C exceptions.
unsigned CXXExceptions : 1; // Support C++ exceptions.
unsigned SjLjExceptions : 1; // Use setjmp-longjump exception handling.
+ unsigned TraditionalCPP : 1; /// Enable some traditional CPP emulation.
unsigned RTTI : 1; // Support RTTI information.
unsigned MSBitfields : 1; // MS-compatible structure layout
@@ -87,6 +89,8 @@ public:
// used (instead of C99 semantics).
unsigned NoInline : 1; // Should __NO_INLINE__ be defined.
+ unsigned Deprecated : 1; // Should __DEPRECATED be defined.
+
unsigned ObjCGCBitmapPrint : 1; // Enable printing of gc's bitmap layout
// for __weak/__strong ivars.
@@ -112,6 +116,7 @@ public:
unsigned NoConstantCFStrings : 1; // Do not do CF strings
unsigned InlineVisibilityHidden : 1; // Whether inline C++ methods have
// hidden visibility by default.
+ unsigned ParseUnknownAnytype: 1; /// Let the user write __unknown_anytype.
unsigned SpellChecking : 1; // Whether to perform spell-checking for error
// recovery.
@@ -123,6 +128,11 @@ public:
unsigned DefaultFPContract : 1; // Default setting for FP_CONTRACT
// FIXME: This is just a temporary option, for testing purposes.
unsigned NoBitFieldTypeAlign : 1;
+ unsigned FakeAddressSpaceMap : 1; // Use a fake address space map, for
+ // testing languages such as OpenCL.
+
+ unsigned MRTD : 1; // -mrtd calling convention
+ unsigned DelayedTemplateParsing : 1; // Delayed template parsing
private:
// We declare multibit enums as unsigned because MSVC insists on making enums
@@ -164,10 +174,10 @@ public:
AppleKext = 0;
ObjCDefaultSynthProperties = 0;
NoConstantCFStrings = 0; InlineVisibilityHidden = 0;
- C99 = Microsoft = Borland = CPlusPlus = CPlusPlus0x = 0;
+ C99 = C1X = Microsoft = Borland = CPlusPlus = CPlusPlus0x = 0;
CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0;
Exceptions = ObjCExceptions = CXXExceptions = SjLjExceptions = 0;
- Freestanding = NoBuiltin = 0;
+ TraditionalCPP = Freestanding = NoBuiltin = 0;
MSBitfields = 0;
NeXTRuntime = 1;
RTTI = 1;
@@ -205,6 +215,8 @@ public:
GNUInline = 0;
NoInline = 0;
+ Deprecated = 0;
+
CharIsSigned = 1;
ShortWChar = 0;
ShortEnums = 0;
@@ -216,6 +228,10 @@ public:
FastRelaxedMath = 0;
DefaultFPContract = 0;
NoBitFieldTypeAlign = 0;
+ FakeAddressSpaceMap = 0;
+ MRTD = 0;
+ DelayedTemplateParsing = 0;
+ ParseUnknownAnytype = 0;
}
GCMode getGCMode() const { return (GCMode) GC; }
@@ -240,8 +256,8 @@ public:
SignedOverflowBehavior = (unsigned)V;
}
- bool areExceptionsEnabled() const {
- return Exceptions;
+ bool isSignedOverflowDefined() const {
+ return getSignedOverflowBehavior() == SOB_Defined;
}
};
diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile
index bc64f6aab555..1338464fd5d9 100644
--- a/include/clang/Basic/Makefile
+++ b/include/clang/Basic/Makefile
@@ -4,7 +4,7 @@ BUILT_SOURCES = \
DiagnosticCommonKinds.inc DiagnosticDriverKinds.inc \
DiagnosticFrontendKinds.inc DiagnosticLexKinds.inc \
DiagnosticParseKinds.inc DiagnosticSemaKinds.inc \
- DiagnosticGroups.inc AttrList.inc arm_neon.inc \
+ DiagnosticIndexName.inc DiagnosticGroups.inc AttrList.inc arm_neon.inc \
Version.inc
TABLEGEN_INC_FILES_COMMON = 1
@@ -33,6 +33,10 @@ $(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td Diagnostic%Kinds.td $(TBLGEN)
$(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen"
$(Verb) $(TableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $<
+$(ObjDir)/DiagnosticIndexName.inc.tmp : Diagnostic.td $(INPUT_TDS) $(TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang diagnostic name index with tblgen"
+ $(Verb) $(TableGen) -gen-clang-diags-index-name -o $(call SYSPATH, $@) $<
+
$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.td $(INPUT_TDS) $(TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang diagnostic groups with tblgen"
$(Verb) $(TableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $<
diff --git a/include/clang/Basic/OpenCL.h b/include/clang/Basic/OpenCL.h
new file mode 100644
index 000000000000..6f9785f25677
--- /dev/null
+++ b/include/clang/Basic/OpenCL.h
@@ -0,0 +1,28 @@
+//===--- OpenCL.h - OpenCL enums --------------------------------*- 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 some OpenCL-specific enums.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_OPENCL_H
+#define LLVM_CLANG_BASIC_OPENCL_H
+
+namespace clang {
+
+/// Names for the OpenCL image access qualifiers (OpenCL 1.1 6.6).
+enum OpenCLImageAccess {
+ CLIA_read_only = 1,
+ CLIA_write_only = 2,
+ CLIA_read_write = 3
+};
+
+}
+
+#endif
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index c63619440551..7d7c0896f505 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -53,7 +53,7 @@ public:
/// DiagArgumentsVal - The values for the various substitution positions.
/// This is used when the argument is not an std::string. The specific value
- /// is mangled into an intptr_t and the intepretation depends on exactly
+ /// is mangled into an intptr_t and the interpretation depends on exactly
/// what sort of argument kind it is.
intptr_t DiagArgumentsVal[MaxArguments];
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 605c4bbafc74..14bb2b724fd4 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -16,6 +16,7 @@
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <utility>
+#include <functional>
#include <cassert>
namespace llvm {
@@ -295,6 +296,14 @@ public:
return isBeforeInTranslationUnitThan((SourceLocation)Loc);
}
+ /// \brief Comparison function class, useful for sorting FullSourceLocs.
+ struct BeforeThanCompare : public std::binary_function<FullSourceLoc,
+ FullSourceLoc, bool> {
+ bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const {
+ return lhs.isBeforeInTranslationUnitThan(rhs);
+ }
+ };
+
/// Prints information about this FullSourceLoc to stderr. Useful for
/// debugging.
void dump() const { SourceLocation::dump(*SrcMgr); }
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index b1443dad09fd..c121bbb34f34 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -19,12 +19,13 @@
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/MemoryBuffer.h"
#include <vector>
#include <cassert>
namespace llvm {
-class MemoryBuffer;
class StringRef;
}
@@ -66,10 +67,16 @@ namespace SrcMgr {
mutable llvm::PointerIntPair<const llvm::MemoryBuffer *, 2> Buffer;
public:
- /// Reference to the file entry. This reference does not own
- /// the FileEntry object. It is possible for this to be NULL if
+ /// Reference to the file entry representing this ContentCache.
+ /// This reference does not own the FileEntry object.
+ /// It is possible for this to be NULL if
/// the ContentCache encapsulates an imaginary text buffer.
- const FileEntry *Entry;
+ const FileEntry *OrigEntry;
+
+ /// \brief References the file which the contents were actually loaded from.
+ /// Can be different from 'Entry' if we overridden the contents of one file
+ /// with the contents of another file.
+ const FileEntry *ContentsEntry;
/// SourceLineCache - A bump pointer allocated array of offsets for each
/// source line. This is lazily computed. This is owned by the
@@ -104,6 +111,10 @@ namespace SrcMgr {
/// this ContentCache. This can be 0 if the MemBuffer was not actually
/// instantiated.
unsigned getSizeBytesMapped() const;
+
+ /// Returns the kind of memory used to back the memory buffer for
+ /// this content cache. This is used for performance analysis.
+ llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const;
void setBuffer(const llvm::MemoryBuffer *B) {
assert(!Buffer.getPointer() && "MemoryBuffer already set.");
@@ -132,17 +143,23 @@ namespace SrcMgr {
}
ContentCache(const FileEntry *Ent = 0)
- : Buffer(0, false), Entry(Ent), SourceLineCache(0), NumLines(0) {}
+ : Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent),
+ SourceLineCache(0), NumLines(0) {}
+
+ ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
+ : Buffer(0, false), OrigEntry(Ent), ContentsEntry(contentEnt),
+ SourceLineCache(0), NumLines(0) {}
~ContentCache();
/// The copy ctor does not allow copies where source object has either
/// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
- /// is not transfered, so this is a logical error.
+ /// is not transferred, so this is a logical error.
ContentCache(const ContentCache &RHS)
: Buffer(0, false), SourceLineCache(0)
{
- Entry = RHS.Entry;
+ OrigEntry = RHS.OrigEntry;
+ ContentsEntry = RHS.ContentsEntry;
assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0
&& "Passed ContentCache object cannot own a buffer.");
@@ -301,7 +318,10 @@ public:
virtual ~ExternalSLocEntrySource();
/// \brief Read the source location entry with index ID.
- virtual void ReadSLocEntry(unsigned ID) = 0;
+ ///
+ /// \returns true if an error occurred that prevented the source-location
+ /// entry from being loaded.
+ virtual bool ReadSLocEntry(unsigned ID) = 0;
};
@@ -364,9 +384,9 @@ public:
/// Spelling locations represent where the bytes corresponding to a token came
/// from and instantiation locations represent where the location is in the
/// user's view. In the case of a macro expansion, for example, the spelling
-/// location indicates where the expanded token came from and the instantiation
+/// location indicates where the expanded token came from and the instantiation
/// location specifies where it was expanded.
-class SourceManager {
+class SourceManager : public llvm::RefCountedBase<SourceManager> {
/// \brief Diagnostic object.
Diagnostic &Diag;
@@ -380,6 +400,13 @@ class SourceManager {
/// non-null, FileEntry pointers.
llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos;
+ /// \brief True if the ContentCache for files that are overriden by other
+ /// files, should report the original file name. Defaults to true.
+ bool OverridenFilesKeepOriginalName;
+
+ /// \brief Files that have been overriden with the contents from another file.
+ llvm::DenseMap<const FileEntry *, const FileEntry *> OverriddenFiles;
+
/// MemBufferInfos - Information about various memory buffers that we have
/// read in. All FileEntry* within the stored ContentCache objects are NULL,
/// as they do not refer to a file.
@@ -425,6 +452,9 @@ class SourceManager {
// Cache results for the isBeforeInTranslationUnit method.
mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache;
+ // Cache for the "fake" buffer used for error-recovery purposes.
+ mutable llvm::MemoryBuffer *FakeBufferForRecovery;
+
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&);
void operator=(const SourceManager&);
@@ -438,6 +468,12 @@ public:
FileManager &getFileManager() const { return FileMgr; }
+ /// \brief Set true if the SourceManager should report the original file name
+ /// for contents of files that were overriden by other files.Defaults to true.
+ void setOverridenFilesKeepOriginalName(bool value) {
+ OverridenFilesKeepOriginalName = value;
+ }
+
//===--------------------------------------------------------------------===//
// MainFileID creation and querying methods.
//===--------------------------------------------------------------------===//
@@ -527,6 +563,15 @@ public:
const llvm::MemoryBuffer *Buffer,
bool DoNotFree = false);
+ /// \brief Override the the given source file with another one.
+ ///
+ /// \param SourceFile the source file which will be overriden.
+ ///
+ /// \param NewFile the file whose contents will be used as the
+ /// data instead of the contents of the given source file.
+ void overrideFileContents(const FileEntry *SourceFile,
+ const FileEntry *NewFile);
+
//===--------------------------------------------------------------------===//
// FileID manipulation methods.
//===--------------------------------------------------------------------===//
@@ -536,18 +581,48 @@ public:
/// buffer and returns a non-empty error string.
const llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc,
bool *Invalid = 0) const {
- return getSLocEntry(FID).getFile().getContentCache()
- ->getBuffer(Diag, *this, Loc, Invalid);
+ bool MyInvalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+ if (MyInvalid || !Entry.isFile()) {
+ if (Invalid)
+ *Invalid = true;
+
+ return getFakeBufferForRecovery();
+ }
+
+ return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc,
+ Invalid);
}
const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const {
- return getSLocEntry(FID).getFile().getContentCache()
- ->getBuffer(Diag, *this, SourceLocation(), Invalid);
+ bool MyInvalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+ if (MyInvalid || !Entry.isFile()) {
+ if (Invalid)
+ *Invalid = true;
+
+ return getFakeBufferForRecovery();
+ }
+
+ return Entry.getFile().getContentCache()->getBuffer(Diag, *this,
+ SourceLocation(),
+ Invalid);
}
/// getFileEntryForID - Returns the FileEntry record for the provided FileID.
const FileEntry *getFileEntryForID(FileID FID) const {
- return getSLocEntry(FID).getFile().getContentCache()->Entry;
+ bool MyInvalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+ if (MyInvalid || !Entry.isFile())
+ return 0;
+
+ return Entry.getFile().getContentCache()->OrigEntry;
+ }
+
+ /// Returns the FileEntry record for the provided SLocEntry.
+ const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const
+ {
+ return sloc.getFile().getContentCache()->OrigEntry;
}
/// getBufferData - Return a StringRef to the source buffer data for the
@@ -581,8 +656,12 @@ public:
/// first byte of the specified file.
SourceLocation getLocForStartOfFile(FileID FID) const {
assert(FID.ID < SLocEntryTable.size() && "FileID out of range");
- assert(getSLocEntry(FID).isFile() && "FileID is not a file");
- unsigned FileOffset = getSLocEntry(FID).getOffset();
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return SourceLocation();
+
+ unsigned FileOffset = Entry.getOffset();
return SourceLocation::getFileLoc(FileOffset);
}
@@ -775,6 +854,28 @@ public:
LineTableInfo &getLineTable();
//===--------------------------------------------------------------------===//
+ // Queries for performance analysis.
+ //===--------------------------------------------------------------------===//
+
+ /// Return the total amount of physical memory allocated by the
+ /// ContentCache allocator.
+ size_t getContentCacheSize() const {
+ return ContentCacheAlloc.getTotalMemory();
+ }
+
+ struct MemoryBufferSizes {
+ const size_t malloc_bytes;
+ const size_t mmap_bytes;
+
+ MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
+ : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
+ };
+
+ /// Return the amount of memory used by memory buffers, breaking down
+ /// by heap-backed versus mmap'ed memory.
+ MemoryBufferSizes getMemoryBufferSizes() const;
+
+ //===--------------------------------------------------------------------===//
// Other miscellaneous methods.
//===--------------------------------------------------------------------===//
@@ -810,17 +911,22 @@ public:
// any other external source).
unsigned sloc_loaded_entry_size() const { return SLocEntryLoaded.size(); }
- const SrcMgr::SLocEntry &getSLocEntry(unsigned ID) const {
+ const SrcMgr::SLocEntry &getSLocEntry(unsigned ID, bool *Invalid = 0) const {
assert(ID < SLocEntryTable.size() && "Invalid id");
+ // If we haven't loaded this source-location entry from the external source
+ // yet, do so now.
if (ExternalSLocEntries &&
ID < SLocEntryLoaded.size() &&
- !SLocEntryLoaded[ID])
- ExternalSLocEntries->ReadSLocEntry(ID);
+ !SLocEntryLoaded[ID] &&
+ ExternalSLocEntries->ReadSLocEntry(ID) &&
+ Invalid)
+ *Invalid = true;
+
return SLocEntryTable[ID];
}
- const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const {
- return getSLocEntry(FID.ID);
+ const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
+ return getSLocEntry(FID.ID, Invalid);
}
unsigned getNextOffset() const { return NextOffset; }
@@ -836,6 +942,8 @@ public:
void ClearPreallocatedSLocEntries();
private:
+ const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
+
/// isOffsetInFileID - Return true if the specified FileID contains the
/// specified SourceLocation offset. This is a very hot method.
inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const {
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index e6b6218100ad..2f0ad9ffb688 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -55,6 +55,7 @@ namespace clang {
TST_typeofExpr,
TST_decltype, // C++0x decltype
TST_auto, // C++0x auto
+ TST_unknown_anytype, // __unknown_anytype extension
TST_error // erroneous type
};
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index be0d8ff091e8..15ac760ce725 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -41,6 +41,7 @@ def ObjCForCollectionStmt : Stmt;
// C++ statments
def CXXCatchStmt : Stmt;
def CXXTryStmt : Stmt;
+def CXXForRangeStmt : Stmt;
// Expressions
def Expr : Stmt<1>;
@@ -54,7 +55,7 @@ def CharacterLiteral : DStmt<Expr>;
def ParenExpr : DStmt<Expr>;
def UnaryOperator : DStmt<Expr>;
def OffsetOfExpr : DStmt<Expr>;
-def SizeOfAlignOfExpr : DStmt<Expr>;
+def UnaryExprOrTypeTraitExpr : DStmt<Expr>;
def ArraySubscriptExpr : DStmt<Expr>;
def CallExpr : DStmt<Expr>;
def MemberExpr : DStmt<Expr>;
@@ -74,6 +75,7 @@ def DesignatedInitExpr : DStmt<Expr>;
def ImplicitValueInitExpr : DStmt<Expr>;
def ParenListExpr : DStmt<Expr>;
def VAArgExpr : DStmt<Expr>;
+def GenericSelectionExpr : DStmt<Expr>;
// GNU Extensions.
def AddrLabelExpr : DStmt<Expr>;
@@ -102,6 +104,8 @@ def CXXDeleteExpr : DStmt<Expr>;
def CXXPseudoDestructorExpr : DStmt<Expr>;
def UnaryTypeTraitExpr : DStmt<Expr>;
def BinaryTypeTraitExpr : DStmt<Expr>;
+def ArrayTypeTraitExpr : DStmt<Expr>;
+def ExpressionTraitExpr : DStmt<Expr>;
def DependentScopeDeclRefExpr : DStmt<Expr>;
def CXXConstructExpr : DStmt<Expr>;
def CXXBindTemporaryExpr : DStmt<Expr>;
@@ -138,4 +142,7 @@ def OpaqueValueExpr : DStmt<Expr>;
// Microsoft Extensions.
def CXXUuidofExpr : DStmt<Expr>;
+def SEHTryStmt : Stmt;
+def SEHExceptStmt : Stmt;
+def SEHFinallyStmt : Stmt;
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index f1edd1d45162..8bc60ff5386d 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -35,6 +35,17 @@ namespace clang {
};
}
+ /// PTX builtins
+ namespace PTX {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsPTX.def"
+ LastTSBuiltin
+ };
+ }
+
+
/// X86 builtins
namespace X86 {
enum {
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index b9087f2c47e8..b830bf2f82cd 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -14,18 +14,20 @@
#ifndef LLVM_CLANG_BASIC_TARGETINFO_H
#define LLVM_CLANG_BASIC_TARGETINFO_H
-// FIXME: Daniel isn't smart enough to use a prototype for this.
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/DataTypes.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/VersionTuple.h"
#include <cassert>
#include <vector>
#include <string>
namespace llvm {
struct fltSemantics;
-class StringRef;
}
namespace clang {
@@ -56,7 +58,7 @@ enum TargetCXXABI {
/// TargetInfo - This class exposes information about the current target.
///
-class TargetInfo {
+class TargetInfo : public llvm::RefCountedBase<TargetInfo> {
llvm::Triple Triple;
protected:
// Target values set by the ctor of the actual target implementation. Default
@@ -78,6 +80,10 @@ protected:
const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat;
unsigned char RegParmMax, SSERegParmMax;
TargetCXXABI CXXABI;
+ const LangAS::Map *AddrSpaceMap;
+
+ mutable llvm::StringRef PlatformName;
+ mutable VersionTuple PlatformMinVersion;
unsigned HasAlignMac68kSupport : 1;
unsigned RealTypeUsesObjCFPRet : 3;
@@ -530,6 +536,19 @@ public:
virtual const char *getStaticInitSectionSpecifier() const {
return 0;
}
+
+ const LangAS::Map &getAddressSpaceMap() const {
+ return *AddrSpaceMap;
+ }
+
+ /// \brief Retrieve the name of the platform as it is used in the
+ /// availability attribute.
+ llvm::StringRef getPlatformName() const { return PlatformName; }
+
+ /// \brief Retrieve the minimum desired version of the platform, to
+ /// which the program should be compiled.
+ VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; }
+
protected:
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const {
return PointerWidth;
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index b84b04da3de2..f9d1f4ef158e 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -38,6 +38,9 @@
#ifndef OBJC2_AT_KEYWORD
#define OBJC2_AT_KEYWORD(X)
#endif
+#ifndef TESTING_KEYWORD
+#define TESTING_KEYWORD(X, L) KEYWORD(X, L)
+#endif
#ifndef ANNOTATION
#define ANNOTATION(X) TOK(annot_ ## X)
#endif
@@ -94,7 +97,8 @@ PPKEYWORD(unassert)
TOK(unknown) // Not a token.
TOK(eof) // End of file.
-TOK(eom) // End of macro (end of line inside a macro).
+TOK(eod) // End of preprocessing directive (end of line inside a
+ // directive).
TOK(code_completion) // Code completion marker
TOK(cxx_defaultarg_end) // C++ default argument end marker
@@ -186,6 +190,7 @@ PUNCTUATOR(greatergreatergreater, ">>>")
// is a keyword in the implementation namespace that should
// always be treated as a keyword
// KEYC99 - This is a keyword introduced to C in C99
+// KEYC1X - This is a keyword introduced to C in C1X
// KEYCXX - This is a C++ keyword, or a C++-specific keyword in the
// implementation namespace
// KEYNOCXX - This is a keyword in every non-C++ dialect.
@@ -195,6 +200,7 @@ PUNCTUATOR(greatergreatergreater, ">>>")
// KEYOPENCL - This is a keyword in OpenCL
// KEYALTIVEC - This is a keyword in AltiVec
// KEYBORLAND - This is a keyword if Borland extensions are enabled
+// BOOLSUPPORT - This is a keyword if 'bool' is a built-in type
//
KEYWORD(auto , KEYALL)
KEYWORD(break , KEYALL)
@@ -232,7 +238,9 @@ KEYWORD(volatile , KEYALL)
KEYWORD(while , KEYALL)
KEYWORD(_Bool , KEYNOCXX)
KEYWORD(_Complex , KEYALL)
+KEYWORD(_Generic , KEYALL)
KEYWORD(_Imaginary , KEYALL)
+KEYWORD(_Static_assert , KEYALL)
KEYWORD(__func__ , KEYALL)
// C++ 2.11p1: Keywords.
@@ -251,7 +259,7 @@ KEYWORD(mutable , KEYCXX)
KEYWORD(namespace , KEYCXX)
KEYWORD(new , KEYCXX)
KEYWORD(operator , KEYCXX)
-KEYWORD(private , KEYCXX)
+KEYWORD(private , KEYCXX|KEYOPENCL)
KEYWORD(protected , KEYCXX)
KEYWORD(public , KEYCXX)
KEYWORD(reinterpret_cast , KEYCXX)
@@ -328,11 +336,50 @@ KEYWORD(__is_class , KEYCXX)
KEYWORD(__is_convertible_to , KEYCXX)
KEYWORD(__is_empty , KEYCXX)
KEYWORD(__is_enum , KEYCXX)
+// Tentative name - there's no implementation of std::is_literal_type yet.
+KEYWORD(__is_literal , KEYCXX)
+// Name for GCC 4.6 compatibility - people have already written libraries using
+// this name unfortunately.
+KEYWORD(__is_literal_type , KEYCXX)
KEYWORD(__is_pod , KEYCXX)
KEYWORD(__is_polymorphic , KEYCXX)
+KEYWORD(__is_trivial , KEYCXX)
KEYWORD(__is_union , KEYCXX)
-// Tentative name - there's no implementation of std::is_literal_type yet.
-KEYWORD(__is_literal , KEYCXX)
+
+// Embarcadero Expression Traits
+KEYWORD(__is_lvalue_expr , KEYCXX)
+KEYWORD(__is_rvalue_expr , KEYCXX)
+
+// Embarcadero Unary Type Traits
+KEYWORD(__is_arithmetic , KEYCXX)
+KEYWORD(__is_floating_point , KEYCXX)
+KEYWORD(__is_integral , KEYCXX)
+KEYWORD(__is_complete_type , KEYCXX)
+KEYWORD(__is_void , KEYCXX)
+KEYWORD(__is_array , KEYCXX)
+KEYWORD(__is_function , KEYCXX)
+KEYWORD(__is_reference , KEYCXX)
+KEYWORD(__is_lvalue_reference , KEYCXX)
+KEYWORD(__is_rvalue_reference , KEYCXX)
+KEYWORD(__is_fundamental , KEYCXX)
+KEYWORD(__is_object , KEYCXX)
+KEYWORD(__is_scalar , KEYCXX)
+KEYWORD(__is_compound , KEYCXX)
+KEYWORD(__is_pointer , KEYCXX)
+KEYWORD(__is_member_object_pointer , KEYCXX)
+KEYWORD(__is_member_function_pointer, KEYCXX)
+KEYWORD(__is_member_pointer , KEYCXX)
+KEYWORD(__is_const , KEYCXX)
+KEYWORD(__is_volatile , KEYCXX)
+KEYWORD(__is_standard_layout , KEYCXX)
+KEYWORD(__is_signed , KEYCXX)
+KEYWORD(__is_unsigned , KEYCXX)
+
+// Embarcadero Binary Type Traits
+KEYWORD(__is_same , KEYCXX)
+KEYWORD(__is_convertible , KEYCXX)
+KEYWORD(__array_rank , KEYCXX)
+KEYWORD(__array_extent , KEYCXX)
// Apple Extension.
KEYWORD(__private_extern__ , KEYALL)
@@ -345,9 +392,23 @@ KEYWORD(__fastcall , KEYALL)
KEYWORD(__thiscall , KEYALL)
KEYWORD(__forceinline , KEYALL)
-// OpenCL-specific keywords (see OpenCL 1.1 [6.1.9])
+// OpenCL-specific keywords
KEYWORD(__kernel , KEYOPENCL)
ALIAS("kernel", __kernel , KEYOPENCL)
+KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC)
+KEYWORD(__private , KEYOPENCL)
+KEYWORD(__global , KEYOPENCL)
+KEYWORD(__local , KEYOPENCL)
+KEYWORD(__constant , KEYOPENCL)
+ALIAS("global", __global , KEYOPENCL)
+ALIAS("local", __local , KEYOPENCL)
+ALIAS("constant", __constant , KEYOPENCL)
+KEYWORD(__read_only , KEYOPENCL)
+KEYWORD(__write_only , KEYOPENCL)
+KEYWORD(__read_write , KEYOPENCL)
+ALIAS("read_only", __read_only , KEYOPENCL)
+ALIAS("write_only", __write_only , KEYOPENCL)
+ALIAS("read_write", __read_write , KEYOPENCL)
// Borland Extensions.
KEYWORD(__pascal , KEYALL)
@@ -358,18 +419,19 @@ KEYWORD(__pixel , KEYALTIVEC)
// Alternate spelling for various tokens. There are GCC extensions in all
// languages, but should not be disabled in strict conformance mode.
-ALIAS("__attribute__", __attribute, KEYALL)
-ALIAS("__const" , const , KEYALL)
-ALIAS("__const__" , const , KEYALL)
ALIAS("__alignof__" , __alignof , KEYALL)
ALIAS("__asm" , asm , KEYALL)
ALIAS("__asm__" , asm , KEYALL)
+ALIAS("__attribute__", __attribute, KEYALL)
ALIAS("__complex" , _Complex , KEYALL)
ALIAS("__complex__" , _Complex , KEYALL)
+ALIAS("__const" , const , KEYALL)
+ALIAS("__const__" , const , KEYALL)
+ALIAS("__decltype" , decltype , KEYCXX)
ALIAS("__imag__" , __imag , KEYALL)
ALIAS("__inline" , inline , KEYALL)
ALIAS("__inline__" , inline , KEYALL)
-ALIAS("__nullptr" , nullptr , KEYCXX)
+ALIAS("__nullptr" , nullptr , KEYCXX)
ALIAS("__real__" , __real , KEYALL)
ALIAS("__restrict" , restrict , KEYALL)
ALIAS("__restrict__" , restrict , KEYALL)
@@ -384,6 +446,14 @@ ALIAS("__volatile__" , volatile , KEYALL)
KEYWORD(__ptr64 , KEYMS)
KEYWORD(__w64 , KEYMS)
KEYWORD(__uuidof , KEYMS | KEYBORLAND)
+KEYWORD(__try , KEYMS | KEYBORLAND)
+KEYWORD(__except , KEYMS | KEYBORLAND)
+KEYWORD(__finally , KEYMS | KEYBORLAND)
+KEYWORD(__leave , KEYMS | KEYBORLAND)
+KEYWORD(__int64 , KEYMS)
+ALIAS("__int8" , char , KEYMS)
+ALIAS("__int16" , short , KEYMS)
+ALIAS("__int32" , int , KEYMS)
ALIAS("_asm" , asm , KEYMS)
ALIAS("_cdecl" , __cdecl , KEYMS | KEYBORLAND)
ALIAS("_fastcall" , __fastcall , KEYMS | KEYBORLAND)
@@ -391,6 +461,8 @@ ALIAS("_stdcall" , __stdcall , KEYMS | KEYBORLAND)
ALIAS("_thiscall" , __thiscall , KEYMS)
ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND)
ALIAS("_inline" , inline , KEYMS)
+ALIAS("_declspec" , __declspec , KEYMS)
+ALIAS("__interface" , class , KEYMS)
// Borland Extensions which should be disabled in strict conformance mode.
ALIAS("_pascal" , __pascal , KEYBORLAND)
@@ -399,9 +471,12 @@ ALIAS("_pascal" , __pascal , KEYBORLAND)
ALIAS("__char16_t" , char16_t , KEYCXX)
ALIAS("__char32_t" , char32_t , KEYCXX)
+// Clang-specific keywords enabled only in testing.
+TESTING_KEYWORD(__unknown_anytype , KEYALL)
+
//===----------------------------------------------------------------------===//
-// Objective-C @-preceeded keywords.
+// Objective-C @-preceded keywords.
//===----------------------------------------------------------------------===//
// These have meaning after an '@' in Objective-C mode. These define enums in
@@ -443,6 +518,7 @@ ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly
ANNOTATION(template_id) // annotation for a C++ template-id that names a
// function template specialization (not a type),
// e.g., "std::swap<int>"
+ANNOTATION(primary_expr) // annotation for a primary expression
// Annotation for #pragma unused(...)
// For each argument inside the parentheses the pragma handler will produce
@@ -450,6 +526,7 @@ ANNOTATION(template_id) // annotation for a C++ template-id that names a
ANNOTATION(pragma_unused)
#undef ANNOTATION
+#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD
#undef OBJC1_AT_KEYWORD
#undef CXX_KEYWORD_OPERATOR
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 00c6e9ed5000..4a2a2c67e0eb 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -27,20 +27,59 @@ namespace clang {
UTT_HasTrivialDestructor,
UTT_HasVirtualDestructor,
UTT_IsAbstract,
+ UTT_IsArithmetic,
+ UTT_IsArray,
UTT_IsClass,
+ UTT_IsCompleteType,
+ UTT_IsCompound,
+ UTT_IsConst,
UTT_IsEmpty,
UTT_IsEnum,
+ UTT_IsFloatingPoint,
+ UTT_IsFunction,
+ UTT_IsFundamental,
+ UTT_IsIntegral,
+ UTT_IsLiteral,
+ UTT_IsLvalueReference,
+ UTT_IsMemberFunctionPointer,
+ UTT_IsMemberObjectPointer,
+ UTT_IsMemberPointer,
+ UTT_IsObject,
UTT_IsPOD,
+ UTT_IsPointer,
UTT_IsPolymorphic,
+ UTT_IsReference,
+ UTT_IsRvalueReference,
+ UTT_IsScalar,
+ UTT_IsSigned,
+ UTT_IsStandardLayout,
+ UTT_IsTrivial,
UTT_IsUnion,
- UTT_IsLiteral
+ UTT_IsUnsigned,
+ UTT_IsVoid,
+ UTT_IsVolatile
};
/// BinaryTypeTrait - Names for the binary type traits.
enum BinaryTypeTrait {
BTT_IsBaseOf,
- BTT_TypeCompatible,
- BTT_IsConvertibleTo
+ BTT_IsConvertible,
+ BTT_IsConvertibleTo,
+ BTT_IsSame,
+ BTT_TypeCompatible
+ };
+
+ /// ArrayTypeTrait - Names for the array type traits.
+ enum ArrayTypeTrait {
+ ATT_ArrayRank,
+ ATT_ArrayExtent
+ };
+
+ /// UnaryExprOrTypeTrait - Names for the "expression or type" traits.
+ enum UnaryExprOrTypeTrait {
+ UETT_SizeOf,
+ UETT_AlignOf,
+ UETT_VecStep
};
}
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
index ede68ed50d52..15cdf1fa02e6 100644
--- a/include/clang/Basic/Version.h
+++ b/include/clang/Basic/Version.h
@@ -58,6 +58,11 @@ namespace clang {
/// which includes the clang version number, the repository version,
/// and the vendor tag.
std::string getClangFullVersion();
+
+ /// \brief Retrieves a string representing the complete clang version suitable
+ /// for use in the CPP __VERSION__ macro, which includes the clang version
+ /// number, the repository version, and the vendor tag.
+ std::string getClangFullCPPVersion();
}
#endif // LLVM_CLANG_BASIC_VERSION_H
diff --git a/include/clang/Basic/VersionTuple.h b/include/clang/Basic/VersionTuple.h
new file mode 100644
index 000000000000..91eb68eaad9f
--- /dev/null
+++ b/include/clang/Basic/VersionTuple.h
@@ -0,0 +1,126 @@
+//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines the VersionTuple class, which represents a version in
+// the form major[.minor[.subminor]].
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_VERSIONTUPLE_H
+#define LLVM_CLANG_BASIC_VERSIONTUPLE_H
+
+#include "llvm/ADT/Optional.h"
+#include <string>
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+
+/// \brief Represents a version number in the form major[.minor[.subminor]].
+class VersionTuple {
+ unsigned Major;
+ unsigned Minor : 31;
+ unsigned Subminor : 31;
+ unsigned HasMinor : 1;
+ unsigned HasSubminor : 1;
+
+public:
+ VersionTuple()
+ : Major(0), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false) { }
+
+ explicit VersionTuple(unsigned Major)
+ : Major(Major), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false)
+ { }
+
+ explicit VersionTuple(unsigned Major, unsigned Minor)
+ : Major(Major), Minor(Minor), Subminor(0), HasMinor(true),
+ HasSubminor(false)
+ { }
+
+ explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
+ : Major(Major), Minor(Minor), Subminor(Subminor), HasMinor(true),
+ HasSubminor(true)
+ { }
+
+ /// \brief Determine whether this version information is empty
+ /// (e.g., all version components are zero).
+ bool empty() const { return Major == 0 && Minor == 0 && Subminor == 0; }
+
+ /// \brief Retrieve the major version number.
+ unsigned getMajor() const { return Major; }
+
+ /// \brief Retrieve the minor version number, if provided.
+ llvm::Optional<unsigned> getMinor() const {
+ if (!HasMinor)
+ return llvm::Optional<unsigned>();
+ return Minor;
+ }
+
+ /// \brief Retrieve the subminor version number, if provided.
+ llvm::Optional<unsigned> getSubminor() const {
+ if (!HasSubminor)
+ return llvm::Optional<unsigned>();
+ return Subminor;
+ }
+
+ /// \brief Determine if two version numbers are equivalent. If not
+ /// provided, minor and subminor version numbers are considered to be zero.
+ friend bool operator==(const VersionTuple& X, const VersionTuple &Y) {
+ return X.Major == Y.Major && X.Minor == Y.Minor && X.Subminor == Y.Subminor;
+ }
+
+ /// \brief Determine if two version numbers are not equivalent. If
+ /// not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(X == Y);
+ }
+
+ /// \brief Determine whether one version number precedes another. If not
+ /// provided, minor and subminor version numbers are considered to be zero.
+ friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
+ if (X.Major != Y.Major)
+ return X.Major < Y.Major;
+
+ if (X.Minor != Y.Minor)
+ return X.Minor < Y.Minor;
+
+ return X.Subminor < Y.Subminor;
+ }
+
+ /// \brief Determine whether one version number follows another. If not
+ /// provided, minor and subminor version numbers are considered to be zero.
+ friend bool operator>(const VersionTuple &X, const VersionTuple &Y) {
+ return Y < X;
+ }
+
+ /// \brief Determine whether one version number precedes or is
+ /// equivalent to another. If not provided, minor and subminor
+ /// version numbers are considered to be zero.
+ friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(Y < X);
+ }
+
+ /// \brief Determine whether one version number follows or is
+ /// equivalent to another. If not provided, minor and subminor
+ /// version numbers are considered to be zero.
+ friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(X < Y);
+ }
+
+ /// \brief Retrieve a string representation of the version number/
+ std::string getAsString() const;
+};
+
+/// \brief Print a version number.
+llvm::raw_ostream& operator<<(llvm::raw_ostream &Out, const VersionTuple &V);
+
+} // end namespace clang
+#endif // LLVM_CLANG_BASIC_VERSIONTUPLE_H
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index 880a0da6bc68..6d6c7c7bede3 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -22,13 +22,11 @@ def OP_SUB : Op;
def OP_SUBL : Op;
def OP_SUBW : Op;
def OP_MUL : Op;
-def OP_MULL : Op;
def OP_MLA : Op;
def OP_MLAL : Op;
def OP_MLS : Op;
def OP_MLSL : Op;
def OP_MUL_N : Op;
-def OP_MULL_N: Op;
def OP_MLA_N : Op;
def OP_MLS_N : Op;
def OP_MLAL_N : Op;
@@ -144,8 +142,7 @@ def VQDMULH : SInst<"vqdmulh", "ddd", "siQsQi">;
def VQRDMULH : SInst<"vqrdmulh", "ddd", "siQsQi">;
def VQDMLAL : SInst<"vqdmlal", "wwdd", "si">;
def VQDMLSL : SInst<"vqdmlsl", "wwdd", "si">;
-def VMULL : Inst<"vmull", "wdd", "csiUcUsUi", OP_MULL>;
-def VMULLP : SInst<"vmull", "wdd", "Pc">;
+def VMULL : SInst<"vmull", "wdd", "csiUcUsUiPc">;
def VQDMULL : SInst<"vqdmull", "wdd", "si">;
////////////////////////////////////////////////////////////////////////////////
@@ -331,7 +328,7 @@ def VMLSL_LANE : Inst<"vmlsl_lane", "wwddi", "siUsUi", OP_MLSL_LN>;
def VQDMLSL_LANE : Inst<"vqdmlsl_lane", "wwddi", "si", OP_QDMLSL_LN>;
def VMUL_N : Inst<"vmul_n", "dds", "sifUsUiQsQiQfQUsQUi", OP_MUL_N>;
def VMUL_LANE : Inst<"vmul_lane", "ddgi", "sifUsUiQsQiQfQUsQUi", OP_MUL_LN>;
-def VMULL_N : Inst<"vmull_n", "wda", "siUsUi", OP_MULL_N>;
+def VMULL_N : SInst<"vmull_n", "wda", "siUsUi">;
def VMULL_LANE : Inst<"vmull_lane", "wddi", "siUsUi", OP_MULL_LN>;
def VQDMULL_N : SInst<"vqdmull_n", "wda", "si">;
def VQDMULL_LANE : Inst<"vqdmull_lane", "wddi", "si", OP_QDMULL_LN>;
diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h
index a52789e69929..265d6d871672 100644
--- a/include/clang/Driver/Arg.h
+++ b/include/clang/Driver/Arg.h
@@ -13,7 +13,6 @@
#include "Util.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include <vector>
#include <string>
namespace clang {
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
index 50472ffdf9cd..2643c4f0e854 100644
--- a/include/clang/Driver/CC1AsOptions.td
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -29,6 +29,10 @@ def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">,
HelpText<"Add directory to include search path">;
def n : Flag<"-n">,
HelpText<"Don't automatically start assembly file with a text section">;
+def L : Flag<"-L">,
+ HelpText<"Save temporary labels in the symbol table. "
+ "Note this may change .s semantics, it should almost never be used "
+ "on compiler generated code!">;
//===----------------------------------------------------------------------===//
// Frontend Options
@@ -72,4 +76,4 @@ def relax_all : Flag<"-relax-all">,
HelpText<"Relax all fixups (for performance testing)">;
def no_exec_stack : Flag<"--noexecstack">,
- HelpText<"Mark the file as not needing an executable stack">; \ No newline at end of file
+ HelpText<"Mark the file as not needing an executable stack">;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 748e6cf32691..d243bf989fda 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -42,14 +42,6 @@ def analysis_CFGAddImplicitDtors : Flag<"-cfg-add-implicit-dtors">,
HelpText<"Add C++ implicit destructors to CFGs for all analyses">;
def analysis_CFGAddInitializers : Flag<"-cfg-add-initializers">,
HelpText<"Add C++ initializers to CFGs for all analyses">;
-def analysis_WarnUninitVals : Flag<"-warn-uninit-values">,
- HelpText<"Warn about uses of uninitialized variables">;
-def analysis_ObjCMemChecker : Flag<"-analyzer-check-objc-mem">,
- HelpText<"Run the [Core] Foundation reference count checker">;
-def analysis_AnalyzerStats : Flag<"-analyzer-stats">,
- HelpText<"Emit warnings with analyzer statistics">;
-def analysis_WarnBufferOverflows : Flag<"-analyzer-check-buffer-overflows">,
- HelpText<"Warn about buffer overflows">;
def analyzer_store : Separate<"-analyzer-store">,
HelpText<"Source Code Analysis - Abstract Memory Store Models">;
@@ -71,8 +63,6 @@ def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-bloc
HelpText<"Analyze the definitions of blocks in addition to functions">;
def analyzer_display_progress : Flag<"-analyzer-display-progress">,
HelpText<"Emit verbose output about the analyzer's progress">;
-def analyzer_experimental_checks : Flag<"-analyzer-experimental-checks">,
- HelpText<"Use experimental path-sensitive checks">;
def analyze_function : Separate<"-analyze-function">,
HelpText<"Run analysis on specific function">;
def analyze_function_EQ : Joined<"-analyze-function=">, Alias<analyze_function>;
@@ -120,7 +110,10 @@ def disable_red_zone : Flag<"-disable-red-zone">,
HelpText<"Do not emit code that uses the red zone.">;
def dwarf_debug_flags : Separate<"-dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
+def fforbid_guard_variables : Flag<"-fforbid-guard-variables">,
+ HelpText<"Emit an error if a C++ static local initializer would need a guard variable">;
def g : Flag<"-g">, HelpText<"Generate source level debug information">;
+def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, HelpText<"Don't use the cfi directives">;
def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">,
HelpText<"Generate runtime checks for undefined behavior.">;
def flimit_debug_info : Flag<"-flimit-debug-info">,
@@ -143,6 +136,10 @@ def fdata_sections : Flag<"-fdata-sections">,
HelpText<"Place each data in its own section (ELF Only)">;
def funroll_loops : Flag<"-funroll-loops">,
HelpText<"Turn on loop unroller">;
+def femit_coverage_notes : Flag<"-femit-coverage-notes">,
+ HelpText<"Emit a gcov coverage notes file when compiling.">;
+def femit_coverage_data: Flag<"-femit-coverage-data">,
+ HelpText<"Instrument the program to emit gcov coverage data when run.">;
def relaxed_aliasing : Flag<"-relaxed-aliasing">,
HelpText<"Turn off Type Based Alias Analysis">;
def masm_verbose : Flag<"-masm-verbose">,
@@ -163,10 +160,16 @@ def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">,
HelpText<"Omit frame pointer setup for leaf functions.">;
def msoft_float : Flag<"-msoft-float">,
HelpText<"Use software floating point">;
+def backend_option : Separate<"-backend-option">,
+ HelpText<"Additional arguments to forward to LLVM backend (during code gen)">;
def mregparm : Separate<"-mregparm">,
HelpText<"Limit the number of registers available for integer arguments">;
def mrelax_all : Flag<"-mrelax-all">,
- HelpText<"Relax all machine instructions">;
+ HelpText<"(integrated-as) Relax all machine instructions">;
+def msave_temp_labels : Flag<"-msave-temp-labels">,
+ HelpText<"(integrated-as) Save temporary labels">;
+def mrtd: Flag<"-mrtd">,
+ HelpText<"Make StdCall calling convention the default">;
def mrelocation_model : Separate<"-mrelocation-model">,
HelpText<"The relocation model to use">;
def munwind_tables : Flag<"-munwind-tables">,
@@ -177,6 +180,7 @@ def mms_bitfields : Flag<"-mms-bitfields">,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">;
def O : Joined<"-O">, HelpText<"Optimization level">;
def Os : Flag<"-Os">, HelpText<"Optimize for size">;
+def Oz : Flag<"-Oz">, HelpText<"Optimize for size, regardless of performance">;
def pg : Flag<"-pg">, HelpText<"Enable mcount instrumentation">;
//===----------------------------------------------------------------------===//
@@ -203,6 +207,8 @@ def MP : Flag<"-MP">,
def dump_build_information : Separate<"-dump-build-information">,
MetaVarName<"<filename>">,
HelpText<"output a dump of some build information to a file">;
+def diagnostic_log_file : Separate<"-diagnostic-log-file">,
+ HelpText<"Filename (or -) to log diagnostics to">;
def fno_show_column : Flag<"-fno-show-column">,
HelpText<"Do not include column number on diagnostics">;
def fno_show_source_location : Flag<"-fno-show-source-location">,
@@ -214,6 +220,9 @@ def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">,
HelpText<"Do not include source line and caret with diagnostics">;
def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">,
HelpText<"Do not include fixit information in diagnostics">;
+def fno_diagnostics_show_note_include_stack :
+ Flag<"-fno-diagnostics-show-note-include-stack">,
+ HelpText<"Display include stacks for diagnostic notes">;
def w : Flag<"-w">, HelpText<"Suppress all warnings">;
def pedantic : Flag<"-pedantic">;
def pedantic_errors : Flag<"-pedantic-errors">;
@@ -227,11 +236,15 @@ def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-rang
HelpText<"Print source range spans in numeric form">;
def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">,
HelpText<"Print fix-its in machine parseable form">;
+def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">,
+ HelpText<"Print diagnostic name">;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
- HelpText<"Print diagnostic name with mappable diagnostics">;
+ HelpText<"Print option name with mappable diagnostics">;
def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">,
HelpText<"Print diagnostic category">;
-
+def fdiagnostics_show_note_include_stack :
+ Flag<"-fdiagnostics-show-note-include-stack">,
+ HelpText<"Display include stacks for diagnostic notes">;
def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">,
HelpText<"Set the tab stop distance.">;
def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">,
@@ -246,8 +259,6 @@ def fcolor_diagnostics : Flag<"-fcolor-diagnostics">,
HelpText<"Use colors in diagnostics">;
def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">,
HelpText<"Silence ObjC rewriting warnings">;
-def Wwrite_strings : Flag<"-Wwrite-strings">,
- HelpText<"Remove const qualifier from string literals">;
def verify : Flag<"-verify">,
HelpText<"Verify emitted diagnostics and warnings">;
@@ -326,8 +337,6 @@ def emit_html : Flag<"-emit-html">,
HelpText<"Output input source as HTML">;
def ast_print : Flag<"-ast-print">,
HelpText<"Build ASTs and then pretty-print them">;
-def ast_print_xml : Flag<"-ast-print-xml">,
- HelpText<"Build ASTs and then print them in XML format">;
def ast_dump : Flag<"-ast-dump">,
HelpText<"Build ASTs and then debug dump them">;
def ast_dump_xml : Flag<"-ast-dump-xml">,
@@ -517,8 +526,25 @@ def trigraphs : Flag<"-trigraphs">,
HelpText<"Process trigraph sequences">;
def fwritable_strings : Flag<"-fwritable-strings">,
HelpText<"Store string literals as writable data">;
+def fconst_strings : Flag<"-fconst-strings">,
+ HelpText<"Use a const qualified type for string literals in C and ObjC">;
+def fno_const_strings : Flag<"-fno-const-strings">,
+ HelpText<"Don't use a const qualified type for string literals in C and ObjC">;
def fno_bitfield_type_align : Flag<"-fno-bitfield-type-align">,
HelpText<"Ignore bit-field types when aligning structures">;
+def traditional_cpp : Flag<"-traditional-cpp">,
+ HelpText<"Enable some traditional CPP emulation">;
+def ffake_address_space_map : Flag<"-ffake-address-space-map">,
+ HelpText<"Use a fake address space map; OpenCL testing purposes only">;
+def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">,
+ HelpText<"Parse templated function definitions at the end of the "
+ "translation unit ">;
+def funknown_anytype : Flag<"-funknown-anytype">,
+ HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">;
+def fdeprecated_macro : Flag<"-fdeprecated-macro">,
+ HelpText<"Defines the __DEPRECATED macro">;
+def fno_deprecated_macro : Flag<"-fno-deprecated-macro">,
+ HelpText<"Undefines the __DEPRECATED macro">;
//===----------------------------------------------------------------------===//
// Header Search Options
@@ -570,6 +596,8 @@ def include_pch : Separate<"-include-pch">, MetaVarName<"<file>">,
HelpText<"Include precompiled header file">;
def include_pth : Separate<"-include-pth">, MetaVarName<"<file>">,
HelpText<"Include file before parsing">;
+def chain_include : Separate<"-chain-include">, MetaVarName<"<file>">,
+ HelpText<"Include and chain a header file after turning it into PCH">;
def preamble_bytes_EQ : Joined<"-preamble-bytes=">,
HelpText<"Assume that the precompiled header is a precompiled preamble "
"covering the first N bytes of the main file">;
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 03fa0ef972d0..5a7d830b069d 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -25,6 +25,7 @@
namespace llvm {
class raw_ostream;
+ template<typename T> class ArrayRef;
}
namespace clang {
namespace driver {
@@ -77,6 +78,12 @@ public:
typedef llvm::SmallVector<std::string, 4> prefix_list;
prefix_list PrefixDirs;
+ /// sysroot, if present
+ std::string SysRoot;
+
+ /// If the standard library is used
+ bool UseStdLib;
+
/// Default host triple.
std::string DefaultHostTriple;
@@ -90,7 +97,7 @@ public:
/// will generally be the actual host platform, but not always.
const HostInfo *Host;
- /// Information about the host which can be overriden by the user.
+ /// Information about the host which can be overridden by the user.
std::string HostBits, HostMachine, HostSystem, HostRelease;
/// The file to log CC_PRINT_OPTIONS output to, if enabled.
@@ -99,9 +106,15 @@ public:
/// The file to log CC_PRINT_HEADERS output to, if enabled.
const char *CCPrintHeadersFilename;
+ /// The file to log CC_LOG_DIAGNOSTICS output to, if enabled.
+ const char *CCLogDiagnosticsFilename;
+
/// Whether the driver should follow g++ like behavior.
unsigned CCCIsCXX : 1;
+ /// Whether the driver is just the preprocessor
+ unsigned CCCIsCPP : 1;
+
/// Echo commands while executing (in -v style).
unsigned CCCEcho : 1;
@@ -116,8 +129,13 @@ public:
/// information to CCPrintHeadersFilename or to stderr.
unsigned CCPrintHeaders : 1;
+ /// Set CC_LOG_DIAGNOSTICS mode, which causes the frontend to log diagnostics
+ /// to CCLogDiagnosticsFilename or to stderr, in a stable machine readable
+ /// format.
+ unsigned CCLogDiagnostics : 1;
+
private:
- /// Name to use when calling the generic gcc.
+ /// Name to use when invoking gcc/g++.
std::string CCCGenericGCCName;
/// Whether to check that input files exist when constructing compilation
@@ -165,7 +183,7 @@ public:
/// @name Accessors
/// @{
- /// Name to use when calling the generic gcc.
+ /// Name to use when invoking gcc/g++.
const std::string &getCCCGenericGCCName() const { return CCCGenericGCCName; }
@@ -206,14 +224,14 @@ public:
/// argument vector. A null return value does not necessarily
/// indicate an error condition, the diagnostics should be queried
/// to determine if an error occurred.
- Compilation *BuildCompilation(int argc, const char **argv);
+ Compilation *BuildCompilation(llvm::ArrayRef<const char *> Args);
/// @name Driver Steps
/// @{
/// ParseArgStrings - Parse the given list of strings into an
/// ArgList.
- InputArgList *ParseArgStrings(const char **ArgBegin, const char **ArgEnd);
+ InputArgList *ParseArgStrings(llvm::ArrayRef<const char *> Args);
/// BuildActions - Construct the list of actions to perform for the
/// given arguments, which are only done for a single architecture.
@@ -221,7 +239,7 @@ public:
/// \param TC - The default host tool chain.
/// \param Args - The input arguments.
/// \param Actions - The list to store the resulting actions onto.
- void BuildActions(const ToolChain &TC, const ArgList &Args,
+ void BuildActions(const ToolChain &TC, const DerivedArgList &Args,
ActionList &Actions) const;
/// BuildUniversalActions - Construct the list of actions to perform
@@ -230,7 +248,7 @@ public:
/// \param TC - The default host tool chain.
/// \param Args - The input arguments.
/// \param Actions - The list to store the resulting actions onto.
- void BuildUniversalActions(const ToolChain &TC, const ArgList &Args,
+ void BuildUniversalActions(const ToolChain &TC, const DerivedArgList &Args,
ActionList &Actions) const;
/// BuildJobs - Bind actions to concrete tools and translate
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
index 0733c51027d9..0f9376b8dea1 100644
--- a/include/clang/Driver/DriverDiagnostic.h
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -15,7 +15,8 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#define DRIVERSTART
#include "clang/Basic/DiagnosticDriverKinds.inc"
#undef DIAG
diff --git a/include/clang/Driver/OptParser.td b/include/clang/Driver/OptParser.td
index 04efd00fb1d8..25ecbc35f92e 100644
--- a/include/clang/Driver/OptParser.td
+++ b/include/clang/Driver/OptParser.td
@@ -78,7 +78,7 @@ def RenderSeparate : OptionFlag;
def Unsupported : OptionFlag;
// HelpHidden - The option should not be displayed in --help, even if it has
-// help text. Clients *can* use this in conjuction with the OptTable::PrintHelp
+// help text. Clients *can* use this in conjunction with the OptTable::PrintHelp
// arguments to implement hidden help groups.
def HelpHidden : OptionFlag;
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 288c10f52354..38f0c57af73e 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -29,6 +29,7 @@ def X_Group : OptionGroup<"<X group>">;
def a_Group : OptionGroup<"<a group>">;
def d_Group : OptionGroup<"<d group>">;
def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>;
+def f_clang_Group : OptionGroup<"<f (clang-only) group>">, Group<CompileOnly_Group>;
def g_Group : OptionGroup<"<g group>">;
def i_Group : OptionGroup<"<i group>">, Group<CompileOnly_Group>;
def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>;
@@ -165,6 +166,8 @@ def Wa_COMMA : CommaJoined<"-Wa,">,
HelpText<"Pass the comma separated arguments in <arg> to the assembler">,
MetaVarName<"<arg>">;
def Wall : Flag<"-Wall">, Group<W_Group>;
+def Wdeprecated : Flag<"-Wdeprecated">, Group<W_Group>;
+def Wno_deprecated : Flag<"-Wno-deprecated">, Group<W_Group>;
def Wextra : Flag<"-Wextra">, Group<W_Group>;
def Wl_COMMA : CommaJoined<"-Wl,">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass the comma separated arguments in <arg> to the linker">,
@@ -174,6 +177,8 @@ def Wnonportable_cfstrings : Joined<"-Wnonportable-cfstrings">, Group<W_Group>;
def Wp_COMMA : CommaJoined<"-Wp,">,
HelpText<"Pass the comma separated arguments in <arg> to the preprocessor">,
MetaVarName<"<arg>">;
+def Wwrite_strings : Flag<"-Wwrite-strings">, Group<W_Group>;
+def Wno_write_strings : Flag<"-Wno-write-strings">, Group<W_Group>;
def W_Joined : Joined<"-W">, Group<W_Group>;
def Xanalyzer : Separate<"-Xanalyzer">,
HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">;
@@ -264,18 +269,24 @@ def fcompile_resource_EQ : Joined<"-fcompile-resource=">, Group<f_Group>;
def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group<f_Group>;
def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Group>;
def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>;
+def fcxx_exceptions: Flag<"-fcxx-exceptions">, Group<f_Group>;
def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>;
def fdebug_pass_structure : Flag<"-fdebug-pass-structure">, Group<f_Group>;
-def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_Group>;
-def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_Group>;
-def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Group<f_Group>;
+def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_clang_Group>;
+def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_clang_Group>;
+def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Group<f_clang_Group>;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;
-def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_Group>;
+def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">, Group<f_Group>;
+def fdiagnostics_show_note_include_stack : Flag<"-fdiagnostics-show-note-include-stack">, Group<f_Group>;
+def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_clang_Group>;
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>;
+def fdwarf2_cfi_asm : Flag<"-fdwarf2-cfi-asm">, Group<f_Group>;
+def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, Group<f_Group>;
def felide_constructors : Flag<"-felide-constructors">, Group<f_Group>;
def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>;
def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>;
def fencoding_EQ : Joined<"-fencoding=">, Group<f_Group>;
+def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>;
def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
def fhosted : Flag<"-fhosted">, Group<f_Group>;
@@ -301,6 +312,7 @@ def flimit_debug_info : Flag<"-flimit-debug-info">, Group<f_Group>,
HelpText<"Limit debug information produced to reduce size of debug binary">;
def flimited_precision_EQ : Joined<"-flimited-precision=">, Group<f_Group>;
def flto : Flag<"-flto">, Group<f_Group>;
+def fno_lto : Flag<"-fno-lto">, Group<f_Group>;
def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">,
Group<f_Group>;
def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
@@ -308,6 +320,7 @@ def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>;
def fmsc_version : Joined<"-fmsc-version=">, Group<f_Group>;
+def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, Group<f_Group>;
def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>;
def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
@@ -325,8 +338,11 @@ def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, Group<f_Group>;
def fno_color_diagnostics : Flag<"-fno-color-diagnostics">, Group<f_Group>;
def fno_common : Flag<"-fno-common">, Group<f_Group>;
def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, Group<f_Group>;
+def fno_cxx_exceptions: Flag<"-fno-cxx-exceptions">, Group<f_Group>;
def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, Group<f_Group>;
+def fno_diagnostics_show_name : Flag<"-fno-diagnostics-show-name">, Group<f_Group>;
def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group<f_Group>;
+def fno_diagnostics_show_note_include_stack : Flag<"-fno-diagnostics-show-note-include-stack">, Group<f_Group>;
def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Group>;
def fno_elide_constructors : Flag<"-fno-elide-constructors">, Group<f_Group>;
def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>;
@@ -340,6 +356,7 @@ def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Gr
def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>;
def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>;
+def fno_delayed_template_parsing : Flag<"-fno-delayed-template-parsing">, Group<f_Group>;
def fno_objc_default_synthesize_properties
: Flag<"-fno-objc-default-synthesize-properties">, Group<f_Group>;
def fno_objc_exceptions: Flag<"-fno-objc-exceptions">, Group<f_Group>;
@@ -353,12 +370,14 @@ def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>
def fno_spell_checking : Flag<"-fno-spell-checking">, Group<f_Group>;
def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<f_Group>;
+def fno_strict_overflow : Flag<"-fno-strict-overflow">, Group<f_Group>;
def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>;
def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>;
def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>;
def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>;
def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>;
def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
+def fno_wrapv : Flag<"-fno-wrapv">, Group<f_Group>;
def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>;
def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
@@ -406,19 +425,30 @@ def fsigned_char : Flag<"-fsigned-char">, Group<f_Group>;
def fstack_protector_all : Flag<"-fstack-protector-all">, Group<f_Group>;
def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>;
def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<f_Group>;
+def fstrict_overflow : Flag<"-fstrict-overflow">, Group<f_Group>;
def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
-def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>;
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">,
Group<f_Group>;
+def ftest_coverage : Flag<"-ftest-coverage">, Group<f_Group>;
def Wlarge_by_value_copy_def : Flag<"-Wlarge-by-value-copy">;
def Wlarge_by_value_copy_EQ : Joined<"-Wlarge-by-value-copy=">;
+
+// Just silence warnings about -Wlarger-than, -Wframe-larger-than for now.
+def Wlarger_than : Separate<"-Wlarger-than">, Group<clang_ignored_f_Group>;
+def Wlarger_than_EQ : Joined<"-Wlarger-than=">, Alias<Wlarger_than>;
+def Wlarger_than_ : Joined<"-Wlarger-than-">, Alias<Wlarger_than>;
+def Wframe_larger_than : Separate<"-Wframe-larger-than">, Group<clang_ignored_f_Group>;
+def Wframe_larger_than_EQ : Joined<"-Wframe-larger-than=">, Alias<Wframe_larger_than>;
+
def fterminated_vtables : Flag<"-fterminated-vtables">, Group<f_Group>;
def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group<f_Group>;
def ftime_report : Flag<"-ftime-report">, Group<f_Group>;
def ftrapv : Flag<"-ftrapv">, Group<f_Group>;
def ftrapv_handler_EQ : Joined<"-ftrapv-handler=">, Group<f_Group>;
+def ftrap_function_EQ : Joined<"-ftrap-function=">, Group<f_Group>,
+ HelpText<"Issue call to specified function rather than a trap instruction">;
def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>;
def funroll_loops : Flag<"-funroll-loops">, Group<f_Group>;
def funsigned_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>;
@@ -465,11 +495,11 @@ def m32 : Flag<"-m32">, Group<m_Group>, Flags<[DriverOption]>;
def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>;
def m3dnow : Flag<"-m3dnow">, Group<m_x86_Features_Group>;
def m64 : Flag<"-m64">, Group<m_Group>, Flags<[DriverOption]>;
-def mabi_EQ : Joined<"-mabi=">, Group<m_Group>, Flags<[DriverOption]>;
-def march_EQ : Joined<"-march=">, Group<m_Group>, Flags<[DriverOption]>;
-def mcmodel_EQ : Joined<"-mcmodel=">, Group<m_Group>, Flags<[DriverOption]>;
+def mabi_EQ : Joined<"-mabi=">, Group<m_Group>;
+def march_EQ : Joined<"-march=">, Group<m_Group>;
+def mcmodel_EQ : Joined<"-mcmodel=">, Group<m_Group>;
def mconstant_cfstrings : Flag<"-mconstant-cfstrings">, Group<clang_ignored_m_Group>;
-def mcpu_EQ : Joined<"-mcpu=">, Group<m_Group>, Flags<[DriverOption]>;
+def mcpu_EQ : Joined<"-mcpu=">, Group<m_Group>;
def mdynamic_no_pic : Joined<"-mdynamic-no-pic">, Group<m_Group>, Flags<[NoArgumentUnused]>;
def mfix_and_continue : Flag<"-mfix-and-continue">, Group<clang_ignored_m_Group>;
def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group<m_Group>;
@@ -477,6 +507,7 @@ def mfpu_EQ : Joined<"-mfpu=">, Group<m_Group>;
def mhard_float : Flag<"-mhard-float">, Group<m_Group>;
def miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group<m_Group>;
def mios_version_min_EQ : Joined<"-mios-version-min=">, Alias<miphoneos_version_min_EQ>;
+def mios_simulator_version_min_EQ : Joined<"-mios-simulator-version-min=">, Group<m_Group>;
def mkernel : Flag<"-mkernel">, Group<m_Group>;
def mlinker_version_EQ : Joined<"-mlinker-version=">, Flags<[NoForward]>;
def mllvm : Separate<"-mllvm">;
@@ -490,6 +521,7 @@ def mno_mmx : Flag<"-mno-mmx">, Group<m_x86_Features_Group>;
def mno_pascal_strings : Flag<"-mno-pascal-strings">, Group<m_Group>;
def mno_red_zone : Flag<"-mno-red-zone">, Group<m_Group>;
def mno_relax_all : Flag<"-mno-relax-all">, Group<m_Group>;
+def mno_rtd: Flag<"-mno-rtd">, Group<m_Group>;
def mno_soft_float : Flag<"-mno-soft-float">, Group<m_Group>;
def mno_sse2 : Flag<"-mno-sse2">, Group<m_x86_Features_Group>;
def mno_sse3 : Flag<"-mno-sse3">, Group<m_x86_Features_Group>;
@@ -512,6 +544,7 @@ def mpascal_strings : Flag<"-mpascal-strings">, Group<m_Group>;
def mred_zone : Flag<"-mred-zone">, Group<m_Group>;
def mregparm_EQ : Joined<"-mregparm=">, Group<m_Group>;
def mrelax_all : Flag<"-mrelax-all">, Group<m_Group>;
+def mrtd: Flag<"-mrtd">, Group<m_Group>;
def msoft_float : Flag<"-msoft-float">, Group<m_Group>;
def msse2 : Flag<"-msse2">, Group<m_x86_Features_Group>;
def msse3 : Flag<"-msse3">, Group<m_x86_Features_Group>;
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index f0012bd851eb..da6949f9786e 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -88,8 +88,10 @@ public:
return 0;
}
- /// SelectTool - Choose a tool to use to handle the action \arg JA.
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const = 0;
+ /// SelectTool - Choose a tool to use to handle the action \arg JA with the
+ /// given \arg Inputs.
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const = 0;
// Helper methods
@@ -151,6 +153,9 @@ public:
/// particular PIC mode.
virtual const char *GetForcedPicModel() const = 0;
+ /// SupportsProfiling - Does this tool chain support -pg.
+ virtual bool SupportsProfiling() const { return true; }
+
/// Does this tool chain support Objective-C garbage collection.
virtual bool SupportsObjCGC() const { return false; }
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index c45bd4070600..3c05834ad6a7 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -14,8 +14,6 @@
#ifndef DRIVER_ASTCONSUMERS_H
#define DRIVER_ASTCONSUMERS_H
-#include <string>
-
namespace llvm {
class raw_ostream;
namespace sys { class Path; }
@@ -36,12 +34,6 @@ class TargetOptions;
// implementation is still incomplete.
ASTConsumer *CreateASTPrinter(llvm::raw_ostream *OS);
-// AST XML-printer: prints out the AST in a XML format
-// The output is intended to be in a format such that
-// clang or any other tool could re-parse the output back into the same AST,
-// but the implementation is still incomplete.
-ASTConsumer *CreateASTPrinterXML(llvm::raw_ostream *OS);
-
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
ASTConsumer *CreateASTDumper();
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index e93563311b85..57c59d951e94 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -71,12 +71,12 @@ public:
private:
llvm::IntrusiveRefCntPtr<Diagnostic> Diagnostics;
- llvm::OwningPtr<FileManager> FileMgr;
- llvm::OwningPtr<SourceManager> SourceMgr;
+ llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
+ llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
llvm::OwningPtr<HeaderSearch> HeaderInfo;
- llvm::OwningPtr<TargetInfo> Target;
- llvm::OwningPtr<Preprocessor> PP;
- llvm::OwningPtr<ASTContext> Ctx;
+ llvm::IntrusiveRefCntPtr<TargetInfo> Target;
+ llvm::IntrusiveRefCntPtr<Preprocessor> PP;
+ llvm::IntrusiveRefCntPtr<ASTContext> Ctx;
FileSystemOptions FileSystemOpts;
@@ -90,7 +90,7 @@ private:
/// Optional owned invocation, just used to make the invocation used in
/// LoadFromCommandLine available.
- llvm::OwningPtr<CompilerInvocation> Invocation;
+ llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation;
/// \brief The set of target features.
///
@@ -115,6 +115,9 @@ private:
/// \brief Whether we should time each operation.
bool WantTiming;
+
+ /// \brief Whether the ASTUnit should delete the remapped buffers.
+ bool OwnsRemappedFileBuffers;
/// Track the top-level decls which appeared in an ASTUnit which was loaded
/// from a source file.
@@ -393,11 +396,11 @@ public:
const SourceManager &getSourceManager() const { return *SourceMgr; }
SourceManager &getSourceManager() { return *SourceMgr; }
- const Preprocessor &getPreprocessor() const { return *PP.get(); }
- Preprocessor &getPreprocessor() { return *PP.get(); }
+ const Preprocessor &getPreprocessor() const { return *PP; }
+ Preprocessor &getPreprocessor() { return *PP; }
- const ASTContext &getASTContext() const { return *Ctx.get(); }
- ASTContext &getASTContext() { return *Ctx.get(); }
+ const ASTContext &getASTContext() const { return *Ctx; }
+ ASTContext &getASTContext() { return *Ctx; }
bool hasSema() const { return TheSema; }
Sema &getSema() const {
@@ -422,6 +425,9 @@ public:
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
+ bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; }
+ void setOwnsRemappedFileBuffers(bool val) { OwnsRemappedFileBuffers = val; }
+
/// \brief Retrieve the maximum PCH level of declarations that a
/// traversal of the translation unit should consider.
unsigned getMaxPCHLevel() const;
@@ -529,10 +535,16 @@ public:
/// that might still be used as a precompiled header or preamble.
bool isCompleteTranslationUnit() const { return CompleteTranslationUnit; }
+ typedef llvm::PointerUnion<const char *, const llvm::MemoryBuffer *>
+ FilenameOrMemBuf;
/// \brief A mapping from a file name to the memory buffer that stores the
/// remapped contents of that file.
- typedef std::pair<std::string, const llvm::MemoryBuffer *> RemappedFile;
-
+ typedef std::pair<std::string, FilenameOrMemBuf> RemappedFile;
+
+ /// \brief Create a ASTUnit. Gets ownership of the passed CompilerInvocation.
+ static ASTUnit *create(CompilerInvocation *CI,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags);
+
/// \brief Create a ASTUnit from an AST file.
///
/// \param Filename - The AST file to load.
@@ -603,6 +615,7 @@ public:
bool CaptureDiagnostics = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0,
+ bool RemappedFilesKeepOriginalName = true,
bool PrecompilePreamble = false,
bool CompleteTranslationUnit = true,
bool CacheCodeCompletionResults = false,
@@ -647,6 +660,11 @@ public:
///
/// \returns True if an error occurred, false otherwise.
bool Save(llvm::StringRef File);
+
+ /// \brief Serialize this translation unit with the given output stream.
+ ///
+ /// \returns True if an error occurred, false otherwise.
+ bool serialize(llvm::raw_ostream &OS);
};
} // namespace clang
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def
index 75b52a824c63..f055549b4e24 100644
--- a/include/clang/Frontend/Analyses.def
+++ b/include/clang/Frontend/Analyses.def
@@ -11,16 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#ifndef ANALYSIS
-#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)
-#endif
-
-ANALYSIS(WarnUninitVals, "warn-uninit-values",
- "Warn about uses of uninitialized variables", Code)
-
-ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem",
- "Run the [Core] Foundation reference count checker", Code)
-
#ifndef ANALYSIS_STORE
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
#endif
@@ -45,7 +35,6 @@ ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", cre
ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticClient, true)
ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticClient, true)
-#undef ANALYSIS
#undef ANALYSIS_STORE
#undef ANALYSIS_CONSTRAINTS
#undef ANALYSIS_DIAGNOSTICS
diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h
index 64263c1b54e8..ea9f5e38b7b9 100644
--- a/include/clang/Frontend/AnalyzerOptions.h
+++ b/include/clang/Frontend/AnalyzerOptions.h
@@ -55,7 +55,6 @@ NUM_ANALYSIS_DIAG_CLIENTS
class AnalyzerOptions {
public:
- std::vector<Analyses> AnalysisList;
/// \brief Pair of checker name and enable/disable.
std::vector<std::pair<std::string, bool> > CheckersControlList;
AnalysisStores AnalysisStoreOpt;
@@ -68,14 +67,11 @@ public:
unsigned AnalyzeAll : 1;
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzeNestedBlocks : 1;
- unsigned AnalyzerStats : 1;
unsigned EagerlyAssume : 1;
- unsigned BufferOverflows : 1;
unsigned PurgeDead : 1;
unsigned TrimGraph : 1;
unsigned VisualizeEGDot : 1;
unsigned VisualizeEGUbi : 1;
- unsigned EnableExperimentalChecks : 1;
unsigned InlineCall : 1;
unsigned UnoptimizedCFG : 1;
unsigned CFGAddImplicitDtors : 1;
@@ -91,14 +87,11 @@ public:
AnalyzeAll = 0;
AnalyzerDisplayProgress = 0;
AnalyzeNestedBlocks = 0;
- AnalyzerStats = 0;
EagerlyAssume = 0;
- BufferOverflows = 0;
PurgeDead = 1;
TrimGraph = 0;
VisualizeEGDot = 0;
VisualizeEGUbi = 0;
- EnableExperimentalChecks = 0;
InlineCall = 0;
UnoptimizedCFG = 0;
CFGAddImplicitDtors = 0;
diff --git a/include/clang/Frontend/ChainedDiagnosticClient.h b/include/clang/Frontend/ChainedDiagnosticClient.h
index 2d5e128dac37..70f21901db4f 100644
--- a/include/clang/Frontend/ChainedDiagnosticClient.h
+++ b/include/clang/Frontend/ChainedDiagnosticClient.h
@@ -48,6 +48,9 @@ public:
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
+ // Default implementation (Warnings/errors count).
+ DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
+
Primary->HandleDiagnostic(DiagLevel, Info);
Secondary->HandleDiagnostic(DiagLevel, Info);
}
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index ee85b655c23f..8bef6a3e0d43 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_FRONTEND_CODEGENOPTIONS_H
#include <string>
+#include <vector>
namespace clang {
@@ -51,6 +52,10 @@ public:
/// Decl* various IR entities came from. Only
/// useful when running CodeGen as a
/// subroutine.
+ unsigned EmitGcovArcs : 1; /// Emit coverage data files, aka. GCDA.
+ unsigned EmitGcovNotes : 1; /// Emit coverage "notes" files, aka GCNO.
+ unsigned ForbidGuardVariables : 1; /// Issue errors if C++ guard variables
+ /// are required
unsigned FunctionSections : 1; /// Set when -ffunction-sections is enabled
unsigned HiddenWeakTemplateVTables : 1; /// Emit weak vtables and RTTI for
/// template classes with hidden visibility
@@ -63,6 +68,7 @@ public:
/// generated.
unsigned MergeAllConstants : 1; /// Merge identical constants.
unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled.
+ unsigned NoDwarf2CFIAsm : 1; /// Set when -fno-dwarf2-cfi-asm is enabled.
unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled.
unsigned NoInfsFPMath : 1; /// Assume FP arguments, results not +-Inf.
unsigned NoNaNsFPMath : 1; /// Assume FP arguments, results not NaN.
@@ -71,9 +77,10 @@ public:
unsigned OmitLeafFramePointer : 1; /// Set when -momit-leaf-frame-pointer is
/// enabled.
unsigned OptimizationLevel : 3; /// The -O[0-4] option specified.
- unsigned OptimizeSize : 1; /// If -Os is specified.
+ unsigned OptimizeSize : 2; /// If -Os (==1) or -Oz (==2) is specified.
unsigned RelaxAll : 1; /// Relax all machine code instructions.
unsigned RelaxedAliasing : 1; /// Set when -fno-strict-aliasing is enabled.
+ unsigned SaveTempLabels : 1; /// Save temporary labels.
unsigned SimplifyLibCalls : 1; /// Set when -fbuiltin is enabled.
unsigned SoftFloat : 1; /// -soft-float.
unsigned TimePasses : 1; /// Set when -ftime-report is enabled.
@@ -112,6 +119,9 @@ public:
/// The name of the relocation model to use.
std::string RelocationModel;
+ /// A list of command-line options to forward to the LLVM backend.
+ std::vector<std::string> BackendOptions;
+
/// The user specified number of registers to be used for integral arguments,
/// or 0 if unspecified.
unsigned NumRegisterParameters;
@@ -128,6 +138,9 @@ public:
DisableLLVMOpts = 0;
DisableRedZone = 0;
EmitDeclMetadata = 0;
+ EmitGcovArcs = 0;
+ EmitGcovNotes = 0;
+ ForbidGuardVariables = 0;
FunctionSections = 0;
HiddenWeakTemplateVTables = 0;
HiddenWeakVTables = 0;
@@ -136,6 +149,7 @@ public:
LessPreciseFPMAD = 0;
MergeAllConstants = 1;
NoCommon = 0;
+ NoDwarf2CFIAsm = 0;
NoImplicitFloat = 0;
NoInfsFPMath = 0;
NoNaNsFPMath = 0;
@@ -147,6 +161,7 @@ public:
OptimizeSize = 0;
RelaxAll = 0;
RelaxedAliasing = 0;
+ SaveTempLabels = 0;
SimplifyLibCalls = 1;
SoftFloat = 0;
TimePasses = 0;
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 7ea79e5599ff..004c8896e232 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -59,25 +59,25 @@ class TargetInfo;
/// and a long form that takes explicit instances of any required objects.
class CompilerInstance {
/// The options used in this compiler instance.
- llvm::OwningPtr<CompilerInvocation> Invocation;
+ llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation;
/// The diagnostics engine instance.
llvm::IntrusiveRefCntPtr<Diagnostic> Diagnostics;
/// The target being compiled for.
- llvm::OwningPtr<TargetInfo> Target;
+ llvm::IntrusiveRefCntPtr<TargetInfo> Target;
/// The file manager.
- llvm::OwningPtr<FileManager> FileMgr;
+ llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
/// The source manager.
- llvm::OwningPtr<SourceManager> SourceMgr;
+ llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
/// The preprocessor.
- llvm::OwningPtr<Preprocessor> PP;
+ llvm::IntrusiveRefCntPtr<Preprocessor> PP;
/// The AST context.
- llvm::OwningPtr<ASTContext> Context;
+ llvm::IntrusiveRefCntPtr<ASTContext> Context;
/// The AST consumer.
llvm::OwningPtr<ASTConsumer> Consumer;
@@ -161,10 +161,7 @@ public:
return *Invocation;
}
- CompilerInvocation *takeInvocation() { return Invocation.take(); }
-
- /// setInvocation - Replace the current invocation; the compiler instance
- /// takes ownership of \arg Value.
+ /// setInvocation - Replace the current invocation.
void setInvocation(CompilerInvocation *Value);
/// }
@@ -251,13 +248,13 @@ public:
bool hasDiagnostics() const { return Diagnostics != 0; }
+ /// Get the current diagnostics engine.
Diagnostic &getDiagnostics() const {
assert(Diagnostics && "Compiler instance has no diagnostics!");
return *Diagnostics;
}
- /// setDiagnostics - Replace the current diagnostics engine; the compiler
- /// instance takes ownership of \arg Value.
+ /// setDiagnostics - Replace the current diagnostics engine.
void setDiagnostics(Diagnostic *Value);
DiagnosticClient &getDiagnosticClient() const {
@@ -277,12 +274,7 @@ public:
return *Target;
}
- /// takeTarget - Remove the current diagnostics engine and give ownership
- /// to the caller.
- TargetInfo *takeTarget() { return Target.take(); }
-
- /// setTarget - Replace the current diagnostics engine; the compiler
- /// instance takes ownership of \arg Value.
+ /// Replace the current diagnostics engine.
void setTarget(TargetInfo *Value);
/// }
@@ -291,17 +283,17 @@ public:
bool hasFileManager() const { return FileMgr != 0; }
+ /// Return the current file manager to the caller.
FileManager &getFileManager() const {
assert(FileMgr && "Compiler instance has no file manager!");
return *FileMgr;
}
+
+ void resetAndLeakFileManager() {
+ FileMgr.resetWithoutRelease();
+ }
- /// takeFileManager - Remove the current file manager and give ownership to
- /// the caller.
- FileManager *takeFileManager() { return FileMgr.take(); }
-
- /// setFileManager - Replace the current file manager; the compiler instance
- /// takes ownership of \arg Value.
+ /// setFileManager - Replace the current file manager.
void setFileManager(FileManager *Value);
/// }
@@ -310,17 +302,17 @@ public:
bool hasSourceManager() const { return SourceMgr != 0; }
+ /// Return the current source manager.
SourceManager &getSourceManager() const {
assert(SourceMgr && "Compiler instance has no source manager!");
return *SourceMgr;
}
+
+ void resetAndLeakSourceManager() {
+ SourceMgr.resetWithoutRelease();
+ }
- /// takeSourceManager - Remove the current source manager and give ownership
- /// to the caller.
- SourceManager *takeSourceManager() { return SourceMgr.take(); }
-
- /// setSourceManager - Replace the current source manager; the compiler
- /// instance takes ownership of \arg Value.
+ /// setSourceManager - Replace the current source manager.
void setSourceManager(SourceManager *Value);
/// }
@@ -329,17 +321,17 @@ public:
bool hasPreprocessor() const { return PP != 0; }
+ /// Return the current preprocessor.
Preprocessor &getPreprocessor() const {
assert(PP && "Compiler instance has no preprocessor!");
return *PP;
}
- /// takePreprocessor - Remove the current preprocessor and give ownership to
- /// the caller.
- Preprocessor *takePreprocessor() { return PP.take(); }
+ void resetAndLeakPreprocessor() {
+ PP.resetWithoutRelease();
+ }
- /// setPreprocessor - Replace the current preprocessor; the compiler instance
- /// takes ownership of \arg Value.
+ /// Replace the current preprocessor.
void setPreprocessor(Preprocessor *Value);
/// }
@@ -352,13 +344,12 @@ public:
assert(Context && "Compiler instance has no AST context!");
return *Context;
}
+
+ void resetAndLeakASTContext() {
+ Context.resetWithoutRelease();
+ }
- /// takeASTContext - Remove the current AST context and give ownership to the
- /// caller.
- ASTContext *takeASTContext() { return Context.take(); }
-
- /// setASTContext - Replace the current AST context; the compiler instance
- /// takes ownership of \arg Value.
+ /// setASTContext - Replace the current AST context.
void setASTContext(ASTContext *Value);
/// \brief Replace the current Sema; the compiler instance takes ownership
@@ -479,11 +470,15 @@ public:
/// attached to (and, then, owned by) the returned Diagnostic
/// object.
///
+ /// \param CodeGenOpts If non-NULL, the code gen options in use, which may be
+ /// used by some diagnostics printers (for logging purposes only).
+ ///
/// \return The new object on success, or null on failure.
static llvm::IntrusiveRefCntPtr<Diagnostic>
createDiagnostics(const DiagnosticOptions &Opts, int Argc,
const char* const *Argv,
- DiagnosticClient *Client = 0);
+ DiagnosticClient *Client = 0,
+ const CodeGenOptions *CodeGenOpts = 0);
/// Create the file manager and replace any existing one with it.
void createFileManager();
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index e0329dbc96ec..e18f3fe63249 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -22,6 +22,7 @@
#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringMap.h"
#include <string>
@@ -41,7 +42,7 @@ class Diagnostic;
/// This class is designed to represent an abstract "invocation" of the
/// compiler, including data such as the include paths, the code generation
/// options, the warning flags, and so on.
-class CompilerInvocation {
+class CompilerInvocation : public llvm::RefCountedBase<CompilerInvocation> {
/// Options controlling the static analyzer.
AnalyzerOptions AnalyzerOpts;
diff --git a/include/clang/Frontend/DeclContextXML.def b/include/clang/Frontend/DeclContextXML.def
deleted file mode 100644
index 39ed5f9432b6..000000000000
--- a/include/clang/Frontend/DeclContextXML.def
+++ /dev/null
@@ -1,113 +0,0 @@
-//===-- DeclContextXML.def - Metadata about Context XML nodes ---*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the XML context info database as written in the
-// <ReferenceSection>/<Contexts> sub-nodes of the XML document. Type nodes
-// are referred by "context" reference attributes throughout the document.
-// A context node never contains sub-nodes.
-// The semantics of the attributes and enums are mostly self-documenting
-// by looking at the appropriate internally used functions and values.
-// The following macros are used:
-//
-// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete
-// context of class CLASS where CLASS is a class name used internally by clang.
-// After a NODE_XML the definition of all (optional) attributes of that context
-// node and possible sub-nodes follows.
-//
-// END_NODE_XML - Closes the attribute definition of the current node.
-//
-// ID_ATTRIBUTE_XML - Context nodes have an "id" attribute containing a
-// string, which value uniquely identify that statement. Other nodes may refer
-// by "context" attributes to this value.
-//
-// TYPE_ATTRIBUTE_XML( FN ) - Context nodes may refer to the ids of type
-// nodes by a "type" attribute, if they create a type during declaration.
-// For instance 'struct S;' creates both a context 'S::' and a type 'S'.
-// Contexts and types always have different ids, however declarations and
-// contexts may share the same ids. FN is internally used by clang.
-//
-// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally
-// used by clang. A boolean attribute have the values "0" or "1".
-//
-// ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value
-// is an enumeration defined with ENUM_XML macros immediately following after
-// that macro. An optional attribute is ommited, if the particular enum is the
-// empty string. FN is internally used by clang.
-//
-// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is
-// internally used by clang.
-//
-// END_ENUM_XML - Closes the enumeration definition of the current attribute.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef TYPE_ATTRIBUTE_XML
-# define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
-#endif
-
-#ifndef CONTEXT_ATTRIBUTE_XML
-# define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
-#endif
-
-NODE_XML(TranslationUnitDecl, "TranslationUnit")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(FunctionDecl, "Function")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAsFunctionType())
-END_NODE_XML
-
-NODE_XML(NamespaceDecl, "Namespace")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
-END_NODE_XML
-
-NODE_XML(RecordDecl, "Record")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getTypeForDecl())
-END_NODE_XML
-
-NODE_XML(EnumDecl, "Enum")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getTypeForDecl())
-END_NODE_XML
-
-NODE_XML(LinkageSpecDecl, "LinkageSpec")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_ENUM_OPT_XML(getLanguage(), "lang")
- ENUM_XML(LinkageSpecDecl::lang_c, "C")
- ENUM_XML(LinkageSpecDecl::lang_cxx, "CXX")
- END_ENUM_XML
-END_NODE_XML
-
-//===----------------------------------------------------------------------===//
-#undef NODE_XML
-#undef ID_ATTRIBUTE_XML
-#undef TYPE_ATTRIBUTE_XML
-#undef ATTRIBUTE_XML
-#undef ATTRIBUTE_SPECIAL_XML
-#undef ATTRIBUTE_OPT_XML
-#undef ATTRIBUTE_ENUM_XML
-#undef ATTRIBUTE_ENUM_OPT_XML
-#undef ATTRIBUTE_FILE_LOCATION_XML
-#undef ENUM_XML
-#undef END_ENUM_XML
-#undef END_NODE_XML
-#undef SUB_NODE_XML
-#undef SUB_NODE_SEQUENCE_XML
-#undef SUB_NODE_OPT_XML
diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def
deleted file mode 100644
index 58f7e55fbe80..000000000000
--- a/include/clang/Frontend/DeclXML.def
+++ /dev/null
@@ -1,372 +0,0 @@
-//===-- DeclXML.def - Metadata about Decl XML nodes ------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the XML statement database structure as written in
-// <TranslationUnit> sub-nodes of the XML document.
-// The semantics of the attributes and enums are mostly self-documenting
-// by looking at the appropriate internally used functions and values.
-// The following macros are used:
-//
-// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete
-// statement of class CLASS where CLASS is a class name used internally by clang.
-// After a NODE_XML the definition of all (optional) attributes of that statement
-// node and possible sub-nodes follows.
-//
-// END_NODE_XML - Closes the attribute definition of the current node.
-//
-// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a
-// string, which value uniquely identify that statement. Other nodes may refer
-// by reference attributes to this value (currently used only for Label).
-//
-// TYPE_ATTRIBUTE_XML( FN ) - Type nodes refer to the result type id of an
-// expression by a "type" attribute. FN is internally used by clang.
-//
-// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally
-// used by clang. A boolean attribute have the values "0" or "1".
-//
-// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves
-// a special handling. See the appropriate documentations.
-//
-// ATTRIBUTE_FILE_LOCATION_XML - A bunch of attributes denoting the location of
-// a statement in the source file(s).
-//
-// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME.
-// Optional attributes are omitted for boolean types, if the value is false,
-// for integral types, if the value is null and for strings,
-// if the value is the empty string. FN is internally used by clang.
-//
-// ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value
-// is an enumeration defined with ENUM_XML macros immediately following after
-// that macro. An optional attribute is ommited, if the particular enum is the
-// empty string. FN is internally used by clang.
-//
-// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is
-// internally used by clang.
-//
-// END_ENUM_XML - Closes the enumeration definition of the current attribute.
-//
-// SUB_NODE_XML( CLASS ) - A mandatory sub-node of class CLASS or its sub-classes.
-//
-// SUB_NODE_OPT_XML( CLASS ) - An optional sub-node of class CLASS or its sub-classes.
-//
-// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or
-// its sub-classes.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ATTRIBUTE_FILE_LOCATION_XML
-# define ATTRIBUTE_FILE_LOCATION_XML \
- ATTRIBUTE_XML(getFilename(), "file") \
- ATTRIBUTE_XML(getLine(), "line") \
- ATTRIBUTE_XML(getColumn(), "col") \
- ATTRIBUTE_OPT_XML(getFilename(), "endfile") \
- ATTRIBUTE_OPT_XML(getLine(), "endline") \
- ATTRIBUTE_OPT_XML(getColumn(), "endcol")
-#endif
-
-#ifndef TYPE_ATTRIBUTE_XML
-# define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
-#endif
-
-#ifndef CONTEXT_ATTRIBUTE_XML
-# define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
-#endif
-
-//NODE_XML(TranslationUnitDecl, "TranslationUnit")
-// SUB_NODE_SEQUENCE_XML(Decl)
-//END_NODE_XML
-
-NODE_XML(Decl, "FIXME_Decl")
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclKindName(), "unhandled_decl_name")
-END_NODE_XML
-
-NODE_XML(FunctionDecl, "Function")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
- ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
- ATTRIBUTE_ENUM_OPT_XML(getStorageClass(), "storage_class")
- ENUM_XML(SC_None, "")
- ENUM_XML(SC_Extern, "extern")
- ENUM_XML(SC_Static, "static")
- ENUM_XML(SC_PrivateExtern, "__private_extern__")
- END_ENUM_XML
- ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
- //ATTRIBUTE_OPT_XML(isVariadic(), "variadic") // in the type reference
- ATTRIBUTE_XML(getNumParams(), "num_args")
- ATTRIBUTE_OPT_XML(isMain(), "main")
- ATTRIBUTE_OPT_XML(isExternC(), "externc")
- ATTRIBUTE_OPT_XML(isGlobal(), "global")
- SUB_NODE_SEQUENCE_XML(ParmVarDecl)
- SUB_NODE_FN_BODY_XML
-END_NODE_XML
-
-NODE_XML(CXXMethodDecl, "CXXMethod")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
- ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
- ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
- ATTRIBUTE_OPT_XML(isStatic(), "static")
- ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
- ATTRIBUTE_OPT_XML(isPure(), "pure")
- ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
- ENUM_XML(AS_none, "")
- ENUM_XML(AS_public, "public")
- ENUM_XML(AS_protected, "protected")
- ENUM_XML(AS_private, "private")
- END_ENUM_XML
- ATTRIBUTE_XML(getNumParams(), "num_args")
- SUB_NODE_SEQUENCE_XML(ParmVarDecl)
- SUB_NODE_FN_BODY_XML
-END_NODE_XML
-
-NODE_XML(CXXConstructorDecl, "CXXConstructor")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
- ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
- ATTRIBUTE_OPT_XML(isExplicit(), "is_explicit")
- ATTRIBUTE_OPT_XML(isDefaultConstructor(), "is_default_ctor")
- ATTRIBUTE_OPT_XML(isCopyConstructor(), "is_copy_ctor")
- ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
- ATTRIBUTE_OPT_XML(isStatic(), "static")
- ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
- ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
- ENUM_XML(AS_none, "")
- ENUM_XML(AS_public, "public")
- ENUM_XML(AS_protected, "protected")
- ENUM_XML(AS_private, "private")
- END_ENUM_XML
- ATTRIBUTE_XML(getNumParams(), "num_args")
- SUB_NODE_SEQUENCE_XML(ParmVarDecl)
- SUB_NODE_FN_BODY_XML
-END_NODE_XML
-
-NODE_XML(CXXDestructorDecl, "CXXDestructor")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
- ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
- ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
- ATTRIBUTE_OPT_XML(isStatic(), "static")
- ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
- ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
- ENUM_XML(AS_none, "")
- ENUM_XML(AS_public, "public")
- ENUM_XML(AS_protected, "protected")
- ENUM_XML(AS_private, "private")
- END_ENUM_XML
- ATTRIBUTE_XML(getNumParams(), "num_args")
- SUB_NODE_SEQUENCE_XML(ParmVarDecl)
- SUB_NODE_FN_BODY_XML
-END_NODE_XML
-
-NODE_XML(CXXConversionDecl, "CXXConversion")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType()->getAs<FunctionType>()->getResultType())
- ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "function_type")
- ATTRIBUTE_OPT_XML(isExplicit(), "is_explicit")
- ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline")
- ATTRIBUTE_OPT_XML(isStatic(), "static")
- ATTRIBUTE_OPT_XML(isVirtual(), "virtual")
- ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
- ENUM_XML(AS_none, "")
- ENUM_XML(AS_public, "public")
- ENUM_XML(AS_protected, "protected")
- ENUM_XML(AS_private, "private")
- END_ENUM_XML
- ATTRIBUTE_XML(getNumParams(), "num_args")
- SUB_NODE_SEQUENCE_XML(ParmVarDecl)
- SUB_NODE_FN_BODY_XML
-END_NODE_XML
-
-NODE_XML(NamespaceDecl, "Namespace")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- SUB_NODE_SEQUENCE_XML(DeclContext)
-END_NODE_XML
-
-NODE_XML(UsingDirectiveDecl, "UsingDirective")
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- ATTRIBUTE_XML(getNominatedNamespace(), "ref")
-END_NODE_XML
-
-NODE_XML(NamespaceAliasDecl, "NamespaceAlias")
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- ATTRIBUTE_XML(getNamespace(), "ref")
-END_NODE_XML
-
-NODE_XML(RecordDecl, "Record")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- ATTRIBUTE_OPT_XML(isDefinition() == false, "forward")
- ATTRIBUTE_XML(getTypeForDecl(), "type") // refers to the type this decl creates
- SUB_NODE_SEQUENCE_XML(FieldDecl)
-END_NODE_XML
-
-NODE_XML(CXXRecordDecl, "CXXRecord")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- ATTRIBUTE_OPT_XML(isDefinition() == false, "forward")
- ATTRIBUTE_XML(getTypeForDecl(), "type") // refers to the type this decl creates
- SUB_NODE_SEQUENCE_XML(FieldDecl)
-END_NODE_XML
-
-NODE_XML(EnumDecl, "Enum")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- ATTRIBUTE_OPT_XML(isDefinition() == false, "forward")
- ATTRIBUTE_SPECIAL_XML(getIntegerType(), "type") // is NULL in pure declarations thus deserves special handling
- SUB_NODE_SEQUENCE_XML(EnumConstantDecl) // only present in definition
-END_NODE_XML
-
-NODE_XML(EnumConstantDecl, "EnumConstant")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getInitVal().toString(10, true), "value") // integer
- SUB_NODE_OPT_XML(Expr) // init expr of this constant
-END_NODE_XML
-
-NODE_XML(FieldDecl, "Field")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_OPT_XML(isMutable(), "mutable")
- ATTRIBUTE_ENUM_OPT_XML(getAccess(), "access")
- ENUM_XML(AS_none, "")
- ENUM_XML(AS_public, "public")
- ENUM_XML(AS_protected, "protected")
- ENUM_XML(AS_private, "private")
- END_ENUM_XML
- ATTRIBUTE_OPT_XML(isBitField(), "bitfield")
- SUB_NODE_OPT_XML(Expr) // init expr of a bit field
-END_NODE_XML
-
-NODE_XML(TypedefDecl, "Typedef")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getUnderlyingType())
-END_NODE_XML
-
-NODE_XML(VarDecl, "Var")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_ENUM_OPT_XML(getStorageClass(), "storage_class")
- ENUM_XML(SC_None, "")
- ENUM_XML(SC_Auto, "auto")
- ENUM_XML(SC_Register, "register")
- ENUM_XML(SC_Extern, "extern")
- ENUM_XML(SC_Static, "static")
- ENUM_XML(SC_PrivateExtern, "__private_extern__")
- END_ENUM_XML
- SUB_NODE_OPT_XML(Expr) // init expr
-END_NODE_XML
-
-NODE_XML(ParmVarDecl, "ParmVar")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_OPT_XML(Expr) // default argument expression
-END_NODE_XML
-
-NODE_XML(LinkageSpecDecl, "LinkageSpec")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_ENUM_OPT_XML(getLanguage(), "lang")
- ENUM_XML(LinkageSpecDecl::lang_c, "C")
- ENUM_XML(LinkageSpecDecl::lang_cxx, "CXX")
- END_ENUM_XML
- SUB_NODE_XML(DeclContext)
-END_NODE_XML
-
-NODE_XML(TemplateDecl, "Template")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
-END_NODE_XML
-
-NODE_XML(TemplateTypeParmDecl, "TemplateTypeParm")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getNameAsString(), "name")
-END_NODE_XML
-
-NODE_XML(UsingShadowDecl, "UsingShadow")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getTargetDecl(), "target_decl")
- ATTRIBUTE_XML(getUsingDecl(), "using_decl")
-END_NODE_XML
-
-NODE_XML(UsingDecl, "Using")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getDeclContext(), "context")
- ATTRIBUTE_XML(getQualifier(), "target_nested_namespace_decl")
- ATTRIBUTE_XML(isTypeName(), "is_typename")
-END_NODE_XML
-
-//===----------------------------------------------------------------------===//
-#undef NODE_XML
-#undef ID_ATTRIBUTE_XML
-#undef TYPE_ATTRIBUTE_XML
-#undef ATTRIBUTE_XML
-#undef ATTRIBUTE_SPECIAL_XML
-#undef ATTRIBUTE_OPT_XML
-#undef ATTRIBUTE_ENUM_XML
-#undef ATTRIBUTE_ENUM_OPT_XML
-#undef ATTRIBUTE_FILE_LOCATION_XML
-#undef ENUM_XML
-#undef END_ENUM_XML
-#undef END_NODE_XML
-#undef SUB_NODE_XML
-#undef SUB_NODE_SEQUENCE_XML
-#undef SUB_NODE_OPT_XML
-#undef SUB_NODE_FN_BODY_XML
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index f7f498bff024..ff92058f01df 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -31,8 +31,10 @@ public:
unsigned ShowFixits : 1; /// Show fixit information.
unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form.
unsigned ShowParseableFixits : 1; /// Show machine parseable fix-its.
- unsigned ShowOptionNames : 1; /// Show the diagnostic name for mappable
+ unsigned ShowNames : 1; /// Show the diagnostic name
+ unsigned ShowOptionNames : 1; /// Show the option name for mappable
/// diagnostics.
+ unsigned ShowNoteIncludeStack : 1; /// Show include stacks for notes.
unsigned ShowCategories : 2; /// Show categories: 0 -> none, 1 -> Number,
/// 2 -> Full Name.
unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences.
@@ -60,6 +62,9 @@ public:
/// testing and analysis.
std::string DumpBuildInformation;
+ /// The file to log diagnostic output to.
+ std::string DiagnosticLogFile;
+
/// The list of -W... options used to alter the diagnostic mappings, with the
/// prefixes removed.
std::vector<std::string> Warnings;
@@ -78,6 +83,7 @@ public:
ShowColumn = 1;
ShowFixits = 1;
ShowLocation = 1;
+ ShowNames = 0;
ShowOptionNames = 0;
ShowCategories = 0;
ShowSourceRanges = 0;
diff --git a/include/clang/Frontend/DocumentXML.def b/include/clang/Frontend/DocumentXML.def
deleted file mode 100644
index 4c52bd84422f..000000000000
--- a/include/clang/Frontend/DocumentXML.def
+++ /dev/null
@@ -1,75 +0,0 @@
-//===-- DocumentXML.def - Metadata about Document XML nodes -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the XML root database structure as written in
-// an AST XML document.
-// The following macros are used:
-//
-// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete
-// statement of class CLASS where CLASS is a class name used internally by clang.
-// After a NODE_XML the definition of all (optional) attributes of that statement
-// node and possible sub-nodes follows.
-//
-// END_NODE_XML - Closes the attribute definition of the current node.
-//
-// ID_ATTRIBUTE_XML - Some nodes have an "id" attribute containing a
-// string, which value uniquely identify the entity represented by that node.
-// Other nodes may refer by reference attributes to this value.
-//
-// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves
-// a special handling. See the appropriate documentations.
-//
-// SUB_NODE_XML( CLASS ) - A mandatory sub-node of class CLASS or its sub-classes.
-//
-// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or
-// its sub-classes.
-//
-//===----------------------------------------------------------------------===//
-
-ROOT_NODE_XML("CLANG_XML")
- ATTRIBUTE_SPECIAL_XML(ignore, "version") // special retrieving needed
- SUB_NODE_XML("TranslationUnit")
- SUB_NODE_XML("ReferenceSection")
-END_NODE_XML
-
-NODE_XML("TranslationUnit")
- SUB_NODE_SEQUENCE_XML(Decl)
-END_NODE_XML
-
-NODE_XML("ReferenceSection")
- SUB_NODE_XML("Types")
- SUB_NODE_XML("Contexts")
- SUB_NODE_XML("Files")
-END_NODE_XML
-
-NODE_XML("Types")
- SUB_NODE_SEQUENCE_XML(Type)
-END_NODE_XML
-
-NODE_XML("Contexts")
- SUB_NODE_SEQUENCE_XML(DeclContext)
-END_NODE_XML
-
-NODE_XML("Files")
- SUB_NODE_SEQUENCE_XML("File")
-END_NODE_XML
-
-NODE_XML("File")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_SPECIAL_XML(ignore, "name") // special retrieving needed, denotes the source file name
-END_NODE_XML
-
-
-//===----------------------------------------------------------------------===//
-#undef NODE_XML
-#undef ID_ATTRIBUTE_XML
-#undef ATTRIBUTE_SPECIAL_XML
-#undef END_NODE_XML
-#undef SUB_NODE_XML
-#undef SUB_NODE_SEQUENCE_XML
diff --git a/include/clang/Frontend/DocumentXML.h b/include/clang/Frontend/DocumentXML.h
deleted file mode 100644
index 602d84655828..000000000000
--- a/include/clang/Frontend/DocumentXML.h
+++ /dev/null
@@ -1,185 +0,0 @@
-//===--- DocumentXML.h - XML document for ASTs ------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the XML document class, which provides the means to
-// dump out the AST in a XML form that exposes type details and other fields.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_FRONTEND_DOCUMENTXML_H
-#define LLVM_CLANG_FRONTEND_DOCUMENTXML_H
-
-#include <string>
-#include <map>
-#include <stack>
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeOrdering.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/DenseMap.h"
-
-namespace clang {
-
-//--------------------------------------------------------- forwards
-class DeclContext;
-class Decl;
-class NamedDecl;
-class FunctionDecl;
-class ASTContext;
-class LabelStmt;
-
-//---------------------------------------------------------
-namespace XML {
- // id maps:
- template<class T>
- struct IdMap : llvm::DenseMap<T, unsigned> {};
-
- template<>
- struct IdMap<QualType> : std::map<QualType, unsigned, QualTypeOrdering> {};
-
- template<>
- struct IdMap<std::string> : std::map<std::string, unsigned> {};
-}
-
-//---------------------------------------------------------
-class DocumentXML {
-public:
- DocumentXML(const std::string& rootName, llvm::raw_ostream& out);
-
- void initialize(ASTContext &Context);
- void PrintDecl(Decl *D);
- void PrintStmt(const Stmt *S); // defined in StmtXML.cpp
- void finalize();
-
-
- DocumentXML& addSubNode(const std::string& name); // also enters the sub node, returns *this
- DocumentXML& toParent(); // returns *this
-
- void addAttribute(const char* pName, const QualType& pType);
- void addAttribute(const char* pName, bool value);
-
- template<class T>
- void addAttribute(const char* pName, const T* value) {
- addPtrAttribute(pName, value);
- }
-
- template<class T>
- void addAttribute(const char* pName, T* value) {
- addPtrAttribute(pName, value);
- }
-
- template<class T>
- void addAttribute(const char* pName, const T& value);
-
- template<class T>
- void addAttributeOptional(const char* pName, const T& value);
-
- void addSourceFileAttribute(const std::string& fileName);
-
- PresumedLoc addLocation(const SourceLocation& Loc);
- void addLocationRange(const SourceRange& R);
-
- static std::string escapeString(const char* pStr, std::string::size_type len);
-
-private:
- DocumentXML(const DocumentXML&); // not defined
- DocumentXML& operator=(const DocumentXML&); // not defined
-
- std::stack<std::string> NodeStack;
- llvm::raw_ostream& Out;
- ASTContext *Ctx;
- bool HasCurrentNodeSubNodes;
-
-
- XML::IdMap<QualType> Types;
- XML::IdMap<const DeclContext*> Contexts;
- XML::IdMap<const Type*> BasicTypes;
- XML::IdMap<std::string> SourceFiles;
- XML::IdMap<const NamedDecl*> Decls;
- XML::IdMap<const LabelStmt*> Labels;
-
- void addContextsRecursively(const DeclContext *DC);
- void addTypeRecursively(const Type* pType);
- void addTypeRecursively(const QualType& pType);
-
- void Indent();
-
- // forced pointer dispatch:
- void addPtrAttribute(const char* pName, const Type* pType);
- void addPtrAttribute(const char* pName, const NamedDecl* D);
- void addPtrAttribute(const char* pName, const DeclContext* D);
- void addPtrAttribute(const char* pName, const NamespaceDecl* D); // disambiguation
- void addPtrAttribute(const char* pName, const NestedNameSpecifier* N);
- void addPtrAttribute(const char* pName, const LabelStmt* L);
- void addPtrAttribute(const char* pName, const char* text);
-
- // defined in TypeXML.cpp:
- void addParentTypes(const Type* pType);
- void writeTypeToXML(const Type* pType);
- void writeTypeToXML(const QualType& pType);
- class TypeAdder;
- friend class TypeAdder;
-
- // defined in DeclXML.cpp:
- void writeDeclToXML(Decl *D);
- class DeclPrinter;
- friend class DeclPrinter;
-
- // for addAttributeOptional:
- static bool isDefault(unsigned value) { return value == 0; }
- static bool isDefault(bool value) { return !value; }
- static bool isDefault(Qualifiers::GC value) { return value == Qualifiers::GCNone; }
- static bool isDefault(const std::string& value) { return value.empty(); }
-};
-
-//--------------------------------------------------------- inlines
-
-inline void DocumentXML::initialize(ASTContext &Context) {
- Ctx = &Context;
-}
-
-//---------------------------------------------------------
-template<class T>
-inline void DocumentXML::addAttribute(const char* pName, const T& value) {
- std::string repr;
- {
- llvm::raw_string_ostream buf(repr);
- buf << value;
- }
-
- Out << ' ' << pName << "=\""
- << DocumentXML::escapeString(repr.c_str(), repr.size())
- << "\"";
-}
-
-//---------------------------------------------------------
-inline void DocumentXML::addPtrAttribute(const char* pName, const char* text) {
- Out << ' ' << pName << "=\""
- << DocumentXML::escapeString(text, strlen(text))
- << "\"";
-}
-
-//---------------------------------------------------------
-inline void DocumentXML::addAttribute(const char* pName, bool value) {
- addPtrAttribute(pName, value ? "1" : "0");
-}
-
-//---------------------------------------------------------
-template<class T>
-inline void DocumentXML::addAttributeOptional(const char* pName,
- const T& value) {
- if (!isDefault(value)) {
- addAttribute(pName, value);
- }
-}
-
-//---------------------------------------------------------
-
-} //namespace clang
-
-#endif //LLVM_CLANG_DOCUMENTXML_H
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 4df2e71571f7..4e67449b8549 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -42,12 +42,6 @@ protected:
llvm::StringRef InFile);
};
-class ASTPrintXMLAction : public ASTFrontendAction {
-protected:
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
-};
-
class ASTDumpAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
index 2efbc818de1b..3e9508c009c8 100644
--- a/include/clang/Frontend/FrontendDiagnostic.h
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -15,7 +15,8 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#define FRONTENDSTART
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#undef DIAG
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 19d39c3ca1b2..02f6f868fe49 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -23,7 +23,6 @@ namespace frontend {
ASTDump, ///< Parse ASTs and dump them.
ASTDumpXML, ///< Parse ASTs and dump them in XML.
ASTPrint, ///< Parse ASTs and print them.
- ASTPrintXML, ///< Parse ASTs and print them in XML.
ASTView, ///< Parse ASTs and view them in Graphviz.
BoostCon, ///< BoostCon mode.
CreateModule, ///< Create module definition
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index 441d34f5a388..74ca5191dd48 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -19,12 +19,13 @@ namespace frontend {
enum LangFeatures {
BCPLComment = (1 << 0),
C99 = (1 << 1),
- CPlusPlus = (1 << 2),
- CPlusPlus0x = (1 << 3),
- Digraphs = (1 << 4),
- GNUMode = (1 << 5),
- HexFloat = (1 << 6),
- ImplicitInt = (1 << 7)
+ C1X = (1 << 2),
+ CPlusPlus = (1 << 3),
+ CPlusPlus0x = (1 << 4),
+ Digraphs = (1 << 5),
+ GNUMode = (1 << 6),
+ HexFloat = (1 << 7),
+ ImplicitInt = (1 << 8)
};
}
@@ -56,6 +57,9 @@ public:
/// isC99 - Language is a superset of C99.
bool isC99() const { return Flags & frontend::C99; }
+ /// isC1X - Language is a superset of C1X.
+ bool isC1X() const { return Flags & frontend::C1X; }
+
/// isCPlusPlus - Language is a C++ variant.
bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; }
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index d4046b3e5668..586e5c8fa2a4 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -54,11 +54,23 @@ LANGSTANDARD(iso9899_199x,
LANGSTANDARD(gnu99, "gnu99",
"ISO C 1999 with GNU extensions",
- BCPLComment | C99 | Digraphs | GNUMode | HexFloat | Digraphs)
+ BCPLComment | C99 | Digraphs | GNUMode | HexFloat)
LANGSTANDARD(gnu9x, "gnu9x",
"ISO C 1999 with GNU extensions",
BCPLComment | C99 | Digraphs | GNUMode | HexFloat)
+// C1X modes
+LANGSTANDARD(c1x, "c1x",
+ "ISO C 201X",
+ BCPLComment | C99 | C1X | Digraphs | HexFloat)
+LANGSTANDARD(iso9899_201x,
+ "iso9899:201x", "ISO C 201X",
+ BCPLComment | C99 | C1X | Digraphs | HexFloat)
+
+LANGSTANDARD(gnu1x, "gnu1x",
+ "ISO C 201X with GNU extensions",
+ BCPLComment | C99 | C1X | Digraphs | GNUMode | HexFloat)
+
// C++ modes
LANGSTANDARD(cxx98, "c++98",
"ISO C++ 1998 with amendments",
diff --git a/include/clang/Frontend/LogDiagnosticPrinter.h b/include/clang/Frontend/LogDiagnosticPrinter.h
new file mode 100644
index 000000000000..b6fc23ca1f04
--- /dev/null
+++ b/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -0,0 +1,77 @@
+//===--- LogDiagnosticPrinter.h - Log Diagnostic Client ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_LOG_DIAGNOSTIC_PRINTER_H_
+#define LLVM_CLANG_FRONTEND_LOG_DIAGNOSTIC_PRINTER_H_
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+class DiagnosticOptions;
+class LangOptions;
+
+class LogDiagnosticPrinter : public DiagnosticClient {
+ struct DiagEntry {
+ /// The primary message line of the diagnostic.
+ std::string Message;
+
+ /// The source file name, if available.
+ std::string Filename;
+
+ /// The source file line number, if available.
+ unsigned Line;
+
+ /// The source file column number, if available.
+ unsigned Column;
+
+ /// The ID of the diagnostic.
+ unsigned DiagnosticID;
+
+ /// The level of the diagnostic.
+ Diagnostic::Level DiagnosticLevel;
+ };
+
+ llvm::raw_ostream &OS;
+ const LangOptions *LangOpts;
+ const DiagnosticOptions *DiagOpts;
+
+ SourceLocation LastWarningLoc;
+ FullSourceLoc LastLoc;
+ unsigned OwnsOutputStream : 1;
+
+ llvm::SmallVector<DiagEntry, 8> Entries;
+
+ std::string MainFilename;
+ std::string DwarfDebugFlags;
+
+public:
+ LogDiagnosticPrinter(llvm::raw_ostream &OS, const DiagnosticOptions &Diags,
+ bool OwnsOutputStream = false);
+ virtual ~LogDiagnosticPrinter();
+
+ void setDwarfDebugFlags(llvm::StringRef Value) {
+ DwarfDebugFlags = Value;
+ }
+
+ void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) {
+ LangOpts = &LO;
+ }
+
+ void EndSourceFile();
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h
index 560178be9bf8..4242f0117147 100644
--- a/include/clang/Frontend/MultiplexConsumer.h
+++ b/include/clang/Frontend/MultiplexConsumer.h
@@ -12,6 +12,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef CLANG_FRONTEND_MULTIPLEXCONSUMER_H
+#define CLANG_FRONTEND_MULTIPLEXCONSUMER_H
+
#include "clang/Sema/SemaConsumer.h"
#include "llvm/ADT/OwningPtr.h"
#include <vector>
@@ -52,3 +55,5 @@ private:
};
} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index 0d52e53ea16a..e875ec1fefd2 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -44,6 +44,9 @@ public:
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
+ /// \brief Headers that will be converted to chained PCHs in memory.
+ std::vector<std::string> ChainedIncludes;
+
/// \brief When true, disables most of the normal validation performed on
/// precompiled headers.
bool DisablePCHValidation;
@@ -73,6 +76,10 @@ public:
/// If given, a PTH cache file to use for speeding up header parsing.
std::string TokenCache;
+ /// \brief True if the SourceManager should report the original file name for
+ /// contents of files that were remapped to other files. Defaults to true.
+ bool RemappedFilesKeepOriginalName;
+
/// \brief The set of file remappings, which take existing files on
/// the system (the first part of each pair) and gives them the
/// contents of other files on the system (the second part of each
@@ -132,6 +139,7 @@ public:
DisablePCHValidation(false), DisableStatCache(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
+ RemappedFilesKeepOriginalName(true),
RetainRemappedFileBuffers(false) { }
void addMacroDef(llvm::StringRef Name) {
diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def
deleted file mode 100644
index 8a859e6898b1..000000000000
--- a/include/clang/Frontend/StmtXML.def
+++ /dev/null
@@ -1,520 +0,0 @@
-//===-- StmtXML.def - Metadata about Stmt XML nodes ------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the XML statement database structure as written in
-// <TranslationUnit> sub-nodes of the XML document.
-// The semantics of the attributes and enums are mostly self-documenting
-// by looking at the appropriate internally used functions and values.
-// The following macros are used:
-//
-// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete
-// statement of class CLASS where CLASS is a class name used internally by clang.
-// After a NODE_XML the definition of all (optional) attributes of that statement
-// node and possible sub-nodes follows.
-//
-// END_NODE_XML - Closes the attribute definition of the current node.
-//
-// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a
-// string, which value uniquely identify that statement. Other nodes may refer
-// by reference attributes to this value (currently used only for Label).
-//
-// TYPE_ATTRIBUTE_XML( FN ) - Type nodes refer to the result type id of an
-// expression by a "type" attribute. FN is internally used by clang.
-//
-// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally
-// used by clang. A boolean attribute have the values "0" or "1".
-//
-// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves
-// a special handling. See the appropriate documentations.
-//
-// ATTRIBUTE_FILE_LOCATION_XML - A bunch of attributes denoting the location of
-// a statement in the source file(s).
-//
-// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME.
-// Optional attributes are omitted for boolean types, if the value is false,
-// for integral types, if the value is null and for strings,
-// if the value is the empty string. FN is internally used by clang.
-//
-// ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value
-// is an enumeration defined with ENUM_XML macros immediately following after
-// that macro. An optional attribute is ommited, if the particular enum is the
-// empty string. FN is internally used by clang.
-//
-// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is
-// internally used by clang.
-//
-// END_ENUM_XML - Closes the enumeration definition of the current attribute.
-//
-// SUB_NODE_XML( CLASS ) - A mandatory sub-node of class CLASS or its sub-classes.
-//
-// SUB_NODE_OPT_XML( CLASS ) - An optional sub-node of class CLASS or its sub-classes.
-//
-// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or
-// its sub-classes.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ATTRIBUTE_FILE_LOCATION_XML
-# define ATTRIBUTE_FILE_LOCATION_XML \
- ATTRIBUTE_XML(getFilename(), "file") \
- ATTRIBUTE_XML(getLine(), "line") \
- ATTRIBUTE_XML(getColumn(), "col") \
- ATTRIBUTE_OPT_XML(getFilename(), "endfile") \
- ATTRIBUTE_OPT_XML(getLine(), "endline") \
- ATTRIBUTE_OPT_XML(getColumn(), "endcol")
-#endif
-
-#ifndef TYPE_ATTRIBUTE_XML
-# define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
-#endif
-
-#ifndef CONTEXT_ATTRIBUTE_XML
-# define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
-#endif
-
-NODE_XML(Stmt, "Stmt_Unsupported") // fallback for unsupproted statements
- ATTRIBUTE_FILE_LOCATION_XML
-END_NODE_XML
-
-NODE_XML(NullStmt, "NullStmt")
- ATTRIBUTE_FILE_LOCATION_XML
-END_NODE_XML
-
-NODE_XML(CompoundStmt, "CompoundStmt")
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(size(), "num_stmts")
- SUB_NODE_SEQUENCE_XML(Stmt)
-END_NODE_XML
-
-NODE_XML(CaseStmt, "CaseStmt") // case expr: body;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Stmt) // body
- SUB_NODE_XML(Expr) // expr
- SUB_NODE_XML(Expr) // rhs expr in gc extension: case expr .. expr: body;
-END_NODE_XML
-
-NODE_XML(DefaultStmt, "DefaultStmt") // default: body;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Stmt) // body
-END_NODE_XML
-
-NODE_XML(LabelStmt, "LabelStmt") // Label: body;
- ID_ATTRIBUTE_XML
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getName(), "name") // string
- SUB_NODE_XML(Stmt) // body
-END_NODE_XML
-
-NODE_XML(IfStmt, "IfStmt") // if (cond) stmt1; else stmt2;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Expr) // cond
- SUB_NODE_XML(Stmt) // stmt1
- SUB_NODE_XML(Stmt) // stmt2
-END_NODE_XML
-
-NODE_XML(SwitchStmt, "SwitchStmt") // switch (cond) body;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Expr) // cond
- SUB_NODE_XML(Stmt) // body
-END_NODE_XML
-
-NODE_XML(WhileStmt, "WhileStmt") // while (cond) body;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Expr) // cond
- SUB_NODE_XML(Stmt) // body
-END_NODE_XML
-
-NODE_XML(DoStmt, "DoStmt") // do body while (cond);
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Expr) // cond
- SUB_NODE_XML(Stmt) // body
-END_NODE_XML
-
-NODE_XML(ForStmt, "ForStmt") // for (init; cond; inc) body;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Stmt) // init
- SUB_NODE_XML(Expr) // cond
- SUB_NODE_XML(Expr) // inc
- SUB_NODE_XML(Stmt) // body
-END_NODE_XML
-
-NODE_XML(GotoStmt, "GotoStmt") // goto label;
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getLabel()->getName(), "name") // informal string
- ATTRIBUTE_XML(getLabel(), "ref") // id string
-END_NODE_XML
-
-NODE_XML(IndirectGotoStmt, "IndirectGotoStmt") // goto expr;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-NODE_XML(ContinueStmt, "ContinueStmt") // continue
- ATTRIBUTE_FILE_LOCATION_XML
-END_NODE_XML
-
-NODE_XML(BreakStmt, "BreakStmt") // break
- ATTRIBUTE_FILE_LOCATION_XML
-END_NODE_XML
-
-NODE_XML(ReturnStmt, "ReturnStmt") // return expr;
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-NODE_XML(AsmStmt, "AsmStmt") // GNU inline-assembly statement extension
- ATTRIBUTE_FILE_LOCATION_XML
- // FIXME
-END_NODE_XML
-
-NODE_XML(DeclStmt, "DeclStmt") // a declaration statement
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_SEQUENCE_XML(Decl)
-END_NODE_XML
-
-// C++ statements
-NODE_XML(CXXTryStmt, "CXXTryStmt") // try CompoundStmt CXXCatchStmt1 CXXCatchStmt2 ..
- ATTRIBUTE_FILE_LOCATION_XML
- ATTRIBUTE_XML(getNumHandlers(), "num_handlers")
- SUB_NODE_XML(CompoundStmt)
- SUB_NODE_SEQUENCE_XML(CXXCatchStmt)
-END_NODE_XML
-
-NODE_XML(CXXCatchStmt, "CXXCatchStmt") // catch (decl) Stmt
- ATTRIBUTE_FILE_LOCATION_XML
- SUB_NODE_XML(VarDecl)
- SUB_NODE_XML(Stmt)
-END_NODE_XML
-
-// Expressions
-NODE_XML(PredefinedExpr, "PredefinedExpr")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_ENUM_XML(getIdentType(), "kind")
- ENUM_XML(PredefinedExpr::Func, "__func__")
- ENUM_XML(PredefinedExpr::Function, "__FUNCTION__")
- ENUM_XML(PredefinedExpr::PrettyFunction, "__PRETTY_FUNCTION__")
- END_ENUM_XML
-END_NODE_XML
-
-NODE_XML(DeclRefExpr, "DeclRefExpr") // an expression referring to a declared entity
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getDecl(), "ref") // id string of the declaration
- ATTRIBUTE_XML(getDecl()->getNameAsString(), "name") // informal
- //ATTRIBUTE_ENUM_XML(getDecl()->getKind(), "kind") // really needed here?
-END_NODE_XML
-
-NODE_XML(IntegerLiteral, "IntegerLiteral")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getValue(), "value") // (signed) integer
-END_NODE_XML
-
-NODE_XML(CharacterLiteral, "CharacterLiteral")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getValue(), "value") // unsigned
-END_NODE_XML
-
-NODE_XML(FloatingLiteral, "FloatingLiteral")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- // FIXME: output float as written in source (no approximation or the like)
- //ATTRIBUTE_XML(getValueAsApproximateDouble(), "value") // float
-END_NODE_XML
-
-NODE_XML(StringLiteral, "StringLiteral")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_SPECIAL_XML(getStrData(), "value") // string, special handling for escaping needed
- ATTRIBUTE_OPT_XML(isWide(), "is_wide") // boolean
-END_NODE_XML
-
-NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_ENUM_XML(getOpcode(), "kind")
- ENUM_XML(UO_PostInc, "postinc")
- ENUM_XML(UO_PostDec, "postdec")
- ENUM_XML(UO_PreInc, "preinc")
- ENUM_XML(UO_PreDec, "predec")
- ENUM_XML(UO_AddrOf, "addrof")
- ENUM_XML(UO_Deref, "deref")
- ENUM_XML(UO_Plus, "plus")
- ENUM_XML(UO_Minus, "minus")
- ENUM_XML(UO_Not, "not") // bitwise not
- ENUM_XML(UO_LNot, "lnot") // boolean not
- ENUM_XML(UO_Real, "__real")
- ENUM_XML(UO_Imag, "__imag")
- ENUM_XML(UO_Extension, "__extension__")
- END_ENUM_XML
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-NODE_XML(BinaryOperator, "BinaryOperator") // (expr1) op (expr2)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_ENUM_XML(getOpcode(), "kind")
- ENUM_XML(BO_PtrMemD , "ptrmemd")
- ENUM_XML(BO_PtrMemI , "ptrmemi")
- ENUM_XML(BO_Mul , "mul")
- ENUM_XML(BO_Div , "div")
- ENUM_XML(BO_Rem , "rem")
- ENUM_XML(BO_Add , "add")
- ENUM_XML(BO_Sub , "sub")
- ENUM_XML(BO_Shl , "shl")
- ENUM_XML(BO_Shr , "shr")
- ENUM_XML(BO_LT , "lt")
- ENUM_XML(BO_GT , "gt")
- ENUM_XML(BO_LE , "le")
- ENUM_XML(BO_GE , "ge")
- ENUM_XML(BO_EQ , "eq")
- ENUM_XML(BO_NE , "ne")
- ENUM_XML(BO_And , "and") // bitwise and
- ENUM_XML(BO_Xor , "xor")
- ENUM_XML(BO_Or , "or") // bitwise or
- ENUM_XML(BO_LAnd , "land") // boolean and
- ENUM_XML(BO_LOr , "lor") // boolean or
- ENUM_XML(BO_Assign , "assign")
- ENUM_XML(BO_MulAssign, "mulassign")
- ENUM_XML(BO_DivAssign, "divassign")
- ENUM_XML(BO_RemAssign, "remassign")
- ENUM_XML(BO_AddAssign, "addassign")
- ENUM_XML(BO_SubAssign, "subassign")
- ENUM_XML(BO_ShlAssign, "shlassign")
- ENUM_XML(BO_ShrAssign, "shrassign")
- ENUM_XML(BO_AndAssign, "andassign")
- ENUM_XML(BO_XorAssign, "xorassign")
- ENUM_XML(BO_OrAssign , "orassign")
- ENUM_XML(BO_Comma , "comma")
- END_ENUM_XML
- SUB_NODE_XML(Expr) // expr1
- SUB_NODE_XML(Expr) // expr2
-END_NODE_XML
-
-// FIXME: is there a special class needed or is BinaryOperator sufficient?
-//NODE_XML(CompoundAssignOperator, "CompoundAssignOperator")
-
-NODE_XML(ConditionalOperator, "ConditionalOperator") // expr1 ? expr2 : expr3
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(Expr) // expr1
- SUB_NODE_XML(Expr) // expr2
- SUB_NODE_XML(Expr) // expr3
-END_NODE_XML
-
-NODE_XML(OffsetOfExpr, "OffsetOfExpr") // offsetof(basetype, components)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getTypeSourceInfo()->getType())
- ATTRIBUTE_XML(getNumComponents(), "num_components")
- SUB_NODE_SEQUENCE_XML(OffsetOfExpr::OffsetOfNode)
-END_NODE_XML
-
-NODE_XML(SizeOfAlignOfExpr, "SizeOfAlignOfExpr") // sizeof(expr) or alignof(expr)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(isSizeOf(), "is_sizeof")
- ATTRIBUTE_XML(isArgumentType(), "is_type") // "1" if expr denotes a type
- ATTRIBUTE_SPECIAL_XML(getArgumentType(), "type_ref") // optional, denotes the type of expr, if is_type=="1", special handling needed since getArgumentType() could assert
- SUB_NODE_OPT_XML(Expr) // expr, if is_type=="0"
-END_NODE_XML
-
-NODE_XML(ArraySubscriptExpr, "ArraySubscriptExpr") // expr1[expr2]
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(Expr) // expr1
- SUB_NODE_XML(Expr) // expr2
-END_NODE_XML
-
-NODE_XML(CallExpr, "CallExpr") // fnexpr(arg1, arg2, ...)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getNumArgs(), "num_args") // unsigned
- SUB_NODE_XML(Expr) // fnexpr
- SUB_NODE_SEQUENCE_XML(Expr) // arg1..argN
-END_NODE_XML
-
-NODE_XML(MemberExpr, "MemberExpr") // expr->F or expr.F
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(isArrow(), "is_deref")
- ATTRIBUTE_XML(getMemberDecl(), "ref") // refers to F
- ATTRIBUTE_XML(getMemberDecl()->getNameAsString(), "name") // informal
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-NODE_XML(CStyleCastExpr, "CStyleCastExpr") // (type)expr
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getTypeAsWritten(), "type_ref") // denotes the type as written in the source code
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-NODE_XML(ImplicitCastExpr, "ImplicitCastExpr")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(Expr)
-END_NODE_XML
-
-NODE_XML(CompoundLiteralExpr, "CompoundLiteralExpr") // [C99 6.5.2.5]
- SUB_NODE_XML(Expr) // init
-END_NODE_XML
-
-NODE_XML(ExtVectorElementExpr, "ExtVectorElementExpr")
- SUB_NODE_XML(Expr) // base
-END_NODE_XML
-
-NODE_XML(InitListExpr, "InitListExpr") // struct foo x = { expr1, { expr2, expr3 } };
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_OPT_XML(getInitializedFieldInUnion(), "field_ref") // if a union is initialized, this refers to the initialized union field id
- ATTRIBUTE_XML(getNumInits(), "num_inits") // unsigned
- SUB_NODE_SEQUENCE_XML(Expr) // expr1..exprN
-END_NODE_XML
-
-NODE_XML(DesignatedInitExpr, "DesignatedInitExpr")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
-END_NODE_XML
-
-NODE_XML(ImplicitValueInitExpr, "ImplicitValueInitExpr") // Implicit value initializations occur within InitListExpr
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
-END_NODE_XML
-
-NODE_XML(VAArgExpr, "VAArgExpr") // used for the builtin function __builtin_va_start(expr)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-NODE_XML(ParenExpr, "ParenExpr") // this represents a parethesized expression "(expr)". Only formed if full location information is requested.
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-// GNU Extensions
-NODE_XML(AddrLabelExpr, "AddrLabelExpr") // the GNU address of label extension, representing &&label.
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getLabel(), "ref") // id string
- SUB_NODE_XML(LabelStmt) // expr
-END_NODE_XML
-
-NODE_XML(StmtExpr, "StmtExpr") // StmtExpr contains a single CompoundStmt node, which it evaluates and takes the value of the last subexpression.
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(CompoundStmt)
-END_NODE_XML
-
-NODE_XML(ChooseExpr, "ChooseExpr") // GNU builtin-in function __builtin_choose_expr(expr1, expr2, expr3)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(Expr) // expr1
- SUB_NODE_XML(Expr) // expr2
- SUB_NODE_XML(Expr) // expr3
-END_NODE_XML
-
-NODE_XML(GNUNullExpr, "GNUNullExpr") // GNU __null extension
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
-END_NODE_XML
-
-// C++ Expressions
-NODE_XML(CXXOperatorCallExpr, "CXXOperatorCallExpr") // fnexpr(arg1, arg2, ...)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getNumArgs(), "num_args") // unsigned
- SUB_NODE_XML(Expr) // fnexpr
- SUB_NODE_SEQUENCE_XML(Expr) // arg1..argN
-END_NODE_XML
-
-NODE_XML(CXXConstructExpr, "CXXConstructExpr") // ctor(arg1, arg2, ...)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getNumArgs(), "num_args") // unsigned
- SUB_NODE_XML(Expr) // fnexpr
- SUB_NODE_SEQUENCE_XML(Expr) // arg1..argN
-END_NODE_XML
-
-NODE_XML(CXXNamedCastExpr, "CXXNamedCastExpr") // xxx_cast<type>(expr)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_ENUM_XML(getStmtClass(), "kind")
- ENUM_XML(Stmt::CXXStaticCastExprClass, "static_cast")
- ENUM_XML(Stmt::CXXDynamicCastExprClass, "dynamic_cast")
- ENUM_XML(Stmt::CXXReinterpretCastExprClass, "reinterpret_cast")
- ENUM_XML(Stmt::CXXConstCastExprClass, "const_cast")
- END_ENUM_XML
- ATTRIBUTE_XML(getTypeAsWritten(), "type_ref") // denotes the type as written in the source code
- SUB_NODE_XML(Expr) // expr
-END_NODE_XML
-
-NODE_XML(CXXMemberCallExpr, "CXXMemberCallExpr") // fnexpr(arg1, arg2, ...)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getNumArgs(), "num_args") // unsigned
- SUB_NODE_XML(Expr) // fnexpr
- SUB_NODE_SEQUENCE_XML(Expr) // arg1..argN
-END_NODE_XML
-
-NODE_XML(CXXBoolLiteralExpr, "CXXBoolLiteralExpr")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getValue(), "value") // boolean
-END_NODE_XML
-
-NODE_XML(CXXNullPtrLiteralExpr, "CXXNullPtrLiteralExpr") // [C++0x 2.14.7] C++ Pointer Literal
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
-END_NODE_XML
-
-NODE_XML(CXXTypeidExpr, "CXXTypeidExpr") // typeid(expr)
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(isTypeOperand(), "is_type") // "1" if expr denotes a type
- ATTRIBUTE_SPECIAL_XML(getTypeOperand(), "type_ref") // optional, denotes the type of expr, if is_type=="1", special handling needed since getTypeOperand() could assert
- SUB_NODE_OPT_XML(Expr) // expr, if is_type=="0"
-END_NODE_XML
-
-NODE_XML(CXXThisExpr, "CXXThisExpr") // this
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
-END_NODE_XML
-
-NODE_XML(CXXThrowExpr, "CXXThrowExpr") // throw (expr);
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- SUB_NODE_XML(Expr) // NULL in case of "throw;"
-END_NODE_XML
-
-NODE_XML(CXXDefaultArgExpr, "CXXDefaultArgExpr")
- ATTRIBUTE_FILE_LOCATION_XML
- TYPE_ATTRIBUTE_XML(getType())
- ATTRIBUTE_XML(getParam(), "ref") // id of the parameter declaration (the expression is a subnode of the declaration)
-END_NODE_XML
-
-//===----------------------------------------------------------------------===//
-#undef NODE_XML
-#undef ID_ATTRIBUTE_XML
-#undef TYPE_ATTRIBUTE_XML
-#undef ATTRIBUTE_XML
-#undef ATTRIBUTE_SPECIAL_XML
-#undef ATTRIBUTE_OPT_XML
-#undef ATTRIBUTE_ENUM_XML
-#undef ATTRIBUTE_ENUM_OPT_XML
-#undef ATTRIBUTE_FILE_LOCATION_XML
-#undef ENUM_XML
-#undef END_ENUM_XML
-#undef END_NODE_XML
-#undef SUB_NODE_XML
-#undef SUB_NODE_SEQUENCE_XML
-#undef SUB_NODE_OPT_XML
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index f5302947a593..d7d2692cb547 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -53,7 +53,8 @@ public:
LangOpts = 0;
}
- void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM);
+ void PrintIncludeStack(Diagnostic::Level Level, SourceLocation Loc,
+ const SourceManager &SM);
void HighlightRange(const CharSourceRange &R,
const SourceManager &SrcMgr,
@@ -61,7 +62,7 @@ public:
std::string &CaretLine,
const std::string &SourceLine);
- void EmitCaretDiagnostic(SourceLocation Loc,
+ void EmitCaretDiagnostic(Diagnostic::Level Level, SourceLocation Loc,
CharSourceRange *Ranges, unsigned NumRanges,
const SourceManager &SM,
const FixItHint *Hints,
@@ -71,7 +72,7 @@ public:
unsigned MacroSkipStart,
unsigned MacroSkipEnd);
- virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ virtual void HandleDiagnostic(Diagnostic::Level Level,
const DiagnosticInfo &Info);
};
diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def
deleted file mode 100644
index b78e70f5aa86..000000000000
--- a/include/clang/Frontend/TypeXML.def
+++ /dev/null
@@ -1,304 +0,0 @@
-//===-- TypeXML.def - Metadata about Type XML nodes ------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the XML type info database as written in the
-// <ReferenceSection>/<Types> sub-nodes of the XML document. Type nodes
-// are referred by "type" reference attributes throughout the document.
-// A type node never contains sub-nodes.
-// The semantics of the attributes and enums are mostly self-documenting
-// by looking at the appropriate internally used functions and values.
-// The following macros are used:
-//
-// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete
-// type of class CLASS where CLASS is a class name used internally by clang.
-// After a NODE_XML the definition of all (optional) attributes of that type
-// node follows.
-//
-// END_NODE_XML - Closes the attribute definition of the current node.
-//
-// ID_ATTRIBUTE_XML - Each type node has an "id" attribute containing a
-// string, which value uniquely identify the type. Other nodes may refer
-// by "type" reference attributes to this value.
-//
-// TYPE_ATTRIBUTE_XML( FN ) - Type nodes may refer to the ids of other type
-// nodes by a "type" attribute. FN is internally used by clang.
-//
-// CONTEXT_ATTRIBUTE_XML( FN ) - Type nodes may refer to the ids of their
-// declaration contexts by a "context" attribute. FN is internally used by
-// clang.
-//
-// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally
-// used by clang. A boolean attribute have the values "0" or "1".
-//
-// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME.
-// Optional attributes are omitted for boolean types, if the value is false,
-// for integral types, if the value is null and for strings,
-// if the value is the empty string. FN is internally used by clang.
-//
-// ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value
-// is an enumeration defined with ENUM_XML macros immediately following after
-// that macro. An optional attribute is ommited, if the particular enum is the
-// empty string. FN is internally used by clang.
-//
-// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is
-// internally used by clang.
-//
-// END_ENUM_XML - Closes the enumeration definition of the current attribute.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef TYPE_ATTRIBUTE_XML
-# define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
-#endif
-
-#ifndef CONTEXT_ATTRIBUTE_XML
-# define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
-#endif
-
-NODE_XML(Type, "FIXME_Type")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getTypeClassName(), "unhandled_type_name")
-END_NODE_XML
-
-NODE_XML(QualType, "CvQualifiedType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getTypePtr()) // the qualified type, e.g. for 'T* const' it's 'T*'
- ATTRIBUTE_OPT_XML(isLocalConstQualified(), "const") // boolean
- ATTRIBUTE_OPT_XML(isLocalVolatileQualified(), "volatile") // boolean
- ATTRIBUTE_OPT_XML(isLocalRestrictQualified(), "restrict") // boolean
- ATTRIBUTE_OPT_XML(getObjCGCAttr(), "objc_gc") // Qualifiers::GC
- ATTRIBUTE_OPT_XML(getAddressSpace(), "address_space") // unsigned
-END_NODE_XML
-
-NODE_XML(BuiltinType, "FundamentalType")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_ENUM_XML(getKind(), "kind")
- ENUM_XML(BuiltinType::Void, "void")
- ENUM_XML(BuiltinType::Bool, "bool")
- ENUM_XML(BuiltinType::Char_U, "char") // not explicitely qualified char, depends on target platform
- ENUM_XML(BuiltinType::Char_S, "char") // not explicitely qualified char, depends on target platform
- ENUM_XML(BuiltinType::SChar, "signed char")
- ENUM_XML(BuiltinType::Short, "short");
- ENUM_XML(BuiltinType::Int, "int");
- ENUM_XML(BuiltinType::Long, "long");
- ENUM_XML(BuiltinType::LongLong, "long long");
- ENUM_XML(BuiltinType::Int128, "__int128_t");
- ENUM_XML(BuiltinType::UChar, "unsigned char");
- ENUM_XML(BuiltinType::UShort, "unsigned short");
- ENUM_XML(BuiltinType::UInt, "unsigned int");
- ENUM_XML(BuiltinType::ULong, "unsigned long");
- ENUM_XML(BuiltinType::ULongLong, "unsigned long long");
- ENUM_XML(BuiltinType::UInt128, "__uint128_t");
- ENUM_XML(BuiltinType::Float, "float");
- ENUM_XML(BuiltinType::Double, "double");
- ENUM_XML(BuiltinType::LongDouble, "long double");
- ENUM_XML(BuiltinType::WChar_U, "wchar_t");
- ENUM_XML(BuiltinType::WChar_S, "wchar_t");
- ENUM_XML(BuiltinType::Char16, "char16_t");
- ENUM_XML(BuiltinType::Char32, "char32_t");
- ENUM_XML(BuiltinType::NullPtr, "nullptr_t"); // This is the type of C++0x 'nullptr'.
- ENUM_XML(BuiltinType::Overload, "overloaded");
- ENUM_XML(BuiltinType::Dependent, "dependent");
- END_ENUM_XML
-END_NODE_XML
-
-NODE_XML(PointerType, "PointerType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getPointeeType())
-END_NODE_XML
-
-NODE_XML(LValueReferenceType, "ReferenceType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getPointeeType())
-END_NODE_XML
-
-NODE_XML(RValueReferenceType, "ReferenceType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getPointeeType())
-END_NODE_XML
-
-NODE_XML(FunctionNoProtoType, "FunctionNoProtoType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(FunctionProtoType, "FunctionType")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getResultType(), "result_type")
- ATTRIBUTE_OPT_XML(isVariadic(), "variadic")
- ATTRIBUTE_ENUM_XML(getCallConv(), "call_conv")
- ENUM_XML(CC_Default, "")
- ENUM_XML(CC_C, "C")
- ENUM_XML(CC_X86StdCall, "X86StdCall")
- ENUM_XML(CC_X86FastCall, "X86FastCall")
- ENUM_XML(CC_X86ThisCall, "X86ThisCall")
- END_ENUM_XML
-END_NODE_XML
-
-NODE_XML(TypedefType, "Typedef")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getDecl()->getUnderlyingType())
- ATTRIBUTE_XML(getDecl()->getNameAsString(), "name") // string
- CONTEXT_ATTRIBUTE_XML(getDecl()->getDeclContext())
-END_NODE_XML
-
-NODE_XML(ComplexType, "ComplexType") // C99 complex types (_Complex float etc)
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getElementType())
-END_NODE_XML
-
-NODE_XML(BlockPointerType, "BlockPointerType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getPointeeType()) // alway refers to a function type
-END_NODE_XML
-
-NODE_XML(MemberPointerType, "MemberPointerType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getPointeeType())
- ATTRIBUTE_XML(getClass(), "class_type") // refers to the class type id of which the pointee is a member
-END_NODE_XML
-
-NODE_XML(ConstantArrayType, "ArrayType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getElementType())
- ATTRIBUTE_XML(getSize(), "size") // unsigned
- ATTRIBUTE_ENUM_OPT_XML(getSizeModifier(), "size_modifier")
- ENUM_XML(ArrayType::Normal, "")
- ENUM_XML(ArrayType::Static, "static")
- ENUM_XML(ArrayType::Star, "star")
- END_ENUM_XML
- ATTRIBUTE_OPT_XML(getIndexTypeCVRQualifiers(), "index_type_qualifier") // unsigned
-END_NODE_XML
-
-NODE_XML(IncompleteArrayType, "IncompleteArrayType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getElementType())
-END_NODE_XML
-
-NODE_XML(VariableArrayType, "VariableArrayType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getElementType())
- // note: the size expression is print at the point of declaration
-END_NODE_XML
-
-NODE_XML(DependentSizedArrayType, "DependentSizedArrayType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getElementType())
- // FIXME: how to deal with size expression?
-END_NODE_XML
-
-NODE_XML(VectorType, "VectorType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getElementType())
- ATTRIBUTE_XML(getNumElements(), "size") // unsigned
-END_NODE_XML
-
-NODE_XML(ExtVectorType, "ExtVectorType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getElementType())
- ATTRIBUTE_XML(getNumElements(), "size") // unsigned
-END_NODE_XML
-
-NODE_XML(TypeOfExprType, "TypeOfExprType")
- ID_ATTRIBUTE_XML
- // note: the typeof expression is print at the point of use
-END_NODE_XML
-
-NODE_XML(TypeOfType, "TypeOfType")
- ID_ATTRIBUTE_XML
- TYPE_ATTRIBUTE_XML(getUnderlyingType())
-END_NODE_XML
-
-
-NODE_XML(RecordType, "Record")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getDecl()->getNameAsString(), "name") // string
- ATTRIBUTE_ENUM_XML(getDecl()->getTagKind(), "kind")
- ENUM_XML(TTK_Struct, "struct")
- ENUM_XML(TTK_Union, "union")
- ENUM_XML(TTK_Class, "class")
- END_ENUM_XML
- CONTEXT_ATTRIBUTE_XML(getDecl()->getDeclContext())
-END_NODE_XML
-
-NODE_XML(EnumType, "Enum")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_XML(getDecl()->getNameAsString(), "name") // string
- CONTEXT_ATTRIBUTE_XML(getDecl()->getDeclContext())
-END_NODE_XML
-
-NODE_XML(TemplateTypeParmType, "TemplateTypeParmType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(TemplateSpecializationType, "TemplateSpecializationType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(ElaboratedType, "ElaboratedType")
- ID_ATTRIBUTE_XML
- ATTRIBUTE_ENUM_XML(getKeyword(), "keyword")
- ENUM_XML(ETK_None, "none")
- ENUM_XML(ETK_Typename, "typename")
- ENUM_XML(ETK_Struct, "struct")
- ENUM_XML(ETK_Union, "union")
- ENUM_XML(ETK_Class, "class")
- ENUM_XML(ETK_Enum, "enum")
- END_ENUM_XML
- TYPE_ATTRIBUTE_XML(getNamedType())
-END_NODE_XML
-
-NODE_XML(InjectedClassNameType, "InjectedClassNameType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(DependentNameType, "DependentNameType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(DependentTemplateSpecializationType,
- "DependentTemplateSpecializationType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(ObjCInterfaceType, "ObjCInterfaceType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(ObjCObjectPointerType, "ObjCObjectPointerType")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(SubstTemplateTypeParmType, "SubstTemplateTypeParm")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(DependentSizedExtVectorType, "DependentSizedExtVector")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(UnresolvedUsingType, "UnresolvedUsing")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-NODE_XML(DecltypeType, "Decltype")
- ID_ATTRIBUTE_XML
-END_NODE_XML
-
-//===----------------------------------------------------------------------===//
-#undef NODE_XML
-#undef ID_ATTRIBUTE_XML
-#undef TYPE_ATTRIBUTE_XML
-#undef CONTEXT_ATTRIBUTE_XML
-#undef ATTRIBUTE_XML
-#undef ATTRIBUTE_OPT_XML
-#undef ATTRIBUTE_ENUM_XML
-#undef ATTRIBUTE_ENUM_OPT_XML
-#undef ENUM_XML
-#undef END_ENUM_XML
-#undef END_NODE_XML
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 02342c1a4710..e4997165cd11 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -14,7 +14,10 @@
#ifndef LLVM_CLANG_FRONTEND_UTILS_H
#define LLVM_CLANG_FRONTEND_UTILS_H
+#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
@@ -24,6 +27,7 @@ class Triple;
namespace clang {
class ASTConsumer;
class CompilerInstance;
+class CompilerInvocation;
class Decl;
class DependencyOutputOptions;
class Diagnostic;
@@ -85,12 +89,23 @@ void AttachDependencyFileGen(Preprocessor &PP,
/// \param OutputPath - If non-empty, a path to write the header include
/// information to, instead of writing to stderr.
void AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders = false,
- llvm::StringRef OutputPath = "");
+ llvm::StringRef OutputPath = "",
+ bool ShowDepth = true);
/// CacheTokens - Cache tokens for use with PCH. Note that this requires
/// a seekable stream.
void CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS);
+/// createInvocationFromCommandLine - Construct a compiler invocation object for
+/// a command line argument vector.
+///
+/// \return A CompilerInvocation, or 0 if none was built for the given
+/// argument vector.
+CompilerInvocation *
+createInvocationFromCommandLine(llvm::ArrayRef<const char *> Args,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags =
+ llvm::IntrusiveRefCntPtr<Diagnostic>());
+
} // end namespace clang
#endif
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index 64687a18e2b6..1ee6953a12b2 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -18,6 +18,7 @@
namespace llvm {
class StringRef;
+ template <typename T> class SmallVectorImpl;
}
namespace clang {
class HeaderMap;
@@ -121,11 +122,26 @@ public:
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
- const FileEntry *LookupFile(llvm::StringRef Filename, HeaderSearch &HS) const;
+ ///
+ /// \param Filename The file to look up relative to the search paths.
+ ///
+ /// \param HS The header search instance to search with.
+ ///
+ /// \param SearchPath If not NULL, will be set to the search path relative
+ /// to which the file was found.
+ ///
+ /// \param RelativePath If not NULL, will be set to the path relative to
+ /// SearchPath at which the file was found. This only differs from the
+ /// Filename for framework includes.
+ const FileEntry *LookupFile(llvm::StringRef Filename, HeaderSearch &HS,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath) const;
private:
- const FileEntry *DoFrameworkLookup(llvm::StringRef Filename,
- HeaderSearch &HS) const;
+ const FileEntry *DoFrameworkLookup(
+ llvm::StringRef Filename, HeaderSearch &HS,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath) const;
};
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index 8a5c83ecf495..e333840b6a9d 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -17,6 +17,7 @@
namespace llvm {
class MemoryBuffer;
class StringRef;
+ template <typename T> class SmallVectorImpl;
}
namespace clang {
class FileEntry;
@@ -47,6 +48,10 @@ public:
/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap. If so, open it and return its FileEntry.
+ /// If RawPath is not NULL and the file is found, RawPath will be set to the
+ /// raw path at which the file was found in the file system. For example,
+ /// for a search path ".." and a filename "../file.h" this would be
+ /// "../../file.h".
const FileEntry *LookupFile(llvm::StringRef Filename, FileManager &FM) const;
/// getFileName - Return the filename of the headermap.
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 30bd4f58549c..fec4dad1e73b 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -104,7 +104,7 @@ class HeaderSearch {
/// consequtively. Requests for <x> search the current dir first, then each
/// directory in SearchDirs, starting at SystemDirIdx, consequtively. If
/// NoCurDirSearch is true, then the check for the file in the current
- /// directory is supressed.
+ /// directory is suppressed.
std::vector<DirectoryLookup> SearchDirs;
unsigned SystemDirIdx;
bool NoCurDirSearch;
@@ -182,25 +182,43 @@ public:
}
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
- /// return null on failure. isAngled indicates whether the file reference is
- /// a <> reference. If successful, this returns 'UsedDir', the
- /// DirectoryLookup member the file was found in, or null if not applicable.
- /// If CurDir is non-null, the file was found in the specified directory
- /// search location. This is used to implement #include_next. CurFileEnt, if
- /// non-null, indicates where the #including file is, in case a relative
- /// search is needed.
+ /// return null on failure.
+ ///
+ /// \returns If successful, this returns 'UsedDir', the DirectoryLookup member
+ /// the file was found in, or null if not applicable.
+ ///
+ /// \param isAngled indicates whether the file reference is a <> reference.
+ ///
+ /// \param CurDir If non-null, the file was found in the specified directory
+ /// search location. This is used to implement #include_next.
+ ///
+ /// \param CurFileEnt If non-null, indicates where the #including file is, in
+ /// case a relative search is needed.
+ ///
+ /// \param SearchPath If non-null, will be set to the search path relative
+ /// to which the file was found. If the include path is absolute, SearchPath
+ /// will be set to an empty string.
+ ///
+ /// \param RelativePath If non-null, will be set to the path relative to
+ /// SearchPath at which the file was found. This only differs from the
+ /// Filename for framework includes.
const FileEntry *LookupFile(llvm::StringRef Filename, bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
- const FileEntry *CurFileEnt);
+ const FileEntry *CurFileEnt,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath);
/// LookupSubframeworkHeader - Look up a subframework for the specified
/// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
- const FileEntry *LookupSubframeworkHeader(llvm::StringRef Filename,
- const FileEntry *RelativeFileEnt);
+ const FileEntry *LookupSubframeworkHeader(
+ llvm::StringRef Filename,
+ const FileEntry *RelativeFileEnt,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath);
/// LookupFrameworkCache - Look up the specified framework name in our
/// framework cache, returning the DirectoryEntry it is in if we know,
@@ -261,6 +279,17 @@ public:
// Used by ASTReader.
void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID);
+ // Used by external tools
+ typedef std::vector<DirectoryLookup>::const_iterator search_dir_iterator;
+ search_dir_iterator search_dir_begin() const { return SearchDirs.begin(); }
+ search_dir_iterator search_dir_end() const { return SearchDirs.end(); }
+ unsigned search_dir_size() const { return SearchDirs.size(); }
+
+ search_dir_iterator system_dir_begin() const {
+ return SearchDirs.begin() + SystemDirIdx;
+ }
+ search_dir_iterator system_dir_end() const { return SearchDirs.end(); }
+
void PrintStats();
private:
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
index 5fcb8eb2d1a4..7d2eb89c50bc 100644
--- a/include/clang/Lex/LexDiagnostic.h
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -15,7 +15,8 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#define LEXSTART
#include "clang/Basic/DiagnosticLexKinds.inc"
#undef DIAG
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index fc9a8de43482..7c3d863bd3d3 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -18,7 +18,6 @@
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/SmallVector.h"
#include <string>
-#include <vector>
#include <cassert>
namespace clang {
@@ -236,6 +235,20 @@ public:
const SourceManager &SourceMgr,
const LangOptions &Features,
bool *Invalid = 0);
+
+ /// getSpelling - This method is used to get the spelling of the
+ /// token at the given source location. If, as is usually true, it
+ /// is not necessary to copy any data, then the returned string may
+ /// not point into the provided buffer.
+ ///
+ /// This method lexes at the instantiation depth of the given
+ /// location and does not jump to the instantiation or spelling
+ /// location.
+ static llvm::StringRef getSpelling(SourceLocation loc,
+ llvm::SmallVectorImpl<char> &buffer,
+ const SourceManager &SourceMgr,
+ const LangOptions &Features,
+ bool *invalid = 0);
/// MeasureTokenLength - Relex the token at the specified location and return
/// its length in bytes in the input file. If the token needs cleaning (e.g.
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index bf2c06becdbf..dcaf4457cfa8 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -19,7 +19,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include <cctype>
-#include <string>
namespace clang {
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index 717c3008eca9..7c4cfb007233 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -17,7 +17,6 @@
#include "clang/Lex/Token.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
-#include <vector>
#include <cassert>
namespace clang {
diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h
index 5d5d67329059..95b00dfcf366 100644
--- a/include/clang/Lex/MultipleIncludeOpt.h
+++ b/include/clang/Lex/MultipleIncludeOpt.h
@@ -47,7 +47,7 @@ public:
TheMacro = 0;
}
- /// Invalidate - Permenantly mark this file as not being suitable for the
+ /// Invalidate - Permanently mark this file as not being suitable for the
/// include-file optimization.
void Invalidate() {
// If we have read tokens but have no controlling macro, the state-machine
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index b2a80a62985f..fd07a29f8e9d 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -75,12 +75,26 @@ public:
///
/// \param EndLoc The location of the last token within the inclusion
/// directive.
+ ///
+ /// \param SearchPath Contains the search path which was used to find the file
+ /// in the file system. If the file was found via an absolute include path,
+ /// SearchPath will be empty. For framework includes, the SearchPath and
+ /// RelativePath will be split up. For example, if an include of "Some/Some.h"
+ /// is found via the framework path
+ /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be
+ /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be
+ /// "Some.h".
+ ///
+ /// \param RelativePath The path relative to SearchPath, at which the include
+ /// file was found. This is equal to FileName except for framework includes.
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
llvm::StringRef FileName,
bool IsAngled,
const FileEntry *File,
- SourceLocation EndLoc) {
+ SourceLocation EndLoc,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath) {
}
/// EndOfMainFile - This callback is invoked when the end of the main file is
@@ -188,11 +202,13 @@ public:
llvm::StringRef FileName,
bool IsAngled,
const FileEntry *File,
- SourceLocation EndLoc) {
- First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
- EndLoc);
- Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
- EndLoc);
+ SourceLocation EndLoc,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath) {
+ First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
+ EndLoc, SearchPath, RelativePath);
+ Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File,
+ EndLoc, SearchPath, RelativePath);
}
virtual void EndOfMainFile() {
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
index 0b5a76ccfd6e..f6a97a0a90a4 100644
--- a/include/clang/Lex/PTHLexer.h
+++ b/include/clang/Lex/PTHLexer.h
@@ -15,7 +15,6 @@
#define LLVM_CLANG_PTHLEXER_H
#include "clang/Lex/PreprocessorLexer.h"
-#include <vector>
namespace clang {
diff --git a/include/clang/Lex/Pragma.h b/include/clang/Lex/Pragma.h
index 8bd22369476e..c6ab35c19c1e 100644
--- a/include/clang/Lex/Pragma.h
+++ b/include/clang/Lex/Pragma.h
@@ -17,7 +17,6 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
-#include <vector>
namespace clang {
class Preprocessor;
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index afd7ae1187cc..7be845549d4a 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -341,7 +341,9 @@ namespace clang {
llvm::StringRef FileName,
bool IsAngled,
const FileEntry *File,
- SourceLocation EndLoc);
+ SourceLocation EndLoc,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath);
};
} // end namespace clang
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 9005adc6ade6..616507a914a8 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -25,6 +25,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
@@ -53,7 +54,7 @@ class PreprocessingRecord;
/// single source file, and don't know anything about preprocessor-level issues
/// like the #include stack, token expansion, etc.
///
-class Preprocessor {
+class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
Diagnostic *Diags;
LangOptions Features;
const TargetInfo &Target;
@@ -217,6 +218,10 @@ class Preprocessor {
/// previous macro value.
llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > PragmaPushMacroInfo;
+ /// \brief Instantiation source location for the last macro that expanded
+ /// to no tokens.
+ SourceLocation LastEmptyMacroInstantiationLoc;
+
// Various statistics we track for performance analysis.
unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma;
unsigned NumIf, NumElse, NumEndif;
@@ -365,6 +370,12 @@ public:
macro_iterator macro_begin(bool IncludeExternalMacros = true) const;
macro_iterator macro_end(bool IncludeExternalMacros = true) const;
+ /// \brief Instantiation source location for the last macro that expanded
+ /// to no tokens.
+ SourceLocation getLastEmptyMacroInstantiationLoc() const {
+ return LastEmptyMacroInstantiationLoc;
+ }
+
const std::string &getPredefines() const { return Predefines; }
/// setPredefines - Set the predefines for this Preprocessor. These
/// predefines are automatically injected when parsing the main file.
@@ -644,13 +655,26 @@ public:
return Diags->Report(Tok.getLocation(), DiagID);
}
+ /// getSpelling() - Return the 'spelling' of the token at the given
+ /// location; does not go up to the spelling location or down to the
+ /// instantiation location.
+ ///
+ /// \param buffer A buffer which will be used only if the token requires
+ /// "cleaning", e.g. if it contains trigraphs or escaped newlines
+ /// \param invalid If non-null, will be set \c true if an error occurs.
+ llvm::StringRef getSpelling(SourceLocation loc,
+ llvm::SmallVectorImpl<char> &buffer,
+ bool *invalid = 0) const {
+ return Lexer::getSpelling(loc, buffer, SourceMgr, Features, invalid);
+ }
+
/// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a
/// token is the characters used to represent the token in the source file
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
///
- /// \param Invalid If non-NULL, will be set \c true if an error occurs.
+ /// \param Invalid If non-null, will be set \c true if an error occurs.
std::string getSpelling(const Token &Tok, bool *Invalid = 0) const {
return Lexer::getSpelling(Tok, SourceMgr, Features, Invalid);
}
@@ -759,6 +783,38 @@ public:
/// updating the token kind accordingly.
IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const;
+private:
+ llvm::DenseMap<IdentifierInfo*,unsigned> PoisonReasons;
+
+public:
+
+ // SetPoisonReason - Call this function to indicate the reason for
+ // poisoning an identifier. If that identifier is accessed while
+ // poisoned, then this reason will be used instead of the default
+ // "poisoned" diagnostic.
+ void SetPoisonReason(IdentifierInfo *II, unsigned DiagID);
+
+ // HandlePoisonedIdentifier - Display reason for poisoned
+ // identifier.
+ void HandlePoisonedIdentifier(Token & Tok);
+
+ void MaybeHandlePoisonedIdentifier(Token & Identifier) {
+ if(IdentifierInfo * II = Identifier.getIdentifierInfo()) {
+ if(II->isPoisoned()) {
+ HandlePoisonedIdentifier(Identifier);
+ }
+ }
+ }
+
+private:
+ /// Identifiers used for SEH handling in Borland. These are only
+ /// allowed in particular circumstances
+ IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except block
+ IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __except filter expression
+ IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; // __finally
+public:
+ void PoisonSEHIdentifiers(bool Poison = true); // Borland
+
/// HandleIdentifier - This callback is invoked when the lexer reads an
/// identifier and has filled in the tokens IdentifierInfo member. This
/// callback potentially macro expands it or turns it into a named token (like
@@ -782,13 +838,13 @@ public:
/// read is the correct one.
void HandleDirective(Token &Result);
- /// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
- /// not, emit a diagnostic and consume up until the eom. If EnableMacros is
+ /// CheckEndOfDirective - Ensure that the next token is a tok::eod token. If
+ /// not, emit a diagnostic and consume up until the eod. If EnableMacros is
/// true, then we consider macros that expand to zero tokens as being ok.
void CheckEndOfDirective(const char *Directive, bool EnableMacros = false);
/// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
- /// current line until the tok::eom token is found.
+ /// current line until the tok::eod token is found.
void DiscardUntilEndOfDirective();
/// SawDateOrTime - This returns true if the preprocessor has seen a use of
@@ -819,7 +875,9 @@ public:
/// for system #include's or not (i.e. using <> instead of "").
const FileEntry *LookupFile(llvm::StringRef Filename,
bool isAngled, const DirectoryLookup *FromDir,
- const DirectoryLookup *&CurDir);
+ const DirectoryLookup *&CurDir,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath);
/// GetCurLookup - The DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable. This allows us to
@@ -839,12 +897,12 @@ public:
///
/// This code concatenates and consumes tokens up to the '>' token. It
/// returns false if the > was found, otherwise it returns true if it finds
- /// and consumes the EOM marker.
+ /// and consumes the EOD marker.
bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer,
SourceLocation &End);
/// LexOnOffSwitch - Lex an on-off-switch (C99 6.10.6p2) and verify that it is
- /// followed by EOM. Return true if the token is not a valid on-off-switch.
+ /// followed by EOD. Return true if the token is not a valid on-off-switch.
bool LexOnOffSwitch(tok::OnOffSwitch &OOS);
private:
@@ -875,7 +933,7 @@ private:
void ReleaseMacroInfo(MacroInfo* MI);
/// ReadMacroName - Lex and validate a macro name, which occurs after a
- /// #define or #undef. This emits a diagnostic, sets the token kind to eom,
+ /// #define or #undef. This emits a diagnostic, sets the token kind to eod,
/// and discards the rest of the macro line if the macro name is invalid.
void ReadMacroName(Token &MacroNameTok, char isDefineUndef = 0);
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index d8332938a7ed..7bf041df974f 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -17,7 +17,6 @@
#include "clang/Lex/MultipleIncludeOpt.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/SmallVector.h"
-#include <string>
namespace clang {
@@ -36,7 +35,7 @@ protected:
//===--------------------------------------------------------------------===//
/// ParsingPreprocessorDirective - This is true when parsing #XXX. This turns
- /// '\n' into a tok::eom token.
+ /// '\n' into a tok::eod token.
bool ParsingPreprocessorDirective;
/// ParsingFilename - True after #include: this turns <xx> into a
@@ -131,7 +130,7 @@ public:
/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
/// (potentially) macro expand the filename. If the sequence parsed is not
- /// lexically legal, emit a diagnostic and return a result EOM token.
+ /// lexically legal, emit a diagnostic and return a result EOD token.
void LexIncludeFilename(Token &Result);
/// setParsingPreprocessorDirective - Inform the lexer whether or not
diff --git a/include/clang/Makefile b/include/clang/Makefile
index d6b9844285d2..a7be0319e5fa 100644
--- a/include/clang/Makefile
+++ b/include/clang/Makefile
@@ -8,9 +8,12 @@ install-local::
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
$(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang" ; then \
cd $(PROJ_SRC_ROOT)/tools/clang/include && \
- for hdr in `find clang -type f '!' '(' -name '*~' \
- -o -name '.#*' -o -name '*.in' -o -name '*.txt' \
- -o -name 'Makefile' -o -name '*.td' -o -name '*.orig' ')' -print \
+ for hdr in `find clang -type f \
+ '(' -name LICENSE.TXT \
+ -o -name '*.def' \
+ -o -name '*.h' \
+ -o -name '*.inc' \
+ ')' -print \
| grep -v CVS | grep -v .svn | grep -v .dir` ; do \
instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
if test \! -d "$$instdir" ; then \
@@ -23,7 +26,12 @@ install-local::
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
$(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include/clang" ; then \
cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
- for hdr in `find clang -type f '!' '(' -name 'Makefile' ')' -print \
+ for hdr in `find clang -type f \
+ '(' -name LICENSE.TXT \
+ -o -name '*.def' \
+ -o -name '*.h' \
+ -o -name '*.inc' \
+ ')' -print \
| grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
done ; \
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
index f640b37c1982..c50ac92f6e8d 100644
--- a/include/clang/Parse/ParseDiagnostic.h
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -15,7 +15,8 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#define PARSESTART
#include "clang/Basic/DiagnosticParseKinds.inc"
#undef DIAG
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 758792097639..3fd9844368ee 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -22,7 +22,6 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/ADT/OwningPtr.h"
#include <stack>
-#include <list>
namespace clang {
class PragmaHandler;
@@ -33,6 +32,8 @@ namespace clang {
class PragmaUnusedHandler;
class ColonProtectionRAIIObject;
class InMessageExpressionRAIIObject;
+ class PoisonSEHIdentifiersRAIIObject;
+ class VersionTuple;
/// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
/// an entry is printed for it.
@@ -75,8 +76,8 @@ class Parser : public CodeCompletionHandler {
friend class PragmaUnusedHandler;
friend class ColonProtectionRAIIObject;
friend class InMessageExpressionRAIIObject;
+ friend class PoisonSEHIdentifiersRAIIObject;
friend class ParenBraceBracketBalancer;
- PrettyStackTraceParserEntry CrashInfo;
Preprocessor &PP;
@@ -103,6 +104,12 @@ class Parser : public CodeCompletionHandler {
unsigned NumCachedScopes;
Scope *ScopeCache[ScopeCacheSize];
+ /// Identifiers used for SEH handling in Borland. These are only
+ /// allowed in particular circumstances
+ IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except block
+ IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __except filter expression
+ IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; // __finally
+
/// Ident_super - IdentifierInfo for "super", to support fast
/// comparison.
IdentifierInfo *Ident_super;
@@ -112,6 +119,18 @@ class Parser : public CodeCompletionHandler {
IdentifierInfo *Ident_vector;
IdentifierInfo *Ident_pixel;
+ /// \brief Identifier for "introduced".
+ IdentifierInfo *Ident_introduced;
+
+ /// \brief Identifier for "deprecated".
+ IdentifierInfo *Ident_deprecated;
+
+ /// \brief Identifier for "obsoleted".
+ IdentifierInfo *Ident_obsoleted;
+
+ /// \brief Identifier for "unavailable".
+ IdentifierInfo *Ident_unavailable;
+
/// C++0x contextual keywords.
mutable IdentifierInfo *Ident_final;
mutable IdentifierInfo *Ident_override;
@@ -120,6 +139,7 @@ class Parser : public CodeCompletionHandler {
llvm::OwningPtr<PragmaHandler> GCCVisibilityHandler;
llvm::OwningPtr<PragmaHandler> OptionsHandler;
llvm::OwningPtr<PragmaHandler> PackHandler;
+ llvm::OwningPtr<PragmaHandler> MSStructHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;
llvm::OwningPtr<PragmaHandler> WeakHandler;
llvm::OwningPtr<PragmaHandler> FPContractHandler;
@@ -137,7 +157,7 @@ class Parser : public CodeCompletionHandler {
/// ColonProtectionRAIIObject RAII object.
bool ColonIsSacred;
- /// \brief When true, we are directly inside an Ojective-C messsage
+ /// \brief When true, we are directly inside an Objective-C messsage
/// send expression.
///
/// This is managed by the \c InMessageExpressionRAIIObject class, and
@@ -148,7 +168,7 @@ class Parser : public CodeCompletionHandler {
unsigned TemplateParameterDepth;
/// Factory object for creating AttributeList objects.
- AttributeList::Factory AttrFactory;
+ AttributeFactory AttrFactory;
public:
Parser(Preprocessor &PP, Sema &Actions);
@@ -380,6 +400,24 @@ private:
static void setTypeAnnotation(Token &Tok, ParsedType T) {
Tok.setAnnotationValue(T.getAsOpaquePtr());
}
+
+ /// \brief Read an already-translated primary expression out of an annotation
+ /// token.
+ static ExprResult getExprAnnotation(Token &Tok) {
+ if (Tok.getAnnotationValue())
+ return ExprResult((Expr *)Tok.getAnnotationValue());
+
+ return ExprResult(true);
+ }
+
+ /// \brief Set the primary expression corresponding to the given annotation
+ /// token.
+ static void setExprAnnotation(Token &Tok, ExprResult ER) {
+ if (ER.isInvalid())
+ Tok.setAnnotationValue(0);
+ else
+ Tok.setAnnotationValue(ER.get());
+ }
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
@@ -678,7 +716,7 @@ private:
/// LateParsedDeclarationsContainer - During parsing of a top (non-nested)
/// C++ class, its method declarations that contain parts that won't be
- /// parsed until after the definiton is completed (C++ [class.mem]p2),
+ /// parsed until after the definition is completed (C++ [class.mem]p2),
/// the method declarations and possibly attached inline definitions
/// will be stored here with the tokens that will be parsed to create those entities.
typedef llvm::SmallVector<LateParsedDeclaration*, 2> LateParsedDeclarationsContainer;
@@ -792,10 +830,9 @@ private:
ParsingDeclRAIIObject ParsingRAII;
public:
- ParsingDeclSpec(Parser &P) : ParsingRAII(P) {}
- ParsingDeclSpec(ParsingDeclRAIIObject &RAII) : ParsingRAII(RAII) {}
+ ParsingDeclSpec(Parser &P) : DeclSpec(P.AttrFactory), ParsingRAII(P) {}
ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII)
- : ParsingRAII(P, RAII) {}
+ : DeclSpec(P.AttrFactory), ParsingRAII(P, RAII) {}
void complete(Decl *D) {
ParsingRAII.complete(D);
@@ -908,6 +945,27 @@ private:
SourceRange getSourceRange() const;
};
+ /// \brief Contains a late templated function.
+ /// Will be parsed at the end of the translation unit.
+ struct LateParsedTemplatedFunction {
+ explicit LateParsedTemplatedFunction(Parser* P, Decl *MD)
+ : D(MD) {}
+
+ CachedTokens Toks;
+
+ /// \brief The template function declaration to be late parsed.
+ Decl *D;
+ };
+
+ void LexTemplateFunctionForLateParsing(CachedTokens &Toks);
+ void ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT);
+ typedef llvm::DenseMap<const FunctionDecl*, LateParsedTemplatedFunction*>
+ LateParsedTemplateMapT;
+ LateParsedTemplateMapT LateParsedTemplateMap;
+
+ static void LateTemplateParserCallback(void *P, const FunctionDecl *FD);
+ void LateTemplateParser(const FunctionDecl *FD);
+
Sema::ParsingClassState
PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass);
void DeallocateParsedClasses(ParsingClass *Class);
@@ -934,6 +992,9 @@ private:
//===--------------------------------------------------------------------===//
// C99 6.9: External Definitions.
struct ParsedAttributesWithRange : ParsedAttributes {
+ ParsedAttributesWithRange(AttributeFactory &factory)
+ : ParsedAttributes(factory) {}
+
SourceRange Range;
};
@@ -992,13 +1053,21 @@ private:
bool isTokIdentifier_in() const;
- ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter);
+ /// \brief The context in which we are parsing an Objective-C type name.
+ enum ObjCTypeNameContext {
+ OTN_ResultType,
+ OTN_ParameterType
+ };
+
+ ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, ObjCTypeNameContext Context);
void ParseObjCMethodRequirement();
Decl *ParseObjCMethodPrototype(Decl *classOrCat,
- tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
+ tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword,
+ bool MethodDefinition = true);
Decl *ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType,
Decl *classDecl,
- tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
+ tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword,
+ bool MethodDefinition=true);
void ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl);
Decl *ParseObjCMethodDefinition();
@@ -1016,14 +1085,14 @@ private:
ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
ExprResult ParseRHSOfBinaryExpression(ExprResult LHS,
- prec::Level MinPrec);
+ prec::Level MinPrec);
ExprResult ParseCastExpression(bool isUnaryExpression,
- bool isAddressOfOperand,
- bool &NotCastExpr,
- ParsedType TypeOfCast);
+ bool isAddressOfOperand,
+ bool &NotCastExpr,
+ ParsedType TypeOfCast);
ExprResult ParseCastExpression(bool isUnaryExpression,
- bool isAddressOfOperand = false,
- ParsedType TypeOfCast = ParsedType());
+ bool isAddressOfOperand = false,
+ ParsedType TypeOfCast = ParsedType());
/// Returns true if the next token would start a postfix-expression
/// suffix.
@@ -1035,10 +1104,10 @@ private:
}
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
- ExprResult ParseSizeofAlignofExpression();
+ ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
- ExprResult ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
+ ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
bool &isCastExpr,
ParsedType &CastTy,
SourceRange &CastRange);
@@ -1079,6 +1148,8 @@ private:
ExprResult ParseStringLiteralExpression();
+ ExprResult ParseGenericSelectionExpression();
+
//===--------------------------------------------------------------------===//
// C++ Expressions
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
@@ -1086,7 +1157,8 @@ private:
bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
bool EnteringContext,
- bool *MayBePseudoDestructor = 0);
+ bool *MayBePseudoDestructor = 0,
+ bool IsTypename = false);
//===--------------------------------------------------------------------===//
// C++ 5.2p1: C++ Casts
@@ -1114,11 +1186,18 @@ private:
//===--------------------------------------------------------------------===//
// C++ 15: C++ Throw Expression
ExprResult ParseThrowExpression();
+
+ ExceptionSpecificationType MaybeParseExceptionSpecification(
+ SourceRange &SpecificationRange,
+ llvm::SmallVectorImpl<ParsedType> &DynamicExceptions,
+ llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
+ ExprResult &NoexceptExpr);
+
// EndLoc is filled with the location of the last token of the specification.
- bool ParseExceptionSpecification(SourceLocation &EndLoc,
- llvm::SmallVectorImpl<ParsedType> &Exns,
- llvm::SmallVectorImpl<SourceRange> &Ranges,
- bool &hasAnyExceptionSpec);
+ ExceptionSpecificationType ParseDynamicExceptionSpecification(
+ SourceRange &SpecificationRange,
+ llvm::SmallVectorImpl<ParsedType> &Exceptions,
+ llvm::SmallVectorImpl<SourceRange> &Ranges);
//===--------------------------------------------------------------------===//
// C++0x 8: Function declaration trailing-return-type
@@ -1205,11 +1284,14 @@ private:
}
StmtResult ParseStatementOrDeclaration(StmtVector& Stmts,
bool OnlyStatement = false);
+ StmtResult ParseExprStatement(ParsedAttributes &Attrs);
StmtResult ParseLabeledStatement(ParsedAttributes &Attr);
- StmtResult ParseCaseStatement(ParsedAttributes &Attr);
+ StmtResult ParseCaseStatement(ParsedAttributes &Attr,
+ bool MissingCase = false,
+ ExprResult Expr = ExprResult());
StmtResult ParseDefaultStatement(ParsedAttributes &Attr);
StmtResult ParseCompoundStatement(ParsedAttributes &Attr,
- bool isStmtExpr = false);
+ bool isStmtExpr = false);
StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
bool ParseParenExprOrCondition(ExprResult &ExprResult,
Decl *&DeclResult,
@@ -1238,6 +1320,14 @@ private:
StmtResult ParseCXXCatchBlock();
//===--------------------------------------------------------------------===//
+ // MS: SEH Statements and Blocks
+
+ StmtResult ParseSEHTryBlock(ParsedAttributes &Attr);
+ StmtResult ParseSEHTryBlockCommon(SourceLocation Loc);
+ StmtResult ParseSEHExceptBlock(SourceLocation Loc);
+ StmtResult ParseSEHFinallyBlock(SourceLocation Loc);
+
+ //===--------------------------------------------------------------------===//
// Objective-C Statements
StmtResult ParseObjCAtStatement(SourceLocation atLoc);
@@ -1258,6 +1348,15 @@ private:
DSC_top_level // top-level/namespace declaration context
};
+ /// Information on a C++0x for-range-initializer found while parsing a
+ /// declaration which turns out to be a for-range-declaration.
+ struct ForRangeInit {
+ SourceLocation ColonLoc;
+ ExprResult RangeExpr;
+
+ bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); }
+ };
+
DeclGroupPtrTy ParseDeclaration(StmtVector &Stmts,
unsigned Context, SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs);
@@ -1265,14 +1364,19 @@ private:
unsigned Context,
SourceLocation &DeclEnd,
ParsedAttributes &attrs,
- bool RequireSemi);
+ bool RequireSemi,
+ ForRangeInit *FRI = 0);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context,
bool AllowFunctionDefinitions,
- SourceLocation *DeclEnd = 0);
+ SourceLocation *DeclEnd = 0,
+ ForRangeInit *FRI = 0);
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
- Decl *ParseFunctionStatementBody(Decl *Decl);
- Decl *ParseFunctionTryBlock(Decl *Decl);
+ bool ParseAttributesAfterDeclarator(Declarator &D);
+ Decl *ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
+ Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
+ Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope);
/// \brief When in code-completion, skip parsing of the function/method body
/// unless the body contains the code-completion point.
@@ -1296,7 +1400,8 @@ private:
void ParseSpecifierQualifierList(DeclSpec &DS);
- void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter);
+ void ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
+ ObjCTypeNameContext Context);
void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
@@ -1470,7 +1575,7 @@ private:
TypeResult ParseTypeName(SourceRange *Range = 0,
Declarator::TheContext Context
- = Declarator::TypeNameContext);
+ = Declarator::TypeNameContext);
void ParseBlockId();
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
@@ -1481,10 +1586,10 @@ private:
void MaybeParseGNUAttributes(Declarator &D) {
if (Tok.is(tok::kw___attribute)) {
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
SourceLocation endLoc;
ParseGNUAttributes(attrs, &endLoc);
- D.addAttributes(attrs.getList(), endLoc);
+ D.takeAttributes(attrs, endLoc);
}
}
void MaybeParseGNUAttributes(ParsedAttributes &attrs,
@@ -1497,18 +1602,18 @@ private:
void MaybeParseCXX0XAttributes(Declarator &D) {
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
SourceLocation endLoc;
ParseCXX0XAttributes(attrs, &endLoc);
- D.addAttributes(attrs.getList(), endLoc);
+ D.takeAttributes(attrs, endLoc);
}
}
void MaybeParseCXX0XAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0) {
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
- ParsedAttributesWithRange attrsWithRange;
+ ParsedAttributesWithRange attrsWithRange(AttrFactory);
ParseCXX0XAttributes(attrsWithRange, endLoc);
- attrs.append(attrsWithRange.getList());
+ attrs.takeAllFrom(attrsWithRange);
}
}
void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
@@ -1530,6 +1635,13 @@ private:
void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs);
void ParseBorlandTypeAttributes(ParsedAttributes &attrs);
void ParseOpenCLAttributes(ParsedAttributes &attrs);
+ void ParseOpenCLQualifiers(DeclSpec &DS);
+
+ VersionTuple ParseVersionTuple(SourceRange &Range);
+ void ParseAvailabilityAttribute(IdentifierInfo &Availability,
+ SourceLocation AvailabilityLoc,
+ ParsedAttributes &attrs,
+ SourceLocation *endLoc);
void ParseTypeofSpecifier(DeclSpec &DS);
void ParseDecltypeSpecifier(DeclSpec &DS);
@@ -1539,8 +1651,7 @@ private:
VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const;
void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS);
- ClassVirtSpecifiers::Specifier isCXX0XClassVirtSpecifier() const;
- void ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS);
+ bool isCXX0XFinalKeyword() const;
/// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to
/// enter a new C++ declarator scope and exit it when the function is
@@ -1624,8 +1735,7 @@ private:
//===--------------------------------------------------------------------===//
// C++ 9: classes [class] and C structs/unions.
- TypeResult ParseClassName(SourceLocation &EndLocation,
- CXXScopeSpec *SS = 0);
+ TypeResult ParseClassName(SourceLocation &EndLocation, CXXScopeSpec &SS);
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
@@ -1696,18 +1806,18 @@ private:
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
SourceLocation TemplateNameLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
SourceLocation &RAngleLoc);
bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
- const CXXScopeSpec *SS,
+ CXXScopeSpec &SS,
UnqualifiedId &TemplateName,
SourceLocation TemplateKWLoc = SourceLocation(),
bool AllowTypeAnnotation = true);
- void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);
+ void AnnotateTemplateIdTokenAsType();
bool IsTemplateArgumentList(unsigned Skip = 0);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
ParsedTemplateArgument ParseTemplateTemplateArgument();
@@ -1722,6 +1832,11 @@ private:
ExprResult ParseBinaryTypeTrait();
//===--------------------------------------------------------------------===//
+ // Embarcadero: Arary and Expression Traits
+ ExprResult ParseArrayTypeTrait();
+ ExprResult ParseExpressionTrait();
+
+ //===--------------------------------------------------------------------===//
// Preprocessor code-completion pass-through
virtual void CodeCompleteDirective(bool InConditional);
virtual void CodeCompleteInConditionalExclusion();
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/FrontendActions.h
index 2b5f88ccee9d..6b33183166f8 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/FrontendActions.h
@@ -11,8 +11,6 @@
#define LLVM_CLANG_REWRITE_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
-#include <string>
-#include <vector>
namespace clang {
class FixItRewriter;
diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h
index b3d4035628ee..7861e9992891 100644
--- a/include/clang/Rewrite/Rewriter.h
+++ b/include/clang/Rewrite/Rewriter.h
@@ -22,7 +22,6 @@
#include <cstring>
#include <map>
#include <string>
-#include <vector>
namespace llvm { class raw_ostream; }
@@ -58,7 +57,8 @@ public:
llvm::raw_ostream &write(llvm::raw_ostream &) const;
/// RemoveText - Remove the specified text.
- void RemoveText(unsigned OrigOffset, unsigned Size);
+ void RemoveText(unsigned OrigOffset, unsigned Size,
+ bool removeLineIfEmpty = false);
/// InsertText - Insert some text at the specified point, where the offset in
/// the buffer is specified relative to the original SourceBuffer. The
@@ -129,6 +129,23 @@ class Rewriter {
const LangOptions *LangOpts;
std::map<FileID, RewriteBuffer> RewriteBuffers;
public:
+ struct RewriteOptions {
+ /// \brief Given a source range, true to include previous inserts at the
+ /// beginning of the range as part of the range itself (true by default).
+ bool IncludeInsertsAtBeginOfRange;
+ /// \brief Given a source range, true to include previous inserts at the
+ /// end of the range as part of the range itself (true by default).
+ bool IncludeInsertsAtEndOfRange;
+ /// \brief If true and removing some text leaves a blank line
+ /// also remove the empty line (false by default).
+ bool RemoveLineIfEmpty;
+
+ RewriteOptions()
+ : IncludeInsertsAtBeginOfRange(true),
+ IncludeInsertsAtEndOfRange(true),
+ RemoveLineIfEmpty(false) { }
+ };
+
typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator;
explicit Rewriter(SourceManager &SM, const LangOptions &LO)
@@ -150,8 +167,10 @@ public:
/// getRangeSize - Return the size in bytes of the specified range if they
/// are in the same file. If not, this returns -1.
- int getRangeSize(SourceRange Range) const;
- int getRangeSize(const CharSourceRange &Range) const;
+ int getRangeSize(SourceRange Range,
+ RewriteOptions opts = RewriteOptions()) const;
+ int getRangeSize(const CharSourceRange &Range,
+ RewriteOptions opts = RewriteOptions()) const;
/// getRewrittenText - Return the rewritten form of the text in the specified
/// range. If the start or end of the range was unrewritable or if they are
@@ -176,6 +195,10 @@ public:
return InsertText(Loc, Str);
}
+ /// \brief Insert the specified string after the token in the
+ /// specified location.
+ bool InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str);
+
/// InsertText - Insert the specified string at the specified location in the
/// original buffer. This method returns true (and does nothing) if the input
/// location was not rewritable, false otherwise. Text is
@@ -186,7 +209,19 @@ public:
}
/// RemoveText - Remove the specified text region.
- bool RemoveText(SourceLocation Start, unsigned Length);
+ bool RemoveText(SourceLocation Start, unsigned Length,
+ RewriteOptions opts = RewriteOptions());
+
+ /// \brief Remove the specified text region.
+ bool RemoveText(CharSourceRange range,
+ RewriteOptions opts = RewriteOptions()) {
+ return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
+ }
+
+ /// \brief Remove the specified text region.
+ bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) {
+ return RemoveText(range.getBegin(), getRangeSize(range, opts), opts);
+ }
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove/insert"
@@ -194,11 +229,37 @@ public:
bool ReplaceText(SourceLocation Start, unsigned OrigLength,
llvm::StringRef NewStr);
+ /// ReplaceText - This method replaces a range of characters in the input
+ /// buffer with a new string. This is effectively a combined "remove/insert"
+ /// operation.
+ bool ReplaceText(SourceRange range, llvm::StringRef NewStr) {
+ return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
+ }
+
+ /// ReplaceText - This method replaces a range of characters in the input
+ /// buffer with a new string. This is effectively a combined "remove/insert"
+ /// operation.
+ bool ReplaceText(SourceRange range, SourceRange replacementRange);
+
/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
/// printer to generate the replacement code. This returns true if the input
/// could not be rewritten, or false if successful.
bool ReplaceStmt(Stmt *From, Stmt *To);
+ /// \brief Increase indentation for the lines between the given source range.
+ /// To determine what the indentation should be, 'parentIndent' is used
+ /// that should be at a source location with an indentation one degree
+ /// lower than the given range.
+ bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent);
+ bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) {
+ return IncreaseIndentation(CharSourceRange::getTokenRange(range),
+ parentIndent);
+ }
+
+ /// ConvertToString converts statement 'From' to a string using the
+ /// pretty printer.
+ std::string ConvertToString(Stmt *From);
+
/// getEditBuffer - This is like getRewriteBufferFor, but always returns a
/// buffer, and allows you to write on it directly. This is useful if you
/// want efficient low-level access to apis for scribbling on one specific
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 45ee579a02d3..72cd47589f91 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -16,14 +16,33 @@
#define LLVM_CLANG_SEMA_ATTRLIST_H
#include "llvm/Support/Allocator.h"
-#include "clang/Sema/Ownership.h"
+#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/VersionTuple.h"
#include <cassert>
namespace clang {
+ class ASTContext;
class IdentifierInfo;
class Expr;
+/// \brief Represents information about a change in availability for
+/// an entity, which is part of the encoding of the 'availability'
+/// attribute.
+struct AvailabilityChange {
+ /// \brief The location of the keyword indicating the kind of change.
+ SourceLocation KeywordLoc;
+
+ /// \brief The version number at which the change occurred.
+ VersionTuple Version;
+
+ /// \brief The source range covering the version number.
+ SourceRange VersionRange;
+
+ /// \brief Determine whether this availability change is valid.
+ bool isValid() const { return !Version.empty(); }
+};
+
/// AttributeList - Represents GCC's __attribute__ declaration. There are
/// 4 forms of this construct...they are:
///
@@ -32,52 +51,102 @@ namespace clang {
/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used.
/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
///
-class AttributeList {
-public:
- class Factory;
+class AttributeList { // TODO: This should really be called ParsedAttribute
private:
IdentifierInfo *AttrName;
- SourceLocation AttrLoc;
IdentifierInfo *ScopeName;
- SourceLocation ScopeLoc;
IdentifierInfo *ParmName;
+ SourceLocation AttrLoc;
+ SourceLocation ScopeLoc;
SourceLocation ParmLoc;
- Expr **Args;
- unsigned NumArgs;
- AttributeList *Next;
- bool DeclspecAttribute, CXX0XAttribute;
+
+ /// The number of expression arguments this attribute has.
+ /// The expressions themselves are stored after the object.
+ unsigned NumArgs : 16;
+
+ /// True if Microsoft style: declspec(foo).
+ unsigned DeclspecAttribute : 1;
+
+ /// True if C++0x-style: [[foo]].
+ unsigned CXX0XAttribute : 1;
/// True if already diagnosed as invalid.
- mutable bool Invalid;
+ mutable unsigned Invalid : 1;
+
+ /// True if this has the extra information associated with an
+ /// availability attribute.
+ unsigned IsAvailability : 1;
+
+ /// \brief The location of the 'unavailable' keyword in an
+ /// availability attribute.
+ SourceLocation UnavailableLoc;
+
+ /// The next attribute in the current position.
+ AttributeList *NextInPosition;
+
+ /// The next attribute allocated in the current Pool.
+ AttributeList *NextInPool;
+
+ Expr **getArgsBuffer() {
+ return reinterpret_cast<Expr**>(this+1);
+ }
+ Expr * const *getArgsBuffer() const {
+ return reinterpret_cast<Expr* const *>(this+1);
+ }
+
+ enum AvailabilitySlot {
+ IntroducedSlot, DeprecatedSlot, ObsoletedSlot
+ };
+
+ AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) {
+ return reinterpret_cast<AvailabilityChange*>(this+1)[index];
+ }
+ const AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) const {
+ return reinterpret_cast<const AvailabilityChange*>(this+1)[index];
+ }
AttributeList(const AttributeList &); // DO NOT IMPLEMENT
void operator=(const AttributeList &); // DO NOT IMPLEMENT
void operator delete(void *); // DO NOT IMPLEMENT
~AttributeList(); // DO NOT IMPLEMENT
- AttributeList(llvm::BumpPtrAllocator &Alloc,
- IdentifierInfo *AttrName, SourceLocation AttrLoc,
- IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
- IdentifierInfo *ParmName, SourceLocation ParmLoc,
- Expr **args, unsigned numargs,
- bool declspec, bool cxx0x);
+
+ size_t allocated_size() const;
+
+ AttributeList(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ Expr **args, unsigned numArgs,
+ bool declspec, bool cxx0x)
+ : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
+ AttrLoc(attrLoc), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ NumArgs(numArgs),
+ DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false),
+ IsAvailability(false), NextInPosition(0), NextInPool(0) {
+ if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
+ }
+
+ AttributeList(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ const AvailabilityChange &introduced,
+ const AvailabilityChange &deprecated,
+ const AvailabilityChange &obsoleted,
+ SourceLocation unavailable,
+ bool declspec, bool cxx0x)
+ : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
+ AttrLoc(attrLoc), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x),
+ Invalid(false), IsAvailability(true), UnavailableLoc(unavailable),
+ NextInPosition(0), NextInPool(0) {
+ new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
+ new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
+ new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
+ }
+
+ friend class AttributePool;
+ friend class AttributeFactory;
+
public:
- class Factory {
- llvm::BumpPtrAllocator Alloc;
- public:
- Factory() {}
- ~Factory() {}
- AttributeList *Create(IdentifierInfo *AttrName, SourceLocation AttrLoc,
- IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
- IdentifierInfo *ParmName, SourceLocation ParmLoc,
- Expr **args, unsigned numargs, bool declspec = false, bool cxx0x = false) {
- AttributeList *Mem = Alloc.Allocate<AttributeList>();
- new (Mem) AttributeList(Alloc, AttrName, AttrLoc, ScopeName, ScopeLoc,
- ParmName, ParmLoc, args, numargs,
- declspec, cxx0x);
- return Mem;
- }
- };
-
enum Kind { // Please keep this list alphabetized.
AT_IBAction, // Clang-specific.
AT_IBOutlet, // Clang-specific.
@@ -88,6 +157,7 @@ public:
AT_always_inline,
AT_analyzer_noreturn,
AT_annotate,
+ AT_availability, // Clang-specific
AT_base_check,
AT_blocks,
AT_carries_dependency,
@@ -125,6 +195,7 @@ public:
AT_nothrow,
AT_nsobject,
AT_objc_exception,
+ AT_objc_method_family,
AT_cf_returns_not_retained, // Clang-specific.
AT_cf_returns_retained, // Clang-specific.
AT_ns_returns_not_retained, // Clang-specific.
@@ -134,6 +205,7 @@ public:
AT_ns_consumed, // Clang-specific.
AT_ns_consumes_self, // Clang-specific.
AT_objc_gc,
+ AT_opencl_image_access, // OpenCL-specific.
AT_opencl_kernel_function, // OpenCL-specific.
AT_overloadable, // Clang-specific.
AT_ownership_holds, // Clang-specific.
@@ -141,6 +213,7 @@ public:
AT_ownership_takes, // Clang-specific.
AT_packed,
AT_pascal,
+ AT_pcs, // ARM specific
AT_pure,
AT_regparm,
AT_section,
@@ -162,6 +235,7 @@ public:
AT_weak_import,
AT_reqd_wg_size,
AT_init_priority,
+ AT_MsStruct,
IgnoredAttribute,
UnknownAttribute
};
@@ -185,23 +259,27 @@ public:
Kind getKind() const { return getKind(getName()); }
static Kind getKind(const IdentifierInfo *Name);
- AttributeList *getNext() const { return Next; }
- void setNext(AttributeList *N) { Next = N; }
+ AttributeList *getNext() const { return NextInPosition; }
+ void setNext(AttributeList *N) { NextInPosition = N; }
/// getNumArgs - Return the number of actual arguments to this attribute.
unsigned getNumArgs() const { return NumArgs; }
+ /// hasParameterOrArguments - Return true if this attribute has a parameter,
+ /// or has a non empty argument expression list.
+ bool hasParameterOrArguments() const { return ParmName || NumArgs; }
+
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) const {
assert(Arg < NumArgs && "Arg access out of range!");
- return Args[Arg];
+ return getArgsBuffer()[Arg];
}
class arg_iterator {
- Expr** X;
+ Expr * const *X;
unsigned Idx;
public:
- arg_iterator(Expr** x, unsigned idx) : X(x), Idx(idx) {}
+ arg_iterator(Expr * const *x, unsigned idx) : X(x), Idx(idx) {}
arg_iterator& operator++() {
++Idx;
@@ -228,14 +306,167 @@ public:
};
arg_iterator arg_begin() const {
- return arg_iterator(Args, 0);
+ return arg_iterator(getArgsBuffer(), 0);
}
arg_iterator arg_end() const {
- return arg_iterator(Args, NumArgs);
+ return arg_iterator(getArgsBuffer(), NumArgs);
+ }
+
+ const AvailabilityChange &getAvailabilityIntroduced() const {
+ assert(getKind() == AT_availability && "Not an availability attribute");
+ return getAvailabilitySlot(IntroducedSlot);
+ }
+
+ const AvailabilityChange &getAvailabilityDeprecated() const {
+ assert(getKind() == AT_availability && "Not an availability attribute");
+ return getAvailabilitySlot(DeprecatedSlot);
+ }
+
+ const AvailabilityChange &getAvailabilityObsoleted() const {
+ assert(getKind() == AT_availability && "Not an availability attribute");
+ return getAvailabilitySlot(ObsoletedSlot);
+ }
+
+ SourceLocation getUnavailableLoc() const {
+ assert(getKind() == AT_availability && "Not an availability attribute");
+ return UnavailableLoc;
}
};
+/// A factory, from which one makes pools, from which one creates
+/// individual attributes which are deallocated with the pool.
+///
+/// Note that it's tolerably cheap to create and destroy one of
+/// these as long as you don't actually allocate anything in it.
+class AttributeFactory {
+public:
+ enum {
+ /// The required allocation size of an availability attribute,
+ /// which we want to ensure is a multiple of sizeof(void*).
+ AvailabilityAllocSize =
+ sizeof(AttributeList)
+ + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1)
+ / sizeof(void*) * sizeof(void*))
+ };
+
+private:
+ enum {
+ /// The number of free lists we want to be sure to support
+ /// inline. This is just enough that availability attributes
+ /// don't surpass it. It's actually very unlikely we'll see an
+ /// attribute that needs more than that; on x86-64 you'd need 10
+ /// expression arguments, and on i386 you'd need 19.
+ InlineFreeListsCapacity =
+ 1 + (AvailabilityAllocSize - sizeof(AttributeList)) / sizeof(void*)
+ };
+
+ llvm::BumpPtrAllocator Alloc;
+
+ /// Free lists. The index is determined by the following formula:
+ /// (size - sizeof(AttributeList)) / sizeof(void*)
+ llvm::SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists;
+
+ // The following are the private interface used by AttributePool.
+ friend class AttributePool;
+
+ /// Allocate an attribute of the given size.
+ void *allocate(size_t size);
+
+ /// Reclaim all the attributes in the given pool chain, which is
+ /// non-empty. Note that the current implementation is safe
+ /// against reclaiming things which were not actually allocated
+ /// with the allocator, although of course it's important to make
+ /// sure that their allocator lives at least as long as this one.
+ void reclaimPool(AttributeList *head);
+
+public:
+ AttributeFactory();
+ ~AttributeFactory();
+};
+
+class AttributePool {
+ AttributeFactory &Factory;
+ AttributeList *Head;
+
+ void *allocate(size_t size) {
+ return Factory.allocate(size);
+ }
+
+ AttributeList *add(AttributeList *attr) {
+ // We don't care about the order of the pool.
+ attr->NextInPool = Head;
+ Head = attr;
+ return attr;
+ }
+
+ void takePool(AttributeList *pool);
+
+public:
+ /// Create a new pool for a factory.
+ AttributePool(AttributeFactory &factory) : Factory(factory), Head(0) {}
+
+ /// Move the given pool's allocations to this pool.
+ AttributePool(AttributePool &pool) : Factory(pool.Factory), Head(pool.Head) {
+ pool.Head = 0;
+ }
+
+ AttributeFactory &getFactory() const { return Factory; }
+
+ void clear() {
+ if (Head) {
+ Factory.reclaimPool(Head);
+ Head = 0;
+ }
+ }
+
+ /// Take the given pool's allocations and add them to this pool.
+ void takeAllFrom(AttributePool &pool) {
+ if (pool.Head) {
+ takePool(pool.Head);
+ pool.Head = 0;
+ }
+ }
+
+ ~AttributePool() {
+ if (Head) Factory.reclaimPool(Head);
+ }
+
+ AttributeList *create(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ Expr **args, unsigned numArgs,
+ bool declspec = false, bool cxx0x = false) {
+ void *memory = allocate(sizeof(AttributeList)
+ + numArgs * sizeof(Expr*));
+ return add(new (memory) AttributeList(attrName, attrLoc,
+ scopeName, scopeLoc,
+ parmName, parmLoc,
+ args, numArgs,
+ declspec, cxx0x));
+ }
+
+ AttributeList *create(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ const AvailabilityChange &introduced,
+ const AvailabilityChange &deprecated,
+ const AvailabilityChange &obsoleted,
+ SourceLocation unavailable,
+ bool declspec = false, bool cxx0x = false) {
+ void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
+ return add(new (memory) AttributeList(attrName, attrLoc,
+ scopeName, scopeLoc,
+ parmName, parmLoc,
+ introduced, deprecated, obsoleted,
+ unavailable,
+ declspec, cxx0x));
+ }
+
+ AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
+ SourceLocation TokLoc, int Arg);
+};
+
/// addAttributeLists - Add two AttributeLists together
/// The right-hand list is appended to the left-hand list, if any
/// A pointer to the joined list is returned.
@@ -278,7 +509,16 @@ struct CXX0XAttributeList {
/// is that this will become significantly more serious.
class ParsedAttributes {
public:
- ParsedAttributes() : list(0) {}
+ ParsedAttributes(AttributeFactory &factory)
+ : pool(factory), list(0) {
+ }
+
+ ParsedAttributes(ParsedAttributes &attrs)
+ : pool(attrs.pool), list(attrs.list) {
+ attrs.list = 0;
+ }
+
+ AttributePool &getPool() const { return pool; }
bool empty() const { return list == 0; }
@@ -289,7 +529,7 @@ public:
list = newAttr;
}
- void append(AttributeList *newList) {
+ void addAll(AttributeList *newList) {
if (!newList) return;
AttributeList *lastInNewList = newList;
@@ -304,14 +544,59 @@ public:
list = newList;
}
- void clear() { list = 0; }
+ void takeAllFrom(ParsedAttributes &attrs) {
+ addAll(attrs.list);
+ attrs.list = 0;
+ pool.takeAllFrom(attrs.pool);
+ }
+
+ void clear() { list = 0; pool.clear(); }
AttributeList *getList() const { return list; }
/// Returns a reference to the attribute list. Try not to introduce
/// dependencies on this method, it may not be long-lived.
AttributeList *&getListRef() { return list; }
+
+ AttributeList *addNew(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ Expr **args, unsigned numArgs,
+ bool declspec = false, bool cxx0x = false) {
+ AttributeList *attr =
+ pool.create(attrName, attrLoc, scopeName, scopeLoc, parmName, parmLoc,
+ args, numArgs, declspec, cxx0x);
+ add(attr);
+ return attr;
+ }
+
+ AttributeList *addNew(IdentifierInfo *attrName, SourceLocation attrLoc,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ const AvailabilityChange &introduced,
+ const AvailabilityChange &deprecated,
+ const AvailabilityChange &obsoleted,
+ SourceLocation unavailable,
+ bool declspec = false, bool cxx0x = false) {
+ AttributeList *attr =
+ pool.create(attrName, attrLoc, scopeName, scopeLoc, parmName, parmLoc,
+ introduced, deprecated, obsoleted, unavailable,
+ declspec, cxx0x);
+ add(attr);
+ return attr;
+ }
+
+ AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name,
+ SourceLocation loc, int arg) {
+ AttributeList *attr =
+ pool.createIntegerAttribute(C, name, loc, arg);
+ add(attr);
+ return attr;
+ }
+
+
private:
+ mutable AttributePool pool;
AttributeList *list;
};
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 64126bd4d80a..708c9b2084b0 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -22,7 +22,9 @@
#include "clang/Sema/AttributeList.h"
#include "clang/Sema/Ownership.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Lex/Token.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/SmallVector.h"
@@ -54,32 +56,10 @@ namespace clang {
///
/// The actual scope is described by getScopeRep().
class CXXScopeSpec {
- SourceRange Range;
- NestedNameSpecifier *ScopeRep;
-
- /// \brief Buffer used to store source-location information for the
- /// nested-name-specifier.
- ///
- /// Note that we explicitly manage the buffer (rather than using a
- /// SmallVector) because \c Declarator expects it to be possible to memcpy()
- /// a \c CXXScopeSpec.
- char *Buffer;
-
- /// \brief The size of the buffer used to store source-location information
- /// for the nested-name-specifier.
- unsigned BufferSize;
-
- /// \brief The capacity of the buffer used to store source-location
- /// information for the nested-name-specifier.
- unsigned BufferCapacity;
+ SourceRange Range;
+ NestedNameSpecifierLocBuilder Builder;
public:
- CXXScopeSpec() : Range(), ScopeRep(), Buffer(0), BufferSize(0),
- BufferCapacity(0) { }
- CXXScopeSpec(const CXXScopeSpec &Other);
- CXXScopeSpec &operator=(const CXXScopeSpec &Other);
- ~CXXScopeSpec();
-
const SourceRange &getRange() const { return Range; }
void setRange(const SourceRange &R) { Range = R; }
void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); }
@@ -87,7 +67,10 @@ public:
SourceLocation getBeginLoc() const { return Range.getBegin(); }
SourceLocation getEndLoc() const { return Range.getEnd(); }
- NestedNameSpecifier *getScopeRep() const { return ScopeRep; }
+ /// \brief Retrieve the representation of the nested-name-specifier.
+ NestedNameSpecifier *getScopeRep() const {
+ return Builder.getRepresentation();
+ }
/// \brief Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'type::'.
@@ -175,10 +158,10 @@ public:
/// A scope specifier is present, but may be valid or invalid.
bool isNotEmpty() const { return !isEmpty(); }
- /// An error occured during parsing of the scope specifier.
- bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; }
+ /// An error occurred during parsing of the scope specifier.
+ bool isInvalid() const { return isNotEmpty() && getScopeRep() == 0; }
/// A scope specifier is present, and it refers to a real scope.
- bool isValid() const { return isNotEmpty() && ScopeRep != 0; }
+ bool isValid() const { return isNotEmpty() && getScopeRep() != 0; }
/// \brief Indicate that this nested-name-specifier is invalid.
void SetInvalid(SourceRange R) {
@@ -186,24 +169,24 @@ public:
if (Range.getBegin().isInvalid())
Range.setBegin(R.getBegin());
Range.setEnd(R.getEnd());
- ScopeRep = 0;
+ Builder.Clear();
}
/// Deprecated. Some call sites intend isNotEmpty() while others intend
/// isValid().
- bool isSet() const { return ScopeRep != 0; }
+ bool isSet() const { return getScopeRep() != 0; }
void clear() {
Range = SourceRange();
- ScopeRep = 0;
+ Builder.Clear();
}
/// \brief Retrieve the data associated with the source-location information.
- char *location_data() const { return Buffer; }
+ char *location_data() const { return Builder.getBuffer().first; }
/// \brief Retrieve the size of the data associated with source-location
/// information.
- unsigned location_size() const { return BufferSize; }
+ unsigned location_size() const { return Builder.getBuffer().second; }
};
/// DeclSpec - This class captures information about "declaration specifiers",
@@ -267,6 +250,7 @@ public:
static const TST TST_typeofExpr = clang::TST_typeofExpr;
static const TST TST_decltype = clang::TST_decltype;
static const TST TST_auto = clang::TST_auto;
+ static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
static const TST TST_error = clang::TST_error;
// type-qualifiers
@@ -288,7 +272,6 @@ public:
};
private:
-
// storage-class-specifier
/*SCS*/unsigned StorageClassSpec : 3;
unsigned SCS_thread_specified : 1;
@@ -346,6 +329,11 @@ private:
SourceLocation StorageClassSpecLoc, SCS_threadLoc;
SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc, AltiVecLoc;
+ /// TSTNameLoc - If TypeSpecType is any of class, enum, struct, union,
+ /// typename, then this is the location of the named type (if present);
+ /// otherwise, it is the same as TSTLoc. Hence, the pair TSTLoc and
+ /// TSTNameLoc provides source range info for tag types.
+ SourceLocation TSTNameLoc;
SourceRange TypeofParensRange;
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
@@ -370,7 +358,7 @@ private:
void operator=(const DeclSpec&); // DO NOT IMPLEMENT
public:
- DeclSpec()
+ DeclSpec(AttributeFactory &attrFactory)
: StorageClassSpec(SCS_unspecified),
SCS_thread_specified(false),
SCS_extern_in_linkage_spec(false),
@@ -389,6 +377,7 @@ public:
Friend_specified(false),
Constexpr_specified(false),
StorageClassSpecAsWritten(SCS_unspecified),
+ Attrs(attrFactory),
ProtocolQualifiers(0),
NumProtocolQualifiers(0),
ProtocolLocs(0),
@@ -448,6 +437,11 @@ public:
SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; }
SourceLocation getAltiVecLoc() const { return AltiVecLoc; }
+ SourceLocation getTypeSpecTypeNameLoc() const {
+ assert(isDeclRep((TST) TypeSpecType) || TypeSpecType == TST_typename);
+ return TSTNameLoc;
+ }
+
SourceRange getTypeofParensRange() const { return TypeofParensRange; }
void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
@@ -539,6 +533,13 @@ public:
unsigned &DiagID, ParsedType Rep);
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, Decl *Rep, bool Owned);
+ bool SetTypeSpecType(TST T, SourceLocation TagKwLoc,
+ SourceLocation TagNameLoc, const char *&PrevSpec,
+ unsigned &DiagID, ParsedType Rep);
+ bool SetTypeSpecType(TST T, SourceLocation TagKwLoc,
+ SourceLocation TagNameLoc, const char *&PrevSpec,
+ unsigned &DiagID, Decl *Rep, bool Owned);
+
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, Expr *Rep);
bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
@@ -581,6 +582,10 @@ public:
bool isConstexprSpecified() const { return Constexpr_specified; }
SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
+ AttributePool &getAttributePool() const {
+ return Attrs.getPool();
+ }
+
/// AddAttributes - contatenates two attribute lists.
/// The GCC attribute syntax allows for the following:
///
@@ -594,9 +599,9 @@ public:
/// int __attribute__((may_alias)) __attribute__((aligned(16))) var;
///
void addAttributes(AttributeList *AL) {
- Attrs.append(AL);
+ Attrs.addAll(AL);
}
- void aetAttributes(AttributeList *AL) {
+ void setAttributes(AttributeList *AL) {
Attrs.set(AL);
}
@@ -608,14 +613,12 @@ public:
/// TakeAttributes - Return the current attribute list and remove them from
/// the DeclSpec so that it doesn't own them.
ParsedAttributes takeAttributes() {
- ParsedAttributes saved = Attrs;
- Attrs.clear();
- return saved;
+ // The non-const "copy" constructor clears the operand automatically.
+ return Attrs;
}
void takeAttributesFrom(ParsedAttributes &attrs) {
- Attrs.append(attrs.getList());
- attrs.clear();
+ Attrs.takeAllFrom(attrs);
}
typedef Decl * const *ProtocolQualifierListTy;
@@ -649,7 +652,12 @@ public:
/// "declaration specifiers" specific to objective-c
class ObjCDeclSpec {
public:
- /// ObjCDeclQualifier - Qualifier used on types in method declarations
+ /// ObjCDeclQualifier - Qualifier used on types in method
+ /// declarations. Not all combinations are sensible. Parameters
+ /// can be one of { in, out, inout } with one of { bycopy, byref }.
+ /// Returns can either be { oneway } or not.
+ ///
+ /// This should be kept in sync with Decl::ObjCDeclQualifier.
enum ObjCDeclQualifier {
DQ_None = 0x0,
DQ_In = 0x1,
@@ -661,7 +669,8 @@ public:
};
/// PropertyAttributeKind - list of property attributes.
- enum ObjCPropertyAttributeKind { DQ_PR_noattr = 0x0,
+ enum ObjCPropertyAttributeKind {
+ DQ_PR_noattr = 0x0,
DQ_PR_readonly = 0x01,
DQ_PR_getter = 0x02,
DQ_PR_assign = 0x04,
@@ -1037,11 +1046,8 @@ struct DeclaratorChunk {
/// The qualifier bitmask values are the same as in QualType.
unsigned TypeQuals : 3;
- /// hasExceptionSpec - True if the function has an exception specification.
- unsigned hasExceptionSpec : 1;
-
- /// hasAnyExceptionSpec - True if the function has a throw(...) specifier.
- unsigned hasAnyExceptionSpec : 1;
+ /// ExceptionSpecType - An ExceptionSpecificationType value.
+ unsigned ExceptionSpecType : 3;
/// DeleteArgInfo - If this is true, we need to delete[] ArgInfo.
unsigned DeleteArgInfo : 1;
@@ -1053,28 +1059,34 @@ struct DeclaratorChunk {
/// declarator.
unsigned NumArgs;
- /// NumExceptions - This is the number of types in the exception-decl, if
- /// the function has one.
+ /// NumExceptions - This is the number of types in the dynamic-exception-
+ /// decl, if the function has one.
unsigned NumExceptions;
/// \brief The location of the ref-qualifier, if any.
///
/// If this is an invalid location, there is no ref-qualifier.
unsigned RefQualifierLoc;
-
- /// ThrowLoc - When hasExceptionSpec is true, the location of the throw
+
+ /// \brief When ExceptionSpecType isn't EST_None, the location of the
/// keyword introducing the spec.
- unsigned ThrowLoc;
+ unsigned ExceptionSpecLoc;
/// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that
/// describe the arguments for this function declarator. This is null if
/// there are no arguments specified.
ParamInfo *ArgInfo;
- /// Exceptions - This is a pointer to a new[]'d array of TypeAndRange
- /// objects that contain the types in the function's exception
- /// specification and their locations.
- TypeAndRange *Exceptions;
+ union {
+ /// \brief Pointer to a new[]'d array of TypeAndRange objects that
+ /// contain the types in the function's dynamic exception specification
+ /// and their locations, if there is one.
+ TypeAndRange *Exceptions;
+
+ /// \brief Pointer to the expression in the noexcept-specifier of this
+ /// function, if it has one.
+ Expr *NoexceptExpr;
+ };
/// TrailingReturnType - If this isn't null, it's the trailing return type
/// specified. This is actually a ParsedType, but stored as void* to
@@ -1094,7 +1106,8 @@ struct DeclaratorChunk {
void destroy() {
if (DeleteArgInfo)
delete[] ArgInfo;
- delete[] Exceptions;
+ if (getExceptionSpecType() == EST_Dynamic)
+ delete[] Exceptions;
}
/// isKNRPrototype - Return true if this is a K&R style identifier list,
@@ -1107,18 +1120,23 @@ struct DeclaratorChunk {
SourceLocation getEllipsisLoc() const {
return SourceLocation::getFromRawEncoding(EllipsisLoc);
}
- SourceLocation getThrowLoc() const {
- return SourceLocation::getFromRawEncoding(ThrowLoc);
+ SourceLocation getExceptionSpecLoc() const {
+ return SourceLocation::getFromRawEncoding(ExceptionSpecLoc);
}
-
+
/// \brief Retrieve the location of the ref-qualifier, if any.
SourceLocation getRefQualifierLoc() const {
return SourceLocation::getFromRawEncoding(RefQualifierLoc);
}
-
+
/// \brief Determine whether this function declaration contains a
/// ref-qualifier.
bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); }
+
+ /// \brief Get the type of exception specification this function has.
+ ExceptionSpecificationType getExceptionSpecType() const {
+ return static_cast<ExceptionSpecificationType>(ExceptionSpecType);
+ }
};
struct BlockPointerTypeInfo : TypeInfoCommon {
@@ -1188,8 +1206,7 @@ struct DeclaratorChunk {
static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc,
SourceLocation ConstQualLoc,
SourceLocation VolatileQualLoc,
- SourceLocation RestrictQualLoc,
- const ParsedAttributes &attrs) {
+ SourceLocation RestrictQualLoc) {
DeclaratorChunk I;
I.Kind = Pointer;
I.Loc = Loc;
@@ -1197,35 +1214,33 @@ struct DeclaratorChunk {
I.Ptr.ConstQualLoc = ConstQualLoc.getRawEncoding();
I.Ptr.VolatileQualLoc = VolatileQualLoc.getRawEncoding();
I.Ptr.RestrictQualLoc = RestrictQualLoc.getRawEncoding();
- I.Ptr.AttrList = attrs.getList();
+ I.Ptr.AttrList = 0;
return I;
}
/// getReference - Return a DeclaratorChunk for a reference.
///
static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc,
- const ParsedAttributes &attrs,
bool lvalue) {
DeclaratorChunk I;
I.Kind = Reference;
I.Loc = Loc;
I.Ref.HasRestrict = (TypeQuals & DeclSpec::TQ_restrict) != 0;
I.Ref.LValueRef = lvalue;
- I.Ref.AttrList = attrs.getList();
+ I.Ref.AttrList = 0;
return I;
}
/// getArray - Return a DeclaratorChunk for an array.
///
static DeclaratorChunk getArray(unsigned TypeQuals,
- const ParsedAttributes &attrs,
bool isStatic, bool isStar, Expr *NumElts,
SourceLocation LBLoc, SourceLocation RBLoc) {
DeclaratorChunk I;
I.Kind = Array;
I.Loc = LBLoc;
I.EndLoc = RBLoc;
- I.Arr.AttrList = attrs.getList();
+ I.Arr.AttrList = 0;
I.Arr.TypeQuals = TypeQuals;
I.Arr.hasStatic = isStatic;
I.Arr.isStar = isStar;
@@ -1235,44 +1250,44 @@ struct DeclaratorChunk {
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
- static DeclaratorChunk getFunction(const ParsedAttributes &attrs,
- bool hasProto, bool isVariadic,
+ static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,
SourceLocation EllipsisLoc,
ParamInfo *ArgInfo, unsigned NumArgs,
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
- bool hasExceptionSpec,
- SourceLocation ThrowLoc,
- bool hasAnyExceptionSpec,
+ ExceptionSpecificationType ESpecType,
+ SourceLocation ESpecLoc,
ParsedType *Exceptions,
SourceRange *ExceptionRanges,
unsigned NumExceptions,
- SourceLocation LPLoc, SourceLocation RPLoc,
+ Expr *NoexceptExpr,
+ SourceLocation LocalRangeBegin,
+ SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
- ParsedType TrailingReturnType = ParsedType());
+ ParsedType TrailingReturnType =
+ ParsedType());
/// getBlockPointer - Return a DeclaratorChunk for a block.
///
- static DeclaratorChunk getBlockPointer(unsigned TypeQuals, SourceLocation Loc,
- const ParsedAttributes &attrs) {
+ static DeclaratorChunk getBlockPointer(unsigned TypeQuals,
+ SourceLocation Loc) {
DeclaratorChunk I;
I.Kind = BlockPointer;
I.Loc = Loc;
I.Cls.TypeQuals = TypeQuals;
- I.Cls.AttrList = attrs.getList();
+ I.Cls.AttrList = 0;
return I;
}
static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS,
unsigned TypeQuals,
- SourceLocation Loc,
- const ParsedAttributes &attrs) {
+ SourceLocation Loc) {
DeclaratorChunk I;
I.Kind = MemberPointer;
I.Loc = Loc;
I.Mem.TypeQuals = TypeQuals;
- I.Mem.AttrList = attrs.getList();
+ I.Mem.AttrList = 0;
new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS);
return I;
}
@@ -1306,6 +1321,7 @@ public:
enum TheContext {
FileContext, // File scope declaration.
PrototypeContext, // Within a function prototype.
+ ObjCPrototypeContext,// Within a method prototype.
KNRTypeListContext, // K&R type definition list for formals.
TypeNameContext, // Abstract declarator for types.
MemberContext, // Struct/Union field.
@@ -1315,7 +1331,8 @@ public:
TemplateParamContext,// Within a template parameter list.
CXXCatchContext, // C++ catch exception-declaration
BlockLiteralContext, // Block literal declarator.
- TemplateTypeArgContext // Template type argument.
+ TemplateTypeArgContext, // Template type argument.
+ AliasDeclContext // C++0x alias-declaration.
};
private:
@@ -1340,8 +1357,8 @@ private:
/// GroupingParens - Set by Parser::ParseParenDeclarator().
bool GroupingParens : 1;
- /// AttrList - Attributes.
- AttributeList *AttrList;
+ /// Attrs - Attributes.
+ ParsedAttributes Attrs;
/// AsmLabel - The asm label, if specified.
Expr *AsmLabel;
@@ -1365,8 +1382,8 @@ public:
Declarator(const DeclSpec &ds, TheContext C)
: DS(ds), Range(ds.getSourceRange()), Context(C),
InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
- GroupingParens(false), AttrList(0), AsmLabel(0),
- InlineParamsUsed(false), Extension(false) {
+ GroupingParens(false), Attrs(ds.getAttributePool().getFactory()),
+ AsmLabel(0), InlineParamsUsed(false), Extension(false) {
}
~Declarator() {
@@ -1384,6 +1401,10 @@ public:
/// be shared or when in error recovery etc.
DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); }
+ AttributePool &getAttributePool() const {
+ return Attrs.getPool();
+ }
+
/// getCXXScopeSpec - Return the C++ scope specifier (global scope or
/// nested-name-specifier) that is part of the declarator-id.
const CXXScopeSpec &getCXXScopeSpec() const { return SS; }
@@ -1394,6 +1415,10 @@ public:
TheContext getContext() const { return Context; }
+ bool isPrototypeContext() const {
+ return (Context == PrototypeContext || Context == ObjCPrototypeContext);
+ }
+
/// getSourceRange - Get the source range that spans this declarator.
const SourceRange &getSourceRange() const { return Range; }
@@ -1429,7 +1454,7 @@ public:
for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i)
DeclTypeInfo[i].destroy();
DeclTypeInfo.clear();
- AttrList = 0;
+ Attrs.clear();
AsmLabel = 0;
InlineParamsUsed = false;
}
@@ -1438,26 +1463,79 @@ public:
/// not allowed. This is true for typenames, prototypes, and template
/// parameter lists.
bool mayOmitIdentifier() const {
- return Context == TypeNameContext || Context == PrototypeContext ||
- Context == TemplateParamContext || Context == CXXCatchContext ||
- Context == BlockLiteralContext || Context == TemplateTypeArgContext;
+ switch (Context) {
+ case FileContext:
+ case KNRTypeListContext:
+ case MemberContext:
+ case BlockContext:
+ case ForContext:
+ case ConditionContext:
+ return false;
+
+ case TypeNameContext:
+ case AliasDeclContext:
+ case PrototypeContext:
+ case ObjCPrototypeContext:
+ case TemplateParamContext:
+ case CXXCatchContext:
+ case BlockLiteralContext:
+ case TemplateTypeArgContext:
+ return true;
+ }
+ llvm_unreachable("unknown context kind!");
}
/// mayHaveIdentifier - Return true if the identifier is either optional or
/// required. This is true for normal declarators and prototypes, but not
/// typenames.
bool mayHaveIdentifier() const {
- return Context != TypeNameContext && Context != BlockLiteralContext &&
- Context != TemplateTypeArgContext;
+ switch (Context) {
+ case FileContext:
+ case KNRTypeListContext:
+ case MemberContext:
+ case BlockContext:
+ case ForContext:
+ case ConditionContext:
+ case PrototypeContext:
+ case TemplateParamContext:
+ case CXXCatchContext:
+ return true;
+
+ case TypeNameContext:
+ case AliasDeclContext:
+ case ObjCPrototypeContext:
+ case BlockLiteralContext:
+ case TemplateTypeArgContext:
+ return false;
+ }
+ llvm_unreachable("unknown context kind!");
}
/// mayBeFollowedByCXXDirectInit - Return true if the declarator can be
/// followed by a C++ direct initializer, e.g. "int x(1);".
bool mayBeFollowedByCXXDirectInit() const {
- return !hasGroupingParens() &&
- (Context == FileContext ||
- Context == BlockContext ||
- Context == ForContext);
+ if (hasGroupingParens()) return false;
+
+ switch (Context) {
+ case FileContext:
+ case BlockContext:
+ case ForContext:
+ return true;
+
+ case KNRTypeListContext:
+ case MemberContext:
+ case ConditionContext:
+ case PrototypeContext:
+ case ObjCPrototypeContext:
+ case TemplateParamContext:
+ case CXXCatchContext:
+ case TypeNameContext:
+ case AliasDeclContext:
+ case BlockLiteralContext:
+ case TemplateTypeArgContext:
+ return false;
+ }
+ llvm_unreachable("unknown context kind!");
}
/// isPastIdentifier - Return true if we have parsed beyond the point where
@@ -1486,8 +1564,13 @@ public:
/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
/// EndLoc, which should be the last token of the chunk.
- void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) {
+ void AddTypeInfo(const DeclaratorChunk &TI,
+ ParsedAttributes &attrs,
+ SourceLocation EndLoc) {
DeclTypeInfo.push_back(TI);
+ DeclTypeInfo.back().getAttrListRef() = attrs.getList();
+ getAttributePool().takeAllFrom(attrs.getPool());
+
if (!EndLoc.isInvalid())
SetRangeEnd(EndLoc);
}
@@ -1567,28 +1650,26 @@ public:
return const_cast<Declarator*>(this)->getFunctionTypeInfo();
}
- /// AddAttributes - simply adds the attribute list to the Declarator.
+ /// takeAttributes - Takes attributes from the given parsed-attributes
+ /// set and add them to this declarator.
+ ///
/// These examples both add 3 attributes to "var":
/// short int var __attribute__((aligned(16),common,deprecated));
/// short int x, __attribute__((aligned(16)) var
/// __attribute__((common,deprecated));
///
/// Also extends the range of the declarator.
- void addAttributes(AttributeList *alist, SourceLocation LastLoc) {
- AttrList = addAttributeLists(AttrList, alist);
+ void takeAttributes(ParsedAttributes &attrs, SourceLocation lastLoc) {
+ Attrs.takeAllFrom(attrs);
- if (!LastLoc.isInvalid())
- SetRangeEnd(LastLoc);
+ if (!lastLoc.isInvalid())
+ SetRangeEnd(lastLoc);
}
- void addAttributes(const ParsedAttributes &attrs) {
- addAttributes(attrs.getList(), SourceLocation());
- }
-
- const AttributeList *getAttributes() const { return AttrList; }
- AttributeList *getAttributes() { return AttrList; }
+ const AttributeList *getAttributes() const { return Attrs.getList(); }
+ AttributeList *getAttributes() { return Attrs.getList(); }
- AttributeList *&getAttrListRef() { return AttrList; }
+ AttributeList *&getAttrListRef() { return Attrs.getListRef(); }
/// hasAttributes - do we contain any attributes?
bool hasAttributes() const {
@@ -1634,8 +1715,7 @@ public:
enum Specifier {
VS_None = 0,
VS_Override = 1,
- VS_Final = 2,
- VS_New = 4
+ VS_Final = 2
};
VirtSpecifiers() : Specifiers(0) { }
@@ -1649,45 +1729,17 @@ public:
bool isFinalSpecified() const { return Specifiers & VS_Final; }
SourceLocation getFinalLoc() const { return VS_finalLoc; }
- bool isNewSpecified() const { return Specifiers & VS_New; }
- SourceLocation getNewLoc() const { return VS_newLoc; }
-
void clear() { Specifiers = 0; }
static const char *getSpecifierName(Specifier VS);
+ SourceLocation getLastLocation() const { return LastLocation; }
+
private:
unsigned Specifiers;
- SourceLocation VS_overrideLoc, VS_finalLoc, VS_newLoc;
-};
-
-/// ClassVirtSpecifiers - Represents a C++0x class-virt-specifier-seq.
-class ClassVirtSpecifiers {
-public:
- enum Specifier {
- CVS_None = 0,
- CVS_Final = 1,
- CVS_Explicit = 2
- };
-
- ClassVirtSpecifiers() : Specifiers(0) { }
-
- bool SetSpecifier(Specifier CVS, SourceLocation Loc,
- const char *&PrevSpec);
-
- bool isFinalSpecified() const { return Specifiers & CVS_Final; }
- SourceLocation getFinalLoc() const { return CVS_finalLoc; }
-
- bool isExplicitSpecified() const { return Specifiers & CVS_Explicit; }
- SourceLocation getExplicitLoc() const { return CVS_explicitLoc; }
-
- static const char *getSpecifierName(Specifier CVS);
-
-private:
- unsigned Specifiers;
-
- SourceLocation CVS_finalLoc, CVS_explicitLoc;
+ SourceLocation VS_overrideLoc, VS_finalLoc;
+ SourceLocation LastLocation;
};
} // end namespace clang
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index 6e808de9a147..8395138ab612 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -119,25 +119,11 @@ public:
SourceLocation Loc;
- void destroy() {
- switch (Kind) {
- case Access: getAccessData().~AccessedEntity(); break;
- case Deprecation: break;
- }
- }
+ void Destroy();
static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
const NamedDecl *D,
- llvm::StringRef Msg) {
- DelayedDiagnostic DD;
- DD.Kind = Deprecation;
- DD.Triggered = false;
- DD.Loc = Loc;
- DD.DeprecationData.Decl = D;
- DD.DeprecationData.Message = Msg.data();
- DD.DeprecationData.MessageLen = Msg.size();
- return DD;
- }
+ llvm::StringRef Msg);
static DelayedDiagnostic makeAccess(SourceLocation Loc,
const AccessedEntity &Entity) {
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index 7e9d338293ee..8d79fc09f292 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -28,7 +28,7 @@ class Scope;
/// IdentifierResolver - Keeps track of shadowed decls on enclosing
/// scopes. It manages the shadowing chains of declaration names and
-/// implements efficent decl lookup based on a declaration name.
+/// implements efficient decl lookup based on a declaration name.
class IdentifierResolver {
/// IdDeclInfo - Keeps track of information about decls associated
@@ -53,6 +53,11 @@ class IdentifierResolver {
/// declaration was not found, returns false.
bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
+ /// \brief Insert the given declaration at the given position in the list.
+ void InsertDecl(DeclsTy::iterator Pos, NamedDecl *D) {
+ Decls.insert(Pos, D);
+ }
+
private:
DeclsTy Decls;
};
@@ -146,8 +151,13 @@ public:
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
+ ///
+ /// \param ExplicitInstantiationOrSpecialization When true, we are checking
+ /// whether the declaration is in scope for the purposes of explicit template
+ /// instantiation or specialization. The default is false.
bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context,
- Scope *S = 0) const;
+ Scope *S = 0,
+ bool ExplicitInstantiationOrSpecialization = false) const;
/// AddDecl - Link the decl to its shadowed decl chain.
void AddDecl(NamedDecl *D);
@@ -161,6 +171,10 @@ public:
/// (and, therefore, replaced).
bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
+ /// \brief Insert the given declaration after the given iterator
+ /// position.
+ void InsertDeclAfter(iterator Pos, NamedDecl *D);
+
/// \brief Link the declaration into the chain of declarations for
/// the given identifier.
///
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index bdf0d8e7b602..e83e5c0ccfda 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -64,6 +64,8 @@ public:
EK_Temporary,
/// \brief The entity being initialized is a base member subobject.
EK_Base,
+ /// \brief The initialization is being done by a delegating constructor.
+ EK_Delegating,
/// \brief The entity being initialized is an element of a vector.
/// or vector.
EK_VectorElement,
@@ -210,6 +212,11 @@ public:
static InitializedEntity InitializeBase(ASTContext &Context,
CXXBaseSpecifier *Base,
bool IsInheritedVirtualBase);
+
+ /// \brief Create the initialization entity for a delegated constructor.
+ static InitializedEntity InitializeDelegation(QualType Type) {
+ return InitializedEntity(EK_Delegating, SourceLocation(), Type);
+ }
/// \brief Create the initialization entity for a member subobject.
static InitializedEntity InitializeMember(FieldDecl *Member,
@@ -234,7 +241,7 @@ public:
EntityKind getKind() const { return Kind; }
/// \brief Retrieve the parent of the entity being initialized, when
- /// the initialization itself is occuring within the context of a
+ /// the initialization itself is occurring within the context of a
/// larger initialization.
const InitializedEntity *getParent() const { return Parent; }
@@ -590,6 +597,8 @@ public:
FK_ReferenceInitFailed,
/// \brief Implicit conversion failed.
FK_ConversionFailed,
+ /// \brief Implicit conversion failed.
+ FK_ConversionFromPropertyFailed,
/// \brief Too many initializers for scalar
FK_TooManyInitsForScalar,
/// \brief Reference initialization from an initializer list
@@ -655,7 +664,7 @@ public:
/// \param Kind the kind of initialization being performed.
///
/// \param Args the argument(s) provided for initialization, ownership of
- /// which is transfered into the routine.
+ /// which is transferred into the routine.
///
/// \param ResultType if non-NULL, will be set to the type of the
/// initialized object, which is the type of the declaration in most
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index aa58d14fac73..400a7cc9194d 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -439,6 +439,7 @@ public:
Decls.clear();
if (Paths) deletePaths(Paths);
Paths = NULL;
+ NamingClass = 0;
}
/// \brief Clears out any current state and re-initializes for a
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 3ce3513c21ae..e196e83a0e26 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -76,6 +76,7 @@ namespace clang {
ICK_Vector_Splat, ///< A vector splat from an arithmetic type
ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
ICK_Block_Pointer_Conversion, ///< Block Pointer conversions
+ ICK_TransparentUnionConversion, /// Transparent Union Conversions
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
@@ -647,8 +648,6 @@ namespace clang {
/// \brief Clear out all of the candidates.
void clear();
-
- ~OverloadCandidateSet() { clear(); }
/// Find the best viable function on this overload set, if it exists.
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index 5f2f0eba7124..cef93fe5832f 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -383,11 +383,18 @@ namespace clang {
template<typename T> T **takeAs() { return reinterpret_cast<T**>(take()); }
};
+ /// An opaque type for threading parsed type information through the
+ /// parser.
+ typedef OpaquePtr<QualType> ParsedType;
+ typedef UnionOpaquePtr<QualType> UnionParsedType;
+
/// A SmallVector of statements, with stack size 32 (as that is the only one
/// used.)
typedef ASTOwningVector<Stmt*, 32> StmtVector;
/// A SmallVector of expressions, with stack size 12 (the maximum used.)
typedef ASTOwningVector<Expr*, 12> ExprVector;
+ /// A SmallVector of types.
+ typedef ASTOwningVector<ParsedType, 12> TypeVector;
template <class T, unsigned N> inline
ASTMultiPtr<T> move_arg(ASTOwningVector<T, N> &vec) {
@@ -421,11 +428,6 @@ namespace clang {
static const bool value = true;
};
- /// An opaque type for threading parsed type information through the
- /// parser.
- typedef OpaquePtr<QualType> ParsedType;
- typedef UnionOpaquePtr<QualType> UnionParsedType;
-
typedef ActionResult<Expr*> ExprResult;
typedef ActionResult<Stmt*> StmtResult;
typedef ActionResult<ParsedType> TypeResult;
@@ -440,6 +442,7 @@ namespace clang {
typedef ASTMultiPtr<Expr*> MultiExprArg;
typedef ASTMultiPtr<Stmt*> MultiStmtArg;
+ typedef ASTMultiPtr<ParsedType> MultiTypeArg;
typedef ASTMultiPtr<TemplateParameterList*> MultiTemplateParamsArg;
inline ExprResult ExprError() { return ExprResult(true); }
diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h
index 9e1a6165b194..1f572e5df4f3 100644
--- a/include/clang/Sema/ParsedTemplate.h
+++ b/include/clang/Sema/ParsedTemplate.h
@@ -139,6 +139,9 @@ namespace clang {
/// tokens. All of the information about template arguments is allocated
/// directly after this structure.
struct TemplateIdAnnotation {
+ /// \brief The nested-name-specifier that precedes the template name.
+ CXXScopeSpec SS;
+
/// TemplateNameLoc - The location of the template name within the
/// source.
SourceLocation TemplateNameLoc;
@@ -174,10 +177,13 @@ namespace clang {
static TemplateIdAnnotation* Allocate(unsigned NumArgs) {
TemplateIdAnnotation *TemplateId
- = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
+ = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
sizeof(ParsedTemplateArgument) * NumArgs);
TemplateId->NumArgs = NumArgs;
+ // Default-construct nested-name-specifier.
+ new (&TemplateId->SS) CXXScopeSpec();
+
// Default-construct parsed template arguments.
ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs();
for (unsigned I = 0; I != NumArgs; ++I)
@@ -186,7 +192,10 @@ namespace clang {
return TemplateId;
}
- void Destroy() { free(this); }
+ void Destroy() {
+ SS.~CXXScopeSpec();
+ free(this);
+ }
};
/// Retrieves the range of the given template parameter lists.
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index d7fda35cdb87..6588a1d92dfa 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -16,6 +16,7 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -75,7 +76,10 @@ public:
/// ObjCMethodScope - This scope corresponds to an Objective-C method body.
/// It always has FnScope and DeclScope set as well.
- ObjCMethodScope = 0x400
+ ObjCMethodScope = 0x400,
+
+ /// SwitchScope - This is a scope that corresponds to a switch statement.
+ SwitchScope = 0x800
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -90,17 +94,25 @@ private:
/// interrelates with other control flow statements.
unsigned short Flags;
+ /// PrototypeDepth - This is the number of function prototype scopes
+ /// enclosing this scope, including this scope.
+ unsigned short PrototypeDepth;
+
+ /// PrototypeIndex - This is the number of parameters currently
+ /// declared in this scope.
+ unsigned short PrototypeIndex;
+
/// FnParent - If this scope has a parent scope that is a function body, this
/// pointer is non-null and points to it. This is used for label processing.
Scope *FnParent;
/// BreakParent/ContinueParent - This is a direct link to the immediately
- /// preceeding BreakParent/ContinueParent if this scope is not one, or null if
+ /// preceding BreakParent/ContinueParent if this scope is not one, or null if
/// there is no containing break/continue scope.
Scope *BreakParent, *ContinueParent;
/// ControlParent - This is a direct link to the immediately
- /// preceeding ControlParent if this scope is not one, or null if
+ /// preceding ControlParent if this scope is not one, or null if
/// there is no containing control scope.
Scope *ControlParent;
@@ -193,6 +205,19 @@ public:
Scope *getTemplateParamParent() { return TemplateParamParent; }
const Scope *getTemplateParamParent() const { return TemplateParamParent; }
+ /// Returns the number of function prototype scopes in this scope
+ /// chain.
+ unsigned getFunctionPrototypeDepth() const {
+ return PrototypeDepth;
+ }
+
+ /// Return the number of parameters declared in this function
+ /// prototype, increasing it by one for the next call.
+ unsigned getNextFunctionPrototypeIndex() {
+ assert(isFunctionPrototypeScope());
+ return PrototypeIndex++;
+ }
+
typedef DeclSetTy::iterator decl_iterator;
decl_iterator decl_begin() const { return DeclsInScope.begin(); }
decl_iterator decl_end() const { return DeclsInScope.end(); }
@@ -260,6 +285,20 @@ public:
return getFlags() & Scope::AtCatchScope;
}
+ /// isSwitchScope - Return true if this scope is a switch scope.
+ bool isSwitchScope() const {
+ for (const Scope *S = this; S; S = S->getParent()) {
+ if (S->getFlags() & Scope::SwitchScope)
+ return true;
+ else if (S->getFlags() & (Scope::FnScope | Scope::ClassScope |
+ Scope::BlockScope | Scope::TemplateParamScope |
+ Scope::FunctionPrototypeScope |
+ Scope::AtCatchScope | Scope::ObjCMethodScope))
+ return false;
+ }
+ return false;
+ }
+
typedef UsingDirectivesTy::iterator udir_iterator;
typedef UsingDirectivesTy::const_iterator const_udir_iterator;
@@ -285,36 +324,7 @@ public:
/// Init - This is used by the parser to implement scope caching.
///
- void Init(Scope *Parent, unsigned ScopeFlags) {
- AnyParent = Parent;
- Depth = AnyParent ? AnyParent->Depth+1 : 0;
- Flags = ScopeFlags;
-
- if (AnyParent) {
- FnParent = AnyParent->FnParent;
- BreakParent = AnyParent->BreakParent;
- ContinueParent = AnyParent->ContinueParent;
- ControlParent = AnyParent->ControlParent;
- BlockParent = AnyParent->BlockParent;
- TemplateParamParent = AnyParent->TemplateParamParent;
- } else {
- FnParent = BreakParent = ContinueParent = BlockParent = 0;
- ControlParent = 0;
- TemplateParamParent = 0;
- }
-
- // If this scope is a function or contains breaks/continues, remember it.
- if (Flags & FnScope) FnParent = this;
- if (Flags & BreakScope) BreakParent = this;
- if (Flags & ContinueScope) ContinueParent = this;
- if (Flags & ControlScope) ControlParent = this;
- if (Flags & BlockScope) BlockParent = this;
- if (Flags & TemplateParamScope) TemplateParamParent = this;
- DeclsInScope.clear();
- UsingDirectives.clear();
- Entity = 0;
- ErrorTrap.reset();
- }
+ void Init(Scope *parent, unsigned flags);
};
} // end namespace clang
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index a93739892cfe..07a14d2dca3b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -27,6 +27,7 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
+#include "clang/Basic/ExpressionTraits.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -43,6 +44,7 @@ namespace clang {
class ADLResult;
class ASTConsumer;
class ASTContext;
+ class ASTMutationListener;
class ArrayType;
class AttributeList;
class BlockDecl;
@@ -110,6 +112,7 @@ namespace clang {
class ObjCPropertyDecl;
class ObjCProtocolDecl;
class OverloadCandidateSet;
+ class OverloadExpr;
class ParenListExpr;
class ParmVarDecl;
class Preprocessor;
@@ -128,7 +131,9 @@ namespace clang {
class TemplatePartialOrderingContext;
class TemplateTemplateParmDecl;
class Token;
+ class TypeAliasDecl;
class TypedefDecl;
+ class TypedefNameDecl;
class TypeLoc;
class UnqualifiedId;
class UnresolvedLookupExpr;
@@ -236,6 +241,8 @@ public:
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"
+
+ bool MSStructPragmaOn; // True when #pragma ms_struct on
/// VisContext - Manages the stack for #pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
@@ -255,7 +262,7 @@ public:
/// ExtVectorDecls - This is a list all the extended vector types. This allows
/// us to associate a raw vector type with one of the ext_vector type names.
/// This is only necessary for issuing pretty diagnostics.
- llvm::SmallVector<TypedefDecl*, 24> ExtVectorDecls;
+ llvm::SmallVector<TypedefNameDecl*, 24> ExtVectorDecls;
/// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
llvm::OwningPtr<CXXFieldCollector> FieldCollector;
@@ -305,6 +312,16 @@ public:
/// and must warn if not used. Only contains the first declaration.
llvm::SmallVector<const DeclaratorDecl*, 4> UnusedFileScopedDecls;
+ /// \brief Callback to the parser to parse templated functions when needed.
+ typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD);
+ LateTemplateParserCB *LateTemplateParser;
+ void *OpaqueParser;
+
+ void SetLateTemplateParser(LateTemplateParserCB *LTP, void *P) {
+ LateTemplateParser = LTP;
+ OpaqueParser = P;
+ }
+
class DelayedDiagnostics;
class ParsingDeclState {
@@ -645,6 +662,7 @@ public:
Preprocessor &getPreprocessor() const { return PP; }
ASTContext &getASTContext() const { return Context; }
ASTConsumer &getASTConsumer() const { return Consumer; }
+ ASTMutationListener *getASTMutationListener() const;
/// \brief Helper class that creates diagnostics with optional
/// template instantiation stacks.
@@ -678,6 +696,8 @@ public:
/// \brief Build a partial diagnostic.
PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h
+ bool findMacroSpelling(SourceLocation &loc, llvm::StringRef name);
+
ExprResult Owned(Expr* E) { return E; }
ExprResult Owned(ExprResult R) { return R; }
StmtResult Owned(Stmt* S) { return S; }
@@ -755,7 +775,9 @@ public:
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc,
bool *MissingExceptionSpecification = 0,
- bool *MissingEmptyExceptionSpecification = 0);
+ bool *MissingEmptyExceptionSpecification = 0,
+ bool AllowNoexceptAllMatchWithNoSpec = false,
+ bool IsOperatorNew = false);
bool CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Superset, SourceLocation SuperLoc,
@@ -792,14 +814,117 @@ public:
Scope *S, CXXScopeSpec *SS = 0,
bool isClassName = false,
bool HasTrailingDot = false,
- ParsedType ObjectType = ParsedType());
+ ParsedType ObjectType = ParsedType(),
+ bool WantNontrivialTypeSourceInfo = false);
TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
+ bool isMicrosoftMissingTypename(const CXXScopeSpec *SS);
bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
CXXScopeSpec *SS,
ParsedType &SuggestedType);
+ /// \brief Describes the result of the name lookup and resolution performed
+ /// by \c ClassifyName().
+ enum NameClassificationKind {
+ NC_Unknown,
+ NC_Error,
+ NC_Keyword,
+ NC_Type,
+ NC_Expression,
+ NC_NestedNameSpecifier,
+ NC_TypeTemplate,
+ NC_FunctionTemplate
+ };
+
+ class NameClassification {
+ NameClassificationKind Kind;
+ ExprResult Expr;
+ TemplateName Template;
+ ParsedType Type;
+ const IdentifierInfo *Keyword;
+
+ explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
+
+ public:
+ NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {}
+
+ NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
+
+ NameClassification(const IdentifierInfo *Keyword)
+ : Kind(NC_Keyword), Keyword(Keyword) { }
+
+ static NameClassification Error() {
+ return NameClassification(NC_Error);
+ }
+
+ static NameClassification Unknown() {
+ return NameClassification(NC_Unknown);
+ }
+
+ static NameClassification NestedNameSpecifier() {
+ return NameClassification(NC_NestedNameSpecifier);
+ }
+
+ static NameClassification TypeTemplate(TemplateName Name) {
+ NameClassification Result(NC_TypeTemplate);
+ Result.Template = Name;
+ return Result;
+ }
+
+ static NameClassification FunctionTemplate(TemplateName Name) {
+ NameClassification Result(NC_FunctionTemplate);
+ Result.Template = Name;
+ return Result;
+ }
+
+ NameClassificationKind getKind() const { return Kind; }
+
+ ParsedType getType() const {
+ assert(Kind == NC_Type);
+ return Type;
+ }
+
+ ExprResult getExpression() const {
+ assert(Kind == NC_Expression);
+ return Expr;
+ }
+
+ TemplateName getTemplateName() const {
+ assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
+ return Template;
+ }
+
+ TemplateNameKind getTemplateNameKind() const {
+ assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
+ return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template;
+ }
+};
+
+ /// \brief Perform name lookup on the given name, classifying it based on
+ /// the results of name lookup and the following token.
+ ///
+ /// This routine is used by the parser to resolve identifiers and help direct
+ /// parsing. When the identifier cannot be found, this routine will attempt
+ /// to correct the typo and classify based on the resulting name.
+ ///
+ /// \param S The scope in which we're performing name lookup.
+ ///
+ /// \param SS The nested-name-specifier that precedes the name.
+ ///
+ /// \param Name The identifier. If typo correction finds an alternative name,
+ /// this pointer parameter will be updated accordingly.
+ ///
+ /// \param NameLoc The location of the identifier.
+ ///
+ /// \param NextToken The token following the identifier. Used to help
+ /// disambiguate the name.
+ NameClassification ClassifyName(Scope *S,
+ CXXScopeSpec &SS,
+ IdentifierInfo *&Name,
+ SourceLocation NameLoc,
+ const Token &NextToken);
+
Decl *ActOnDeclarator(Scope *S, Declarator &D);
Decl *HandleDeclarator(Scope *S, Declarator &D,
@@ -808,6 +933,7 @@ public:
void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
const LookupResult &Previous,
Scope *S);
+ bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info);
void DiagnoseFunctionSpecifiers(Declarator& D);
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
@@ -815,6 +941,8 @@ public:
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
+ NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D,
+ LookupResult &Previous, bool &Redeclaration);
NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
@@ -840,12 +968,10 @@ public:
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
QualType T);
- ParmVarDecl *CheckParameter(DeclContext *DC,
- TypeSourceInfo *TSInfo, QualType T,
- IdentifierInfo *Name,
- SourceLocation NameLoc,
- StorageClass SC,
- StorageClass SCAsWritten);
+ ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation NameLoc, IdentifierInfo *Name,
+ QualType T, TypeSourceInfo *TSInfo,
+ StorageClass SC, StorageClass SCAsWritten);
void ActOnParamDefaultArgument(Decl *param,
SourceLocation EqualLoc,
Expr *defarg);
@@ -860,6 +986,7 @@ public:
bool TypeMayContainAuto);
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
void ActOnInitializerError(Decl *Dcl);
+ void ActOnCXXForRangeDecl(Decl *D);
void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
void FinalizeDeclaration(Decl *D);
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
@@ -869,6 +996,7 @@ public:
bool TypeMayContainAuto = true);
void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls);
+ void CheckForFunctionRedefinition(FunctionDecl *FD);
Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D);
void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);
@@ -890,7 +1018,9 @@ public:
NamedDecl *D);
void DiagnoseInvalidJumps(Stmt *Body);
- Decl *ActOnFileScopeAsmDecl(SourceLocation Loc, Expr *expr);
+ Decl *ActOnFileScopeAsmDecl(Expr *expr,
+ SourceLocation AsmLoc,
+ SourceLocation RParenLoc);
/// Scope actions.
void ActOnPopScope(SourceLocation Loc, Scope *S);
@@ -994,7 +1124,7 @@ public:
/// C++ record definition's base-specifiers clause and are starting its
/// member declarations.
void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl,
- ClassVirtSpecifiers &CVS,
+ SourceLocation FinalLoc,
SourceLocation LBraceLoc);
/// ActOnTagFinishDefinition - Invoked once we have finished parsing
@@ -1055,7 +1185,12 @@ public:
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
- bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0);
+ ///
+ /// \param ExplicitInstantiationOrSpecialization When true, we are checking
+ /// whether the declaration is in scope for the purposes of explicit template
+ /// instantiation or specialization. The default is false.
+ bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0,
+ bool ExplicitInstantiationOrSpecialization = false);
/// Finds the scope corresponding to the given decl context, if it
/// happens to be an enclosing scope. Otherwise return NULL.
@@ -1064,11 +1199,13 @@ public:
/// Subroutines of ActOnDeclarator().
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
TypeSourceInfo *TInfo);
- void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls);
+ void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);
bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
- void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
+ void mergeObjCMethodDecls(ObjCMethodDecl *New, const ObjCMethodDecl *Old);
void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
+ void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
+ void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
// AssignmentAction - This is used by all the assignment diagnostic functions
@@ -1149,13 +1286,13 @@ public:
ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
ExprResult Init);
- bool PerformObjectArgumentInitialization(Expr *&From,
- NestedNameSpecifier *Qualifier,
- NamedDecl *FoundDecl,
- CXXMethodDecl *Method);
+ ExprResult PerformObjectArgumentInitialization(Expr *From,
+ NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
+ CXXMethodDecl *Method);
- bool PerformContextuallyConvertToBool(Expr *&From);
- bool PerformContextuallyConvertToObjCId(Expr *&From);
+ ExprResult PerformContextuallyConvertToBool(Expr *From);
+ ExprResult PerformContextuallyConvertToObjCId(Expr *From);
ExprResult
ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE,
@@ -1167,10 +1304,10 @@ public:
const PartialDiagnostic &AmbigNote,
const PartialDiagnostic &ConvDiag);
- bool PerformObjectMemberConversion(Expr *&From,
- NestedNameSpecifier *Qualifier,
- NamedDecl *FoundDecl,
- NamedDecl *Member);
+ ExprResult PerformObjectMemberConversion(Expr *From,
+ NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
+ NamedDecl *Member);
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
// TODO: make this is a typesafe union.
@@ -1208,7 +1345,7 @@ public:
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
@@ -1216,7 +1353,7 @@ public:
bool SuppressUserConversions = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
@@ -1253,9 +1390,10 @@ public:
void AddArgumentDependentLookupCandidates(DeclarationName Name,
bool Operator,
Expr **Args, unsigned NumArgs,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
- bool PartialOverloading = false);
+ bool PartialOverloading = false,
+ bool StdNamespaceIsAssociated = false);
// Emit as a 'note' the specific overload candidate
void NoteOverloadCandidate(FunctionDecl *Fn);
@@ -1276,10 +1414,18 @@ public:
bool Complain,
DeclAccessPair &Found);
- FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From,
+ FunctionDecl *ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
bool Complain = false,
DeclAccessPair* Found = 0);
+ ExprResult ResolveAndFixSingleFunctionTemplateSpecialization(
+ Expr *SrcExpr, bool DoFunctionPointerConverion = false,
+ bool Complain = false,
+ const SourceRange& OpRangeForComplaining = SourceRange(),
+ QualType DestTypeForComplaining = QualType(),
+ unsigned DiagIDForComplaining = 0);
+
+
Expr *FixOverloadedFunctionReference(Expr *E,
DeclAccessPair FoundDecl,
FunctionDecl *Fn);
@@ -1444,15 +1590,16 @@ public:
QualType T1, QualType T2,
UnresolvedSetImpl &Functions);
- LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
- bool isLocalLabel = false);
-
+ LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc,
+ SourceLocation GnuLabelLoc = SourceLocation());
+
DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class);
CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- ADLResult &Functions);
+ ADLResult &Functions,
+ bool StdNamespaceIsAssociated = false);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
@@ -1695,6 +1842,7 @@ public:
/// initialization.
void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
+
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
public:
@@ -1734,7 +1882,7 @@ public:
StmtResult ActOnExprStmt(FullExprArg Expr);
StmtResult ActOnNullStmt(SourceLocation SemiLoc,
- bool LeadingEmptyMacro = false);
+ SourceLocation LeadingEmptyMacroLoc = SourceLocation());
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg Elts,
bool isStmtExpr);
@@ -1782,6 +1930,17 @@ public:
SourceLocation LParenLoc,
Stmt *First, Expr *Second,
SourceLocation RParenLoc, Stmt *Body);
+ StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc, Stmt *LoopVar,
+ SourceLocation ColonLoc, Expr *Collection,
+ SourceLocation RParenLoc);
+ StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
+ SourceLocation ColonLoc,
+ Stmt *RangeDecl, Stmt *BeginEndDecl,
+ Expr *Cond, Expr *Inc,
+ Stmt *LoopVarDecl,
+ SourceLocation RParenLoc);
+ StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body);
StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc,
@@ -1811,7 +1970,8 @@ public:
VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
- IdentifierInfo *Name, SourceLocation NameLoc,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
bool Invalid = false);
Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D);
@@ -1831,16 +1991,29 @@ public:
Expr *SynchExpr,
Stmt *SynchBody);
- VarDecl *BuildExceptionDeclaration(Scope *S,
- TypeSourceInfo *TInfo,
- IdentifierInfo *Name,
- SourceLocation Loc);
+ VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id);
Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D);
StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
Decl *ExDecl, Stmt *HandlerBlock);
StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
MultiStmtArg Handlers);
+
+ StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ?
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler);
+
+ StmtResult ActOnSEHExceptBlock(SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block);
+
+ StmtResult ActOnSEHFinallyBlock(SourceLocation Loc,
+ Stmt *Block);
+
void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const;
@@ -1870,7 +2043,8 @@ public:
}
void EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message,
- SourceLocation Loc, bool UnknownObjCClass=false);
+ SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass=0);
void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
@@ -1878,7 +2052,8 @@ public:
// Expression Parsing Callbacks: SemaExpr.cpp.
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
- bool UnknownObjCClass=false);
+ const ObjCInterfaceDecl *UnknownObjCClass=0);
+ std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD);
bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
ObjCMethodDecl *Getter,
SourceLocation Loc);
@@ -1906,6 +2081,10 @@ public:
// Primary Expressions.
SourceRange getExprRange(Expr *E) const;
+ ObjCIvarDecl *SynthesizeProvisionalIvar(LookupResult &Lookup,
+ IdentifierInfo *II,
+ SourceLocation NameLoc);
+
ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name,
bool HasTrailingLParen, bool IsAddressOfOperand);
@@ -1971,6 +2150,20 @@ public:
/// fragments (e.g. "foo" "bar" L"baz").
ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks);
+ ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ MultiTypeArg Types,
+ MultiExprArg Exprs);
+ ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ TypeSourceInfo **Types,
+ Expr **Exprs,
+ unsigned NumAssocs);
+
// Binary/Unary Operators. 'Tok' is the token for the operator.
ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Expr *InputArg);
@@ -1979,19 +2172,25 @@ public:
ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, Expr *Input);
- ExprResult CreateSizeOfAlignOfExpr(TypeSourceInfo *T,
- SourceLocation OpLoc,
- bool isSizeOf, SourceRange R);
- ExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
- bool isSizeOf, SourceRange R);
+ ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *T,
+ SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ SourceRange R);
+ ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ SourceRange R);
ExprResult
- ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
- void *TyOrEx, const SourceRange &ArgRange);
+ ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ bool isType, void *TyOrEx,
+ const SourceRange &ArgRange);
- ExprResult CheckPlaceholderExpr(Expr *E, SourceLocation Loc);
+ ExprResult CheckPlaceholderExpr(Expr *E);
+ bool CheckVecStepExpr(Expr *E, SourceLocation OpLoc, SourceRange R);
- bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
- SourceRange R, bool isSizeof);
+ bool CheckUnaryExprOrTypeTraitOperand(QualType type, SourceLocation OpLoc,
+ SourceRange R,
+ UnaryExprOrTypeTrait ExprKind);
ExprResult ActOnSizeofParameterPackExpr(Scope *S,
SourceLocation OpLoc,
IdentifierInfo &Name,
@@ -2020,7 +2219,7 @@ public:
const TemplateArgumentListInfo *TemplateArgs,
bool SuppressQualifierCheck = false);
- ExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
+ ExprResult LookupMemberExpr(LookupResult &R, ExprResult &Base,
bool &IsArrow, SourceLocation OpLoc,
CXXScopeSpec &SS,
Decl *ObjCImpDecl,
@@ -2163,6 +2362,8 @@ public:
// __null
ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc);
+ bool CheckCaseExpression(Expr *expr);
+
//===------------------------- "Block" Extension ------------------------===//
/// ActOnBlockStart - This callback is invoked when a block literal is
@@ -2186,6 +2387,7 @@ public:
// Act on C++ namespaces
Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc,
+ SourceLocation NamespaceLoc,
SourceLocation IdentLoc,
IdentifierInfo *Ident,
SourceLocation LBrace,
@@ -2250,6 +2452,11 @@ public:
AttributeList *AttrList,
bool IsTypeName,
SourceLocation TypenameLoc);
+ Decl *ActOnAliasDeclaration(Scope *CurScope,
+ AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ UnqualifiedId &Name,
+ TypeResult Type);
/// AddCXXDirectInitializerToDecl - This action is called immediately after
/// ActOnDeclarator, when a C++ direct initializer is present.
@@ -2444,7 +2651,7 @@ public:
//// ActOnCXXThrow - Parse throw expressions.
ExprResult ActOnCXXThrow(SourceLocation OpLoc, Expr *expr);
- bool CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E);
+ ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E);
/// ActOnCXXTypeConstructExpr - Parse construction of a specified type.
/// Can be interpreted either as function-style casting ("int(x)")
@@ -2542,6 +2749,32 @@ public:
TypeSourceInfo *RhsT,
SourceLocation RParen);
+ /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support
+ /// pseudo-functions.
+ ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT,
+ SourceLocation KWLoc,
+ ParsedType LhsTy,
+ Expr *DimExpr,
+ SourceLocation RParen);
+
+ ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT,
+ SourceLocation KWLoc,
+ TypeSourceInfo *TSInfo,
+ Expr *DimExpr,
+ SourceLocation RParen);
+
+ /// ActOnExpressionTrait - Parsed one of the unary type trait support
+ /// pseudo-functions.
+ ExprResult ActOnExpressionTrait(ExpressionTrait OET,
+ SourceLocation KWLoc,
+ Expr *Queried,
+ SourceLocation RParen);
+
+ ExprResult BuildExpressionTrait(ExpressionTrait OET,
+ SourceLocation KWLoc,
+ Expr *Queried,
+ SourceLocation RParen);
+
ExprResult ActOnStartCXXMemberReference(Scope *S,
Expr *Base,
SourceLocation OpLoc,
@@ -2659,25 +2892,41 @@ public:
ParsedType ObjectType,
bool EnteringContext);
- /// \brief The parser has parsed a nested-name-specifier 'type::'.
+ /// \brief The parser has parsed a nested-name-specifier
+ /// 'template[opt] template-name < template-args >::'.
///
/// \param S The scope in which this nested-name-specifier occurs.
///
- /// \param Type The type, which will be a template specialization
- /// type, preceding the '::'.
- ///
- /// \param CCLoc The location of the '::'.
+ /// \param TemplateLoc The location of the 'template' keyword, if any.
///
/// \param SS The nested-name-specifier, which is both an input
/// parameter (the nested-name-specifier before this type) and an
/// output parameter (containing the full nested-name-specifier,
/// including this new type).
+ ///
+ /// \param TemplateLoc the location of the 'template' keyword, if any.
+ /// \param TemplateName The template name.
+ /// \param TemplateNameLoc The location of the template name.
+ /// \param LAngleLoc The location of the opening angle bracket ('<').
+ /// \param TemplateArgs The template arguments.
+ /// \param RAngleLoc The location of the closing angle bracket ('>').
+ /// \param CCLoc The location of the '::'.
+
+ /// \param EnteringContext Whether we're entering the context of the
+ /// nested-name-specifier.
+ ///
///
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXNestedNameSpecifier(Scope *S,
- ParsedType Type,
+ SourceLocation TemplateLoc,
+ CXXScopeSpec &SS,
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation RAngleLoc,
SourceLocation CCLoc,
- CXXScopeSpec &SS);
+ bool EnteringContext);
/// \brief Given a C++ nested-name-specifier, produce an annotation value
/// that the parser can use later to reconstruct the given
@@ -2818,10 +3067,13 @@ public:
MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo,
Expr **Args, unsigned NumArgs,
+ SourceLocation BaseLoc,
SourceLocation RParenLoc,
SourceLocation LParenLoc,
- CXXRecordDecl *ClassDecl,
- SourceLocation EllipsisLoc);
+ CXXRecordDecl *ClassDecl);
+
+ bool SetDelegatingInitializer(CXXConstructorDecl *Constructor,
+ CXXCtorInitializer *Initializer);
bool SetCtorInitializers(CXXConstructorDecl *Constructor,
CXXCtorInitializer **Initializers,
@@ -2887,15 +3139,19 @@ public:
AttributeList *AttrList);
void ActOnReenterTemplateScope(Scope *S, Decl *Template);
+ void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D);
void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record);
void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param);
void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record);
+ void MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag = true);
+ bool IsInsideALocalClassWithinATemplateFunction();
- Decl *ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
- Expr *AssertMessageExpr);
+ Expr *AssertMessageExpr,
+ SourceLocation RParenLoc);
FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc,
TypeSourceInfo *TSInfo);
@@ -3071,18 +3327,21 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
+ void FilterAcceptableTemplateNames(LookupResult &R);
+ bool hasAnyAcceptableTemplateNames(LookupResult &R);
+
void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext,
bool &MemberOfUnknownSpecialization);
TemplateNameKind isTemplateName(Scope *S,
- CXXScopeSpec &SS,
- bool hasTemplateKeyword,
- UnqualifiedId &Name,
- ParsedType ObjectType,
- bool EnteringContext,
- TemplateTy &Template,
- bool &MemberOfUnknownSpecialization);
+ CXXScopeSpec &SS,
+ bool hasTemplateKeyword,
+ UnqualifiedId &Name,
+ ParsedType ObjectType,
+ bool EnteringContext,
+ TemplateTy &Template,
+ bool &MemberOfUnknownSpecialization);
bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
@@ -3155,27 +3414,41 @@ public:
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
- AccessSpecifier AS);
+ AccessSpecifier AS,
+ unsigned NumOuterTemplateParamLists,
+ TemplateParameterList **OuterTemplateParamLists);
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
TemplateArgumentListInfo &Out);
+ void NoteAllFoundTemplates(TemplateName Name);
+
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
- const TemplateArgumentListInfo &TemplateArgs);
+ TemplateArgumentListInfo &TemplateArgs);
TypeResult
- ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc,
+ ActOnTemplateIdType(CXXScopeSpec &SS,
+ TemplateTy Template, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation RAngleLoc);
- TypeResult ActOnTagTemplateIdType(CXXScopeSpec &SS,
- TypeResult Type,
- TagUseKind TUK,
+ /// \brief Parsed an elaborated-type-specifier that refers to a template-id,
+ /// such as \c class T::template apply<U>.
+ ///
+ /// \param TUK
+ TypeResult ActOnTagTemplateIdType(TagUseKind TUK,
TypeSpecifierType TagSpec,
- SourceLocation TagLoc);
+ SourceLocation TagLoc,
+ CXXScopeSpec &SS,
+ TemplateTy TemplateD,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation RAngleLoc);
+
ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
LookupResult &R,
bool RequiresADL,
@@ -3225,7 +3498,7 @@ public:
LookupResult &Previous);
bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
@@ -3291,9 +3564,30 @@ public:
llvm::SmallVectorImpl<TemplateArgument> &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
+ /// \brief Check that the given template arguments can be be provided to
+ /// the given template, converting the arguments along the way.
+ ///
+ /// \param Template The template to which the template arguments are being
+ /// provided.
+ ///
+ /// \param TemplateLoc The location of the template name in the source.
+ ///
+ /// \param TemplateArgs The list of template arguments. If the template is
+ /// a template template parameter, this function may extend the set of
+ /// template arguments to also include substituted, defaulted template
+ /// arguments.
+ ///
+ /// \param PartialTemplateArgs True if the list of template arguments is
+ /// intentionally partial, e.g., because we're checking just the initial
+ /// set of template arguments.
+ ///
+ /// \param Converted Will receive the converted, canonicalized template
+ /// arguments.
+ ///
+ /// \returns True if an error occurred, false otherwise.
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
- const TemplateArgumentListInfo &TemplateArgs,
+ TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
llvm::SmallVectorImpl<TemplateArgument> &Converted);
@@ -3305,10 +3599,10 @@ public:
TypeSourceInfo *Arg);
bool CheckTemplateArgumentPointerToMember(Expr *Arg,
TemplateArgument &Converted);
- bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgument &Converted,
- CheckTemplateArgumentKind CTAK = CTAK_Specified);
+ ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ QualType InstantiatedParamType, Expr *Arg,
+ TemplateArgument &Converted,
+ CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg);
@@ -3384,17 +3678,25 @@ public:
/// \param TypenameLoc the location of the 'typename' keyword
/// \param SS the nested-name-specifier following the typename (e.g., 'T::').
/// \param TemplateLoc the location of the 'template' keyword, if any.
- /// \param Ty the type that the typename specifier refers to.
+ /// \param TemplateName The template name.
+ /// \param TemplateNameLoc The location of the template name.
+ /// \param LAngleLoc The location of the opening angle bracket ('<').
+ /// \param TemplateArgs The template arguments.
+ /// \param RAngleLoc The location of the closing angle bracket ('>').
TypeResult
ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS, SourceLocation TemplateLoc,
- ParsedType Ty);
+ const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc,
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation RAngleLoc);
QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
- const IdentifierInfo &II,
SourceLocation KeywordLoc,
- SourceRange NNSRange,
+ NestedNameSpecifierLoc QualifierLoc,
+ const IdentifierInfo &II,
SourceLocation IILoc);
TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
@@ -3480,7 +3782,7 @@ public:
/// \param T The type that is being checked for unexpanded parameter
/// packs.
///
- /// \returns true if an error ocurred, false otherwise.
+ /// \returns true if an error occurred, false otherwise.
bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T,
UnexpandedParameterPackContext UPPC);
@@ -3490,7 +3792,7 @@ public:
/// \param E The expression that is being checked for unexpanded
/// parameter packs.
///
- /// \returns true if an error ocurred, false otherwise.
+ /// \returns true if an error occurred, false otherwise.
bool DiagnoseUnexpandedParameterPack(Expr *E,
UnexpandedParameterPackContext UPPC = UPPC_Expression);
@@ -3500,7 +3802,7 @@ public:
/// \param SS The nested-name-specifier that is being checked for
/// unexpanded parameter packs.
///
- /// \returns true if an error ocurred, false otherwise.
+ /// \returns true if an error occurred, false otherwise.
bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
UnexpandedParameterPackContext UPPC);
@@ -3510,7 +3812,7 @@ public:
/// \param NameInfo The name (with source location information) that
/// is being checked for unexpanded parameter packs.
///
- /// \returns true if an error ocurred, false otherwise.
+ /// \returns true if an error occurred, false otherwise.
bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
UnexpandedParameterPackContext UPPC);
@@ -3522,7 +3824,7 @@ public:
/// \param Template The template name that is being checked for unexpanded
/// parameter packs.
///
- /// \returns true if an error ocurred, false otherwise.
+ /// \returns true if an error occurred, false otherwise.
bool DiagnoseUnexpandedParameterPack(SourceLocation Loc,
TemplateName Template,
UnexpandedParameterPackContext UPPC);
@@ -3533,7 +3835,7 @@ public:
/// \param Arg The template argument that is being checked for unexpanded
/// parameter packs.
///
- /// \returns true if an error ocurred, false otherwise.
+ /// \returns true if an error occurred, false otherwise.
bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
UnexpandedParameterPackContext UPPC);
@@ -3751,7 +4053,7 @@ public:
TemplateDeductionResult
SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo &ExplicitTemplateArgs,
+ TemplateArgumentListInfo &ExplicitTemplateArgs,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
@@ -3766,14 +4068,14 @@ public:
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
@@ -3786,11 +4088,12 @@ public:
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
- bool DeduceAutoType(QualType AutoType, Expr *Initializer, QualType &Result);
+ bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *Initializer,
+ TypeSourceInfo *&Result);
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
@@ -4204,7 +4507,7 @@ public:
/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
- void PerformPendingInstantiations(bool LocalOnly = false);
+ bool PerformPendingInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -4224,6 +4527,7 @@ public:
DeclarationName Entity);
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
+ int indexAdjustment,
llvm::Optional<unsigned> NumExpansions);
bool SubstParmTypes(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
@@ -4289,11 +4593,6 @@ public:
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK);
- NestedNameSpecifier *
- SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
- SourceRange Range,
- const MultiLevelTemplateArgumentList &TemplateArgs);
-
NestedNameSpecifierLoc
SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -4302,7 +4601,8 @@ public:
SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
const MultiLevelTemplateArgumentList &TemplateArgs);
TemplateName
- SubstTemplateName(TemplateName Name, SourceLocation Loc,
+ SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name,
+ SourceLocation Loc,
const MultiLevelTemplateArgumentList &TemplateArgs);
bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs,
TemplateArgumentListInfo &Result,
@@ -4475,7 +4775,7 @@ public:
ObjCArgInfo *ArgInfo,
DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args
AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind,
- bool isVariadic = false);
+ bool isVariadic, bool MethodDefinition);
// Helper method for ActOnClassMethod/ActOnInstanceMethod.
// Will search "local" class/category implementations for a method decl.
@@ -4485,6 +4785,9 @@ public:
ObjCInterfaceDecl *CDecl);
ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl);
+ ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel,
+ const ObjCObjectPointerType *OPT,
+ bool IsInstance);
ExprResult
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
@@ -4586,6 +4889,11 @@ public:
PPK_Pop // #pragma pack(pop, [identifier], [n])
};
+ enum PragmaMSStructKind {
+ PMSST_OFF, // #pragms ms_struct off
+ PMSST_ON // #pragms ms_struct on
+ };
+
/// ActOnPragmaPack - Called on well formed #pragma pack(...).
void ActOnPragmaPack(PragmaPackKind Kind,
IdentifierInfo *Name,
@@ -4593,6 +4901,9 @@ public:
SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
+
+ /// ActOnPragmaMSStruct - Called on well formed #pragms ms_struct [on|off].
+ void ActOnPragmaMSStruct(PragmaMSStructKind Kind);
/// ActOnPragmaUnused - Called on well-formed '#pragma unused'.
void ActOnPragmaUnused(const Token &Identifier,
@@ -4626,6 +4937,9 @@ public:
/// a the record decl, to handle '#pragma pack' and '#pragma options align'.
void AddAlignmentAttributesForRecord(RecordDecl *RD);
+ /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record.
+ void AddMsStructLayoutForRecord(RecordDecl *RD);
+
/// FreePackedContext - Deallocate and null out PackContext.
void FreePackedContext();
@@ -4655,38 +4969,42 @@ public:
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
/// cast. If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
- void ImpCastExprToType(Expr *&Expr, QualType Type, CastKind CK,
- ExprValueKind VK = VK_RValue,
- const CXXCastPath *BasePath = 0);
+ ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK,
+ ExprValueKind VK = VK_RValue,
+ const CXXCastPath *BasePath = 0);
+
+ /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
+ /// to the conversion from scalar type ScalarTy to the Boolean type.
+ static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy);
/// IgnoredValueConversions - Given that an expression's result is
/// syntactically ignored, perform any conversions that are
/// required.
- void IgnoredValueConversions(Expr *&expr);
+ ExprResult IgnoredValueConversions(Expr *E);
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
// functions and arrays to their respective pointers (C99 6.3.2.1).
- Expr *UsualUnaryConversions(Expr *&expr);
+ ExprResult UsualUnaryConversions(Expr *E);
// DefaultFunctionArrayConversion - converts functions and arrays
// to their respective pointers (C99 6.3.2.1).
- void DefaultFunctionArrayConversion(Expr *&expr);
+ ExprResult DefaultFunctionArrayConversion(Expr *E);
// DefaultFunctionArrayLvalueConversion - converts functions and
// arrays to their respective pointers and performs the
// lvalue-to-rvalue conversion.
- void DefaultFunctionArrayLvalueConversion(Expr *&expr);
+ ExprResult DefaultFunctionArrayLvalueConversion(Expr *E);
// DefaultLvalueConversion - performs lvalue-to-rvalue conversion on
// the operand. This is DefaultFunctionArrayLvalueConversion,
// except that it assumes the operand isn't of function or array
// type.
- void DefaultLvalueConversion(Expr *&expr);
+ ExprResult DefaultLvalueConversion(Expr *E);
// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
// do not have a prototype. Integer promotions are performed on each
// argument, and arguments that have type float are promoted to double.
- void DefaultArgumentPromotion(Expr *&Expr);
+ ExprResult DefaultArgumentPromotion(Expr *E);
// Used for emitting the right warning by DefaultVariadicArgumentPromotion
enum VariadicCallType {
@@ -4709,15 +5027,15 @@ public:
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
// will warn if the resulting type is not a POD type.
- bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
- FunctionDecl *FDecl);
+ ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
+ FunctionDecl *FDecl);
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
// operands and then handles various conversions that are common to binary
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this
// routine returns the first non-arithmetic type found. The client is
// responsible for emitting appropriate error diagnostics.
- QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr,
+ QualType UsualArithmeticConversions(ExprResult &lExpr, ExprResult &rExpr,
bool isCompAssign = false);
/// AssignConvertType - All of the 'assignment' semantic checks return this
@@ -4805,94 +5123,102 @@ public:
/// Check assignment constraints and prepare for a conversion of the
/// RHS to the LHS type.
- AssignConvertType CheckAssignmentConstraints(QualType lhs, Expr *&rhs,
+ AssignConvertType CheckAssignmentConstraints(QualType lhs, ExprResult &rhs,
CastKind &Kind);
// CheckSingleAssignmentConstraints - Currently used by
// CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
// this routine performs the default function/array converions.
AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
- Expr *&rExpr);
+ ExprResult &rExprRes);
// \brief If the lhs type is a transparent union, check whether we
// can initialize the transparent union with the given expression.
AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs,
- Expr *&rExpr);
+ ExprResult &rExpr);
bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType);
- bool PerformImplicitConversion(Expr *&From, QualType ToType,
- AssignmentAction Action,
- bool AllowExplicit = false);
- bool PerformImplicitConversion(Expr *&From, QualType ToType,
- AssignmentAction Action,
- bool AllowExplicit,
- ImplicitConversionSequence& ICS);
- bool PerformImplicitConversion(Expr *&From, QualType ToType,
- const ImplicitConversionSequence& ICS,
- AssignmentAction Action,
- bool CStyle = false);
- bool PerformImplicitConversion(Expr *&From, QualType ToType,
- const StandardConversionSequence& SCS,
- AssignmentAction Action,
- bool CStyle);
+ ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
+ AssignmentAction Action,
+ bool AllowExplicit = false);
+ ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
+ AssignmentAction Action,
+ bool AllowExplicit,
+ ImplicitConversionSequence& ICS);
+ ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
+ const ImplicitConversionSequence& ICS,
+ AssignmentAction Action,
+ bool CStyle = false);
+ ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
+ const StandardConversionSequence& SCS,
+ AssignmentAction Action,
+ bool CStyle);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).
/// type checking binary operators (subroutines of CreateBuiltinBinOp).
- QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+ QualType InvalidOperands(SourceLocation l, ExprResult &lex, ExprResult &rex);
QualType CheckPointerToMemberOperands( // C++ 5.5
- Expr *&lex, Expr *&rex, ExprValueKind &VK,
+ ExprResult &lex, ExprResult &rex, ExprValueKind &VK,
SourceLocation OpLoc, bool isIndirect);
QualType CheckMultiplyDivideOperands( // C99 6.5.5
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign,
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, bool isCompAssign,
bool isDivide);
QualType CheckRemainderOperands( // C99 6.5.5
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, bool isCompAssign = false);
QualType CheckAdditionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
QualType CheckSubtractionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, QualType* CompLHSTy = 0);
QualType CheckShiftOperands( // C99 6.5.7
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc,
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, unsigned Opc,
bool isCompAssign = false);
QualType CheckCompareOperands( // C99 6.5.8/9
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc,
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, unsigned Opc,
bool isRelational);
QualType CheckBitwiseOperands( // C99 6.5.[10...12]
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, bool isCompAssign = false);
QualType CheckLogicalOperands( // C99 6.5.[13,14]
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc);
+ ExprResult &lex, ExprResult &rex, SourceLocation OpLoc, unsigned Opc);
// CheckAssignmentOperands is used for both simple and compound assignment.
// For simple assignment, pass both expressions and a null converted type.
// For compound assignment, pass both expressions and the converted type.
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
- Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType);
+ Expr *lex, ExprResult &rex, SourceLocation OpLoc, QualType convertedType);
- void ConvertPropertyForRValue(Expr *&E);
- void ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType& LHSTy);
+ void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType& LHSTy);
+ ExprResult ConvertPropertyForRValue(Expr *E);
QualType CheckConditionalOperands( // C99 6.5.15
- Expr *&cond, Expr *&lhs, Expr *&rhs,
+ ExprResult &cond, ExprResult &lhs, ExprResult &rhs,
ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
QualType CXXCheckConditionalOperands( // C++ 5.16
- Expr *&cond, Expr *&lhs, Expr *&rhs,
+ ExprResult &cond, ExprResult &lhs, ExprResult &rhs,
ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
bool *NonStandardCompositeType = 0);
+ QualType FindCompositePointerType(SourceLocation Loc, ExprResult &E1, ExprResult &E2,
+ bool *NonStandardCompositeType = 0) {
+ Expr *E1Tmp = E1.take(), *E2Tmp = E2.take();
+ QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, NonStandardCompositeType);
+ E1 = Owned(E1Tmp);
+ E2 = Owned(E2Tmp);
+ return Composite;
+ }
- QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
+ QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
SourceLocation questionLoc);
bool DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
SourceLocation QuestionLoc);
/// type checking for vector binary operators.
- QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
- QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
+ QualType CheckVectorOperands(SourceLocation l, ExprResult &lex, ExprResult &rex);
+ QualType CheckVectorCompareOperands(ExprResult &lex, ExprResult &rx,
SourceLocation l, bool isRel);
/// type checking declaration initializers (C99 6.7.8)
@@ -4930,9 +5256,13 @@ public:
/// CheckCastTypes - Check type constraints for casting between types under
/// C semantics, or forward to CXXCheckCStyleCast in C++.
- bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr,
- CastKind &Kind, ExprValueKind &VK, CXXCastPath &BasePath,
- bool FunctionalStyle = false);
+ ExprResult CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *CastExpr,
+ CastKind &Kind, ExprValueKind &VK, CXXCastPath &BasePath,
+ bool FunctionalStyle = false);
+
+ ExprResult checkUnknownAnyCast(SourceRange TyRange, QualType castType,
+ Expr *castExpr, CastKind &castKind,
+ ExprValueKind &valueKind, CXXCastPath &BasePath);
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
@@ -4945,15 +5275,15 @@ public:
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size,
// or vectors and the element type of that vector.
- // returns true if the cast is invalid
- bool CheckExtVectorCast(SourceRange R, QualType VectorTy, Expr *&CastExpr,
- CastKind &Kind);
+ // returns the cast expr
+ ExprResult CheckExtVectorCast(SourceRange R, QualType VectorTy, Expr *CastExpr,
+ CastKind &Kind);
/// CXXCheckCStyleCast - Check constraints of a C-style or function-style
/// cast under C++ semantics.
- bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
- Expr *&CastExpr, CastKind &Kind,
- CXXCastPath &BasePath, bool FunctionalStyle);
+ ExprResult CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
+ Expr *CastExpr, CastKind &Kind,
+ CXXCastPath &BasePath, bool FunctionalStyle);
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.
@@ -4972,7 +5302,7 @@ public:
/// \param Loc - A location associated with the condition, e.g. the
/// 'if' keyword.
/// \return true iff there were any errors
- bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc);
+ ExprResult CheckBooleanCondition(Expr *CondExpr, SourceLocation Loc);
ExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc,
Expr *SubExpr);
@@ -4986,7 +5316,7 @@ public:
void DiagnoseEqualityWithExtraParens(ParenExpr *parenE);
/// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid.
- bool CheckCXXBooleanCondition(Expr *&CondExpr);
+ ExprResult CheckCXXBooleanCondition(Expr *CondExpr);
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
/// the specified width and sign. If an overflow occurs, detect it and emit
@@ -5174,7 +5504,7 @@ public:
unsigned ByteNo) const;
private:
- void CheckArrayAccess(const ArraySubscriptExpr *E);
+ void CheckArrayAccess(const Expr *E);
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
@@ -5210,12 +5540,15 @@ private:
bool isPrintf);
void CheckNonNullArguments(const NonNullAttr *NonNull,
- const CallExpr *TheCall);
+ const Expr * const *ExprArgs,
+ SourceLocation CallSiteLoc);
void CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
bool isPrintf);
+ void CheckMemsetArguments(const CallExpr *Call);
+
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
index ae5aa33db766..83c0999ad49c 100644
--- a/include/clang/Sema/SemaDiagnostic.h
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -15,7 +15,8 @@
namespace clang {
namespace diag {
enum {
-#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) ENUM,
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) ENUM,
#define SEMASTART
#include "clang/Basic/DiagnosticSemaKinds.inc"
#undef DIAG
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 53f4a9d8c8fa..4d97f9bef802 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -335,7 +335,9 @@ namespace clang {
Decl *VisitLabelDecl(LabelDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 7cc35713aace..c66697963e0d 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -56,7 +56,7 @@ public:
}
/// \brief Returns the location at which template argument is
- /// occuring.
+ /// occurring.
SourceLocation getLocation() const {
return Loc;
}
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 68fd91d4c069..1cfd458a3864 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -490,7 +490,11 @@ namespace clang {
/// \brief The ObjC 'Class' type.
PREDEF_TYPE_OBJC_CLASS = 27,
/// \brief The ObjC 'SEL' type.
- PREDEF_TYPE_OBJC_SEL = 28
+ PREDEF_TYPE_OBJC_SEL = 28,
+ /// \brief The 'unknown any' placeholder type.
+ PREDEF_TYPE_UNKNOWN_ANY = 29,
+ /// \brief The placeholder type for bound member functions.
+ PREDEF_TYPE_BOUND_MEMBER = 30
};
/// \brief The number of predefined type IDs that are reserved for
@@ -622,7 +626,11 @@ namespace clang {
/// \brief NSConstantString type
SPECIAL_TYPE_NS_CONSTANT_STRING = 15,
/// \brief Whether __[u]int128_t identifier is installed.
- SPECIAL_TYPE_INT128_INSTALLED = 16
+ SPECIAL_TYPE_INT128_INSTALLED = 16,
+ /// \brief Cached "auto" deduction type.
+ SPECIAL_TYPE_AUTO_DEDUCT = 17,
+ /// \brief Cached "auto &&" deduction type.
+ SPECIAL_TYPE_AUTO_RREF_DEDUCT = 18
};
/// \brief Record codes for each kind of declaration.
@@ -636,6 +644,8 @@ namespace clang {
DECL_TRANSLATION_UNIT = 50,
/// \brief A TypedefDecl record.
DECL_TYPEDEF,
+ /// \brief A TypeAliasDecl record.
+ DECL_TYPEALIAS,
/// \brief An EnumDecl record.
DECL_ENUM,
/// \brief A RecordDecl record.
@@ -872,6 +882,8 @@ namespace clang {
EXPR_BLOCK,
/// \brief A BlockDeclRef record.
EXPR_BLOCK_DECL_REF,
+ /// \brief A GenericSelectionExpr record.
+ EXPR_GENERIC_SELECTION,
// Objective-C
@@ -913,6 +925,8 @@ namespace clang {
STMT_CXX_CATCH,
/// \brief A CXXTryStmt record.
STMT_CXX_TRY,
+ /// \brief A CXXForRangeStmt record.
+ STMT_CXX_FOR_RANGE,
/// \brief A CXXOperatorCallExpr record.
EXPR_CXX_OPERATOR_CALL,
@@ -958,11 +972,13 @@ namespace clang {
EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr
EXPR_CXX_UNARY_TYPE_TRAIT, // UnaryTypeTraitExpr
+ EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr
EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr
EXPR_OPAQUE_VALUE, // OpaqueValueExpr
EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator
EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr
+ EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr
EXPR_PACK_EXPANSION, // PackExpansionExpr
EXPR_SIZEOF_PACK, // SizeOfPackExpr
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 424e78c391bc..da018ab99e65 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -69,6 +69,7 @@ class ASTStmtReader;
class ASTIdentifierLookupTrait;
class TypeLocReader;
struct HeaderFileInfo;
+class VersionTuple;
struct PCHPredefinesBlock {
/// \brief The file ID for this predefines buffer in a PCH file.
@@ -213,6 +214,10 @@ private:
/// \brief The AST consumer.
ASTConsumer *Consumer;
+ /// \brief AST buffers for chained PCHs created and stored in memory.
+ /// First (not depending on another) PCH in chain is in front.
+ std::vector<llvm::MemoryBuffer *> ASTBuffers;
+
/// \brief Information that is needed for every module.
struct PerFileData {
PerFileData(ASTFileType Ty);
@@ -806,7 +811,9 @@ private:
///
/// This routine should only be used for fatal errors that have to
/// do with non-routine failures (e.g., corrupted AST file).
- void Error(const char *Msg);
+ void Error(llvm::StringRef Msg);
+ void Error(unsigned DiagID, llvm::StringRef Arg1 = llvm::StringRef(),
+ llvm::StringRef Arg2 = llvm::StringRef());
ASTReader(const ASTReader&); // do not implement
ASTReader &operator=(const ASTReader &); // do not implement
@@ -886,6 +893,13 @@ public:
/// \brief Sets and initializes the given Context.
void InitializeContext(ASTContext &Context);
+ /// \brief Set AST buffers for chained PCHs created and stored in memory.
+ /// First (not depending on another) PCH in chain is first in array.
+ void setASTMemoryBuffers(llvm::MemoryBuffer **bufs, unsigned numBufs) {
+ ASTBuffers.clear();
+ ASTBuffers.insert(ASTBuffers.begin(), bufs, bufs + numBufs);
+ }
+
/// \brief Retrieve the name of the named (primary) AST file
const std::string &getFileName() const { return Chain[0]->FileName; }
@@ -1052,6 +1066,10 @@ public:
/// \brief Print some statistics about AST usage.
virtual void PrintStats();
+ /// Return the amount of memory used by memory buffers, breaking down
+ /// by heap-backed versus mmap'ed memory.
+ virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
+
/// \brief Initialize the semantic source with the Sema instance
/// being used to perform semantic analysis on the abstract syntax
/// tree.
@@ -1108,7 +1126,7 @@ public:
}
/// \brief Read the source location entry with index ID.
- virtual void ReadSLocEntry(unsigned ID);
+ virtual bool ReadSLocEntry(unsigned ID);
Selector DecodeSelector(unsigned Idx);
@@ -1197,6 +1215,9 @@ public:
// \brief Read a string
std::string ReadString(const RecordData &Record, unsigned &Idx);
+ /// \brief Read a version tuple.
+ VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
+
CXXTemporary *ReadCXXTemporary(const RecordData &Record, unsigned &Idx);
/// \brief Reads attributes from the current stream position.
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 04ad93fa7c1a..1a79b31d26b4 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -56,6 +56,7 @@ class Sema;
class SourceManager;
class SwitchCase;
class TargetInfo;
+class VersionTuple;
/// \brief Writes an AST file containing the contents of a translation unit.
///
@@ -322,6 +323,7 @@ private:
void WriteHeaderSearch(HeaderSearch &HS, const char* isysroot);
void WritePreprocessorDetail(PreprocessingRecord &PPRec);
void WritePragmaDiagnosticMappings(const Diagnostic &Diag);
+ void WriteCXXBaseSpecifiersOffsets();
void WriteType(QualType T);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
@@ -513,6 +515,9 @@ public:
/// \brief Add a string to the given record.
void AddString(llvm::StringRef Str, RecordDataImpl &Record);
+ /// \brief Add a version tuple to the given record
+ void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);
+
/// \brief Mark a declaration context as needing an update.
void AddUpdatedDeclContext(const DeclContext *DC) {
UpdatedDeclContexts.insert(DC);
@@ -581,6 +586,10 @@ public:
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D);
+ virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
+ const FunctionDecl *D);
+ virtual void CompletedImplicitDefinition(const FunctionDecl *D);
+ virtual void StaticDataMemberInstantiated(const VarDecl *D);
};
/// \brief AST and semantic-analysis consumer that generates a
diff --git a/include/clang/Serialization/ChainedIncludesSource.h b/include/clang/Serialization/ChainedIncludesSource.h
new file mode 100644
index 000000000000..0c3e86faf414
--- /dev/null
+++ b/include/clang/Serialization/ChainedIncludesSource.h
@@ -0,0 +1,76 @@
+//===- ChainedIncludesSource.h - Chained PCHs in Memory ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ChainedIncludesSource class, which converts headers
+// to chained PCHs in memory, mainly used for testing.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SERIALIZATION_CHAINEDINCLUDESSOURCE_H
+#define LLVM_CLANG_SERIALIZATION_CHAINEDINCLUDESSOURCE_H
+
+#include "clang/Sema/ExternalSemaSource.h"
+#include <vector>
+
+namespace clang {
+ class CompilerInstance;
+
+class ChainedIncludesSource : public ExternalSemaSource {
+public:
+ virtual ~ChainedIncludesSource();
+
+ static ChainedIncludesSource *create(CompilerInstance &CI);
+
+private:
+ ExternalSemaSource &getFinalReader() const { return *FinalReader; }
+
+ std::vector<CompilerInstance *> CIs;
+ llvm::OwningPtr<ExternalSemaSource> FinalReader;
+
+
+protected:
+
+//===----------------------------------------------------------------------===//
+// ExternalASTSource interface.
+//===----------------------------------------------------------------------===//
+
+ virtual Decl *GetExternalDecl(uint32_t ID);
+ virtual Selector GetExternalSelector(uint32_t ID);
+ virtual uint32_t GetNumExternalSelectors();
+ virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
+ virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
+ virtual DeclContextLookupResult
+ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
+ virtual void MaterializeVisibleDecls(const DeclContext *DC);
+ virtual bool FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ llvm::SmallVectorImpl<Decl*> &Result);
+ virtual void CompleteType(TagDecl *Tag);
+ virtual void CompleteType(ObjCInterfaceDecl *Class);
+ virtual void StartedDeserializing();
+ virtual void FinishedDeserializing();
+ virtual void StartTranslationUnit(ASTConsumer *Consumer);
+ virtual void PrintStats();
+
+ /// Return the amount of memory used by memory buffers, breaking down
+ /// by heap-backed versus mmap'ed memory.
+ virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
+
+//===----------------------------------------------------------------------===//
+// ExternalSemaSource interface.
+//===----------------------------------------------------------------------===//
+
+ virtual void InitializeSema(Sema &S);
+ virtual void ForgetSema();
+ virtual std::pair<ObjCMethodList,ObjCMethodList> ReadMethodPool(Selector Sel);
+ virtual bool LookupUnqualified(LookupResult &R, Scope *S);
+};
+
+}
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td
index e452ccfb6ceb..11f1e5d4bd51 100644
--- a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td
+++ b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td
@@ -11,18 +11,19 @@
//
//===----------------------------------------------------------------------===//
+class CheckerGroup<string name> {
+ string GroupName = name;
+}
+class InGroup<CheckerGroup G> { CheckerGroup Group = G; }
+
class Package<string name> {
string PackageName = name;
bit Hidden = 0;
Package ParentPackage;
+ CheckerGroup Group;
}
class InPackage<Package P> { Package ParentPackage = P; }
-class CheckerGroup<string name> {
- string GroupName = name;
-}
-class InGroup<CheckerGroup G> { CheckerGroup Group = G; }
-
// All checkers are an indirect subclass of this.
class Checker<string name = ""> {
string CheckerName = name;
diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
index afba12dc0620..2a3d43e22325 100644
--- a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
+++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
@@ -39,8 +39,6 @@ class ExprEngine;
TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
const LangOptions& lopts);
-void RegisterExperimentalChecks(ExprEngine &Eng);
-
void RegisterCallInliner(ExprEngine &Eng);
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 93d795831d3c..3acbcd685bc0 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -126,7 +126,7 @@ public:
/// getLocation - Return the "definitive" location of the reported bug.
/// While a bug can span an entire path, usually there is a specific
- /// location that can be used to identify where the key issue occured.
+ /// location that can be used to identify where the key issue occurred.
/// This location is used by clients rendering diagnostics.
virtual SourceLocation getLocation() const;
@@ -219,6 +219,18 @@ public:
virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
return std::make_pair(Ranges.begin(), Ranges.end());
}
+
+ virtual void Profile(llvm::FoldingSetNodeID& hash) const {
+ BugReport::Profile(hash);
+ for (llvm::SmallVectorImpl<SourceRange>::const_iterator I =
+ Ranges.begin(), E = Ranges.end(); I != E; ++I) {
+ const SourceRange range = *I;
+ if (!range.isValid())
+ continue;
+ hash.AddInteger(range.getBegin().getRawEncoding());
+ hash.AddInteger(range.getEnd().getRawEncoding());
+ }
+ }
};
class EnhancedBugReport : public RangedBugReport {
diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/Checker.h
index e080d190ab75..8c2ffc690887 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerV2.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -1,4 +1,4 @@
-//== CheckerV2.h - Registration mechanism for checkers -----------*- C++ -*--=//
+//== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
@@ -7,14 +7,15 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines CheckerV2, used to create and register checkers.
+// This file defines Checker, used to create and register checkers.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_SA_CORE_CHECKERV2
-#define LLVM_CLANG_SA_CORE_CHECKERV2
+#ifndef LLVM_CLANG_SA_CORE_CHECKER
+#define LLVM_CLANG_SA_CORE_CHECKER
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/Support/Casting.h"
namespace clang {
@@ -145,6 +146,21 @@ public:
}
};
+class Bind {
+ template <typename CHECKER>
+ static void _checkBind(void *checker, const SVal &location, const SVal &val,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkBind(location, val, C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForBind(
+ CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>));
+ }
+};
+
class EndAnalysis {
template <typename CHECKER>
static void _checkEndAnalysis(void *checker, ExplodedGraph &G,
@@ -175,6 +191,22 @@ public:
}
};
+class BranchCondition {
+ template <typename CHECKER>
+ static void _checkBranchCondition(void *checker, const Stmt *condition,
+ BranchNodeBuilder &B, ExprEngine &Eng) {
+ ((const CHECKER *)checker)->checkBranchCondition(condition, B, Eng);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForBranchCondition(
+ CheckerManager::CheckBranchConditionFunc(checker,
+ _checkBranchCondition<CHECKER>));
+ }
+};
+
class LiveSymbols {
template <typename CHECKER>
static void _checkLiveSymbols(void *checker, const GRState *state,
@@ -228,10 +260,39 @@ public:
}
};
+template <typename EVENT>
+class Event {
+ template <typename CHECKER>
+ static void _checkEvent(void *checker, const void *event) {
+ ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event);
+ }
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerListenerForEvent<EVENT>(
+ CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>));
+ }
+};
+
} // end check namespace
namespace eval {
+class Assume {
+ template <typename CHECKER>
+ static const GRState *_evalAssume(void *checker, const GRState *state,
+ const SVal &cond, bool assumption) {
+ return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForEvalAssume(
+ CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>));
+ }
+};
+
class Call {
template <typename CHECKER>
static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) {
@@ -254,25 +315,58 @@ template <typename CHECK1, typename CHECK2=check::_VoidCheck,
typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck,
typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck,
typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck>
-class CheckerV2 {
+class Checker;
+
+template <>
+class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck> {
+public:
+ static void _register(void *checker, CheckerManager &mgr) { }
+};
+
+template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4,
+ typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8,
+ typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12>
+class Checker
+ : public CHECK1,
+ public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
+ CHECK9, CHECK10, CHECK11, CHECK12> {
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
CHECK1::_register(checker, mgr);
- CHECK2::_register(checker, mgr);
- CHECK3::_register(checker, mgr);
- CHECK4::_register(checker, mgr);
- CHECK5::_register(checker, mgr);
- CHECK6::_register(checker, mgr);
- CHECK7::_register(checker, mgr);
- CHECK8::_register(checker, mgr);
- CHECK9::_register(checker, mgr);
- CHECK10::_register(checker, mgr);
- CHECK11::_register(checker, mgr);
- CHECK12::_register(checker, mgr);
+ Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, CHECK9,
+ CHECK10, CHECK11,CHECK12>::_register(checker, mgr);
+ }
+};
+
+template <typename EVENT>
+class EventDispatcher {
+ CheckerManager *Mgr;
+public:
+ EventDispatcher() : Mgr(0) { }
+
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerDispatcherForEvent<EVENT>();
+ static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr;
+ }
+
+ void dispatchEvent(const EVENT &event) const {
+ Mgr->_dispatchEvent(event);
}
};
+/// \brief We dereferenced a location that may be null.
+struct ImplicitNullDerefEvent {
+ SVal Location;
+ bool IsLoad;
+ ExplodedNode *SinkNode;
+ BugReporter *BR;
+};
+
} // end ento namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 276819549d1a..92ec0388e500 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -37,6 +37,7 @@ namespace ento {
class ExplodedGraph;
class GRState;
class EndOfFunctionNodeBuilder;
+ class BranchNodeBuilder;
class MemRegion;
class SymbolReaper;
@@ -46,47 +47,46 @@ public:
virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0;
};
-struct VoidCheckerFnParm {};
-template <typename P1=VoidCheckerFnParm, typename P2=VoidCheckerFnParm,
- typename P3=VoidCheckerFnParm, typename P4=VoidCheckerFnParm>
-class CheckerFn {
- typedef void (*Func)(void *, P1, P2, P3, P4);
+template <typename T> class CheckerFn;
+
+template <typename RET, typename P1, typename P2, typename P3>
+class CheckerFn<RET(P1, P2, P3)> {
+ typedef RET (*Func)(void *, P1, P2, P3);
Func Fn;
public:
void *Checker;
CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
- void operator()(P1 p1, P2 p2, P3 p3, P4 p4) { Fn(Checker, p1, p2, p3, p4); }
+ RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); }
};
-template <typename P1, typename P2, typename P3>
-class CheckerFn<P1, P2, P3, VoidCheckerFnParm> {
- typedef void (*Func)(void *, P1, P2, P3);
+template <typename RET, typename P1, typename P2>
+class CheckerFn<RET(P1, P2)> {
+ typedef RET (*Func)(void *, P1, P2);
Func Fn;
public:
void *Checker;
CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
- void operator()(P1 p1, P2 p2, P3 p3) { Fn(Checker, p1, p2, p3); }
+ RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); }
};
-template <typename P1, typename P2>
-class CheckerFn<P1, P2, VoidCheckerFnParm, VoidCheckerFnParm> {
- typedef void (*Func)(void *, P1, P2);
+template <typename RET, typename P1>
+class CheckerFn<RET(P1)> {
+ typedef RET (*Func)(void *, P1);
Func Fn;
public:
void *Checker;
CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
- void operator()(P1 p1, P2 p2) { Fn(Checker, p1, p2); }
+ RET operator()(P1 p1) const { return Fn(Checker, p1); }
};
-template <>
-class CheckerFn<VoidCheckerFnParm, VoidCheckerFnParm, VoidCheckerFnParm,
- VoidCheckerFnParm> {
- typedef void (*Func)(void *);
+template <typename RET>
+class CheckerFn<RET()> {
+ typedef RET (*Func)(void *);
Func Fn;
public:
void *Checker;
CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
- void operator()() { Fn(Checker); }
+ RET operator()() const { return Fn(Checker); }
};
class CheckerManager {
@@ -96,21 +96,35 @@ public:
CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { }
~CheckerManager();
+ bool hasPathSensitiveCheckers() const;
+
+ void finishedCheckerRegistration();
+
const LangOptions &getLangOptions() const { return LangOpts; }
typedef void *CheckerRef;
- typedef CheckerFn<> CheckerDtor;
+ typedef void *CheckerTag;
+ typedef CheckerFn<void ()> CheckerDtor;
//===----------------------------------------------------------------------===//
// registerChecker
//===----------------------------------------------------------------------===//
/// \brief Used to register checkers.
+ ///
+ /// \returns a pointer to the checker object.
template <typename CHECKER>
- void registerChecker() {
+ CHECKER *registerChecker() {
+ CheckerTag tag = getTag<CHECKER>();
+ CheckerRef &ref = CheckerTags[tag];
+ if (ref)
+ return static_cast<CHECKER *>(ref); // already registered.
+
CHECKER *checker = new CHECKER();
CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
CHECKER::_register(checker, *this);
+ ref = checker;
+ return checker;
}
//===----------------------------------------------------------------------===//
@@ -179,6 +193,12 @@ public:
const Stmt *S,
ExprEngine &Eng);
+ /// \brief Run checkers for binding of a value to a location.
+ void runCheckersForBind(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ SVal location, SVal val,
+ const Stmt *S, ExprEngine &Eng);
+
/// \brief Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
@@ -186,6 +206,10 @@ public:
/// \brief Run checkers for end of path.
void runCheckersForEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng);
+ /// \brief Run checkers for branch condition.
+ void runCheckersForBranchCondition(const Stmt *condition,
+ BranchNodeBuilder &B, ExprEngine &Eng);
+
/// \brief Run checkers for live symbols.
void runCheckersForLiveSymbols(const GRState *state,
SymbolReaper &SymReaper);
@@ -204,6 +228,10 @@ public:
const MemRegion * const *Begin,
const MemRegion * const *End);
+ /// \brief Run checkers for handling assumptions on symbolic values.
+ const GRState *runCheckersForEvalAssume(const GRState *state,
+ SVal Cond, bool Assumption);
+
/// \brief Run checkers for evaluating a call.
void runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
@@ -217,9 +245,8 @@ public:
// Functions used by the registration mechanism, checkers should not touch
// these directly.
- typedef CheckerFn<const Decl *, AnalysisManager&, BugReporter &>
+ typedef CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)>
CheckDeclFunc;
- typedef CheckerFn<const Stmt *, CheckerContext &> CheckStmtFunc;
typedef bool (*HandlesDeclFunc)(const Decl *D);
void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn);
@@ -230,14 +257,44 @@ public:
// Internal registration functions for path-sensitive checking.
//===----------------------------------------------------------------------===//
- typedef CheckerFn<const ObjCMessage &, CheckerContext &> CheckObjCMessageFunc;
- typedef CheckerFn<const SVal &/*location*/, bool/*isLoad*/, CheckerContext &>
+ typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc;
+
+ typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)>
+ CheckObjCMessageFunc;
+
+ typedef CheckerFn<void (const SVal &location, bool isLoad, CheckerContext &)>
CheckLocationFunc;
- typedef CheckerFn<ExplodedGraph &, BugReporter &, ExprEngine &>
+
+ typedef CheckerFn<void (const SVal &location, const SVal &val,
+ CheckerContext &)> CheckBindFunc;
+
+ typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>
CheckEndAnalysisFunc;
- typedef CheckerFn<EndOfFunctionNodeBuilder &, ExprEngine &> CheckEndPathFunc;
- typedef CheckerFn<SymbolReaper &, CheckerContext &> CheckDeadSymbolsFunc;
- typedef CheckerFn<const GRState *, SymbolReaper &> CheckLiveSymbolsFunc;
+
+ typedef CheckerFn<void (EndOfFunctionNodeBuilder &, ExprEngine &)>
+ CheckEndPathFunc;
+
+ typedef CheckerFn<void (const Stmt *, BranchNodeBuilder &, ExprEngine &)>
+ CheckBranchConditionFunc;
+
+ typedef CheckerFn<void (SymbolReaper &, CheckerContext &)>
+ CheckDeadSymbolsFunc;
+
+ typedef CheckerFn<void (const GRState *,SymbolReaper &)> CheckLiveSymbolsFunc;
+
+ typedef CheckerFn<const GRState * (const GRState *,
+ const MemRegion * const *begin,
+ const MemRegion * const *end)>
+ CheckRegionChangesFunc;
+
+ typedef CheckerFn<bool (const GRState *)> WantsRegionChangeUpdateFunc;
+
+ typedef CheckerFn<const GRState * (const GRState *,
+ const SVal &cond, bool assumption)>
+ EvalAssumeFunc;
+
+ typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
+ EvalCallFunc;
typedef bool (*HandlesStmtFunc)(const Stmt *D);
void _registerForPreStmt(CheckStmtFunc checkfn,
@@ -250,58 +307,55 @@ public:
void _registerForLocation(CheckLocationFunc checkfn);
+ void _registerForBind(CheckBindFunc checkfn);
+
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
void _registerForEndPath(CheckEndPathFunc checkfn);
+ void _registerForBranchCondition(CheckBranchConditionFunc checkfn);
+
void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn);
void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn);
- class CheckRegionChangesFunc {
- typedef const GRState * (*Func)(void *, const GRState *,
- const MemRegion * const *,
- const MemRegion * const *);
- Func Fn;
- public:
- void *Checker;
- CheckRegionChangesFunc(void *checker, Func fn) : Fn(fn), Checker(checker) {}
- const GRState *operator()(const GRState *state,
- const MemRegion * const *begin,
- const MemRegion * const *end) {
- return Fn(Checker, state, begin, end);
- }
- };
-
- class WantsRegionChangeUpdateFunc {
- typedef bool (*Func)(void *, const GRState *);
- Func Fn;
- public:
- void *Checker;
- WantsRegionChangeUpdateFunc(void *checker, Func fn)
- : Fn(fn), Checker(checker) { }
- bool operator()(const GRState *state) {
- return Fn(Checker, state);
- }
- };
-
void _registerForRegionChanges(CheckRegionChangesFunc checkfn,
WantsRegionChangeUpdateFunc wantUpdateFn);
- class EvalCallFunc {
- typedef bool (*Func)(void *, const CallExpr *, CheckerContext &);
- Func Fn;
- public:
- void *Checker;
- EvalCallFunc(void *checker, Func fn) : Fn(fn), Checker(checker) { }
- bool operator()(const CallExpr *CE, CheckerContext &C) {
- return Fn(Checker, CE, C);
- }
- };
+ void _registerForEvalAssume(EvalAssumeFunc checkfn);
void _registerForEvalCall(EvalCallFunc checkfn);
//===----------------------------------------------------------------------===//
+// Internal registration functions for events.
+//===----------------------------------------------------------------------===//
+
+ typedef void *EventTag;
+ typedef CheckerFn<void (const void *event)> CheckEventFunc;
+
+ template <typename EVENT>
+ void _registerListenerForEvent(CheckEventFunc checkfn) {
+ EventInfo &info = Events[getTag<EVENT>()];
+ info.Checkers.push_back(checkfn);
+ }
+
+ template <typename EVENT>
+ void _registerDispatcherForEvent() {
+ EventInfo &info = Events[getTag<EVENT>()];
+ info.HasDispatcher = true;
+ }
+
+ template <typename EVENT>
+ void _dispatchEvent(const EVENT &event) const {
+ EventsTy::const_iterator I = Events.find(getTag<EVENT>());
+ if (I == Events.end())
+ return;
+ const EventInfo &info = I->second;
+ for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i)
+ info.Checkers[i](&event);
+ }
+
+//===----------------------------------------------------------------------===//
// Implementation details.
//===----------------------------------------------------------------------===//
@@ -309,6 +363,11 @@ private:
template <typename CHECKER>
static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); }
+ template <typename T>
+ static void *getTag() { static int tag; return &tag; }
+
+ llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags;
+
std::vector<CheckerDtor> CheckerDtors;
struct DeclCheckerInfo {
@@ -365,10 +424,14 @@ private:
std::vector<CheckLocationFunc> LocationCheckers;
+ std::vector<CheckBindFunc> BindCheckers;
+
std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
std::vector<CheckEndPathFunc> EndPathCheckers;
+ std::vector<CheckBranchConditionFunc> BranchConditionCheckers;
+
std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers;
std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers;
@@ -379,7 +442,18 @@ private:
};
std::vector<RegionChangesCheckerInfo> RegionChangesCheckers;
+ std::vector<EvalAssumeFunc> EvalAssumeCheckers;
+
std::vector<EvalCallFunc> EvalCallCheckers;
+
+ struct EventInfo {
+ llvm::SmallVector<CheckEventFunc, 4> Checkers;
+ bool HasDispatcher;
+ EventInfo() : HasDispatcher(false) { }
+ };
+
+ typedef llvm::DenseMap<EventTag, EventInfo> EventsTy;
+ EventsTy Events;
};
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h
index 40b838e75886..b8aaaa1a04c0 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerProvider.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerProvider.h
@@ -15,7 +15,6 @@
#define LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H
#include "llvm/ADT/StringRef.h"
-#include <vector>
namespace llvm {
class raw_ostream;
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h
index 2713e31fc0d1..d02228fa30dd 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticClients.h
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H
-#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLiENTS_H
+#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H
#include <string>
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index a4327e127f5f..65fbfcc912f9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -16,6 +16,7 @@
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/FoldingSet.h"
@@ -47,16 +48,17 @@ public:
};
class LazyCompoundValData : public llvm::FoldingSetNode {
- const void *store;
+ StoreRef store;
const TypedRegion *region;
public:
- LazyCompoundValData(const void *st, const TypedRegion *r)
+ LazyCompoundValData(const StoreRef &st, const TypedRegion *r)
: store(st), region(r) {}
- const void *getStore() const { return store; }
+ const void *getStore() const { return store.getStore(); }
const TypedRegion *getRegion() const { return region; }
- static void Profile(llvm::FoldingSetNodeID& ID, const void *store,
+ static void Profile(llvm::FoldingSetNodeID& ID,
+ const StoreRef &store,
const TypedRegion *region);
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
@@ -170,7 +172,7 @@ public:
const CompoundValData *getCompoundValData(QualType T,
llvm::ImmutableList<SVal> Vals);
- const LazyCompoundValData *getLazyCompoundValData(const void *store,
+ const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
const TypedRegion *region);
llvm::ImmutableList<SVal> getEmptySValList() {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h
deleted file mode 100644
index 627bc0ab3516..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h
+++ /dev/null
@@ -1,166 +0,0 @@
-//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating
-// domain-specific checks.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_CHECKER
-#define LLVM_CLANG_GR_CHECKER
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
-//===----------------------------------------------------------------------===//
-// Checker interface.
-//===----------------------------------------------------------------------===//
-
-namespace clang {
-
-namespace ento {
-
-class Checker {
-private:
- friend class ExprEngine;
-
- // FIXME: Remove the 'tag' option.
- void GR_Visit(ExplodedNodeSet &Dst,
- StmtNodeBuilder &Builder,
- ExprEngine &Eng,
- const Stmt *S,
- ExplodedNode *Pred, void *tag, bool isPrevisit,
- bool& respondsToCallback) {
- CheckerContext C(Dst, Builder, Eng, Pred, tag,
- isPrevisit ? ProgramPoint::PreStmtKind :
- ProgramPoint::PostStmtKind, &respondsToCallback, S);
- if (isPrevisit)
- _PreVisit(C, S);
- else
- _PostVisit(C, S);
- }
-
- void GR_visitObjCMessage(ExplodedNodeSet &Dst,
- StmtNodeBuilder &Builder,
- ExprEngine &Eng,
- const ObjCMessage &msg,
- ExplodedNode *Pred, void *tag, bool isPrevisit) {
- CheckerContext C(Dst, Builder, Eng, Pred, tag,
- isPrevisit ? ProgramPoint::PreStmtKind :
- ProgramPoint::PostStmtKind, 0, msg.getOriginExpr());
- if (isPrevisit)
- preVisitObjCMessage(C, msg);
- else
- postVisitObjCMessage(C, msg);
- }
-
- bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
- ExprEngine &Eng, const ObjCMessage &msg,
- ExplodedNode *Pred, const GRState *state, void *tag) {
- CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
- 0, msg.getOriginExpr(), state);
- return evalNilReceiver(C, msg);
- }
-
- bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
- ExprEngine &Eng, const CallExpr *CE,
- ExplodedNode *Pred, void *tag) {
- CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
- 0, CE);
- return evalCallExpr(C, CE);
- }
-
- // FIXME: Remove the 'tag' option.
- void GR_VisitBind(ExplodedNodeSet &Dst,
- StmtNodeBuilder &Builder, ExprEngine &Eng,
- const Stmt *StoreE, ExplodedNode *Pred, void *tag,
- SVal location, SVal val,
- bool isPrevisit) {
- CheckerContext C(Dst, Builder, Eng, Pred, tag,
- isPrevisit ? ProgramPoint::PreStmtKind :
- ProgramPoint::PostStmtKind, 0, StoreE);
- assert(isPrevisit && "Only previsit supported for now.");
- PreVisitBind(C, StoreE, location, val);
- }
-
- // FIXME: Remove the 'tag' option.
- void GR_visitLocation(ExplodedNodeSet &Dst,
- StmtNodeBuilder &Builder,
- ExprEngine &Eng,
- const Stmt *S,
- ExplodedNode *Pred, const GRState *state,
- SVal location,
- void *tag, bool isLoad) {
- CheckerContext C(Dst, Builder, Eng, Pred, tag,
- isLoad ? ProgramPoint::PreLoadKind :
- ProgramPoint::PreStoreKind, 0, S, state);
- visitLocation(C, S, location, isLoad);
- }
-
- void GR_evalDeadSymbols(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
- ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
- SymbolReaper &SymReaper, void *tag) {
- CheckerContext C(Dst, Builder, Eng, Pred, tag,
- ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
- evalDeadSymbols(C, SymReaper);
- }
-
-public:
- virtual ~Checker();
- virtual void _PreVisit(CheckerContext &C, const Stmt *S) {}
- virtual void _PostVisit(CheckerContext &C, const Stmt *S) {}
- virtual void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {}
- virtual void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {}
- virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
- bool isLoad) {}
- virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
- SVal location, SVal val) {}
- virtual void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {}
- virtual void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
- ExprEngine &Eng) {}
-
- virtual void MarkLiveSymbols(const GRState *state, SymbolReaper &SymReaper) {}
-
- virtual void VisitBranchCondition(BranchNodeBuilder &Builder,
- ExprEngine &Eng,
- const Stmt *Condition, void *tag) {}
-
- virtual bool evalNilReceiver(CheckerContext &C, ObjCMessage msg) {
- return false;
- }
-
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE) {
- return false;
- }
-
- virtual const GRState *evalAssume(const GRState *state, SVal Cond,
- bool Assumption, bool *respondsToCallback) {
- *respondsToCallback = false;
- return state;
- }
-
- virtual bool wantsRegionChangeUpdate(const GRState *state) { return false; }
-
- virtual const GRState *EvalRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- bool *respondsToCallback) {
- *respondsToCallback = false;
- return state;
- }
-
- virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
- ExprEngine &Eng) {}
-};
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
-
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def
deleted file mode 100644
index 9b3c263e7d53..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def
+++ /dev/null
@@ -1,48 +0,0 @@
-//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the AST nodes accepted by the CheckerVisitor class.
-//
-//===---------------------------------------------------------------------===//
-
-#ifndef PREVISIT
-#define PREVISIT(NODE, FALLBACK)
-#endif
-
-#ifndef POSTVISIT
-#define POSTVISIT(NODE, FALLBACK)
-#endif
-
-PREVISIT(ArraySubscriptExpr, Stmt)
-PREVISIT(BinaryOperator, Stmt)
-PREVISIT(CallExpr, GenericCall)
-PREVISIT(CompoundAssignOperator, BinaryOperator)
-PREVISIT(CStyleCastExpr, CastExpr)
-PREVISIT(CXXConstCastExpr, CastExpr)
-PREVISIT(CXXDynamicCastExpr, CastExpr)
-PREVISIT(CXXFunctionalCastExpr, CastExpr)
-PREVISIT(CXXOperatorCallExpr, GenericCall)
-PREVISIT(CXXMemberCallExpr, GenericCall)
-PREVISIT(CXXReinterpretCastExpr, CastExpr)
-PREVISIT(CXXStaticCastExpr, CastExpr)
-PREVISIT(DeclStmt, Stmt)
-PREVISIT(ImplicitCastExpr, CastExpr)
-PREVISIT(ObjCAtSynchronizedStmt, Stmt)
-PREVISIT(ReturnStmt, Stmt)
-
-POSTVISIT(BlockExpr, Stmt)
-POSTVISIT(BinaryOperator, Stmt)
-POSTVISIT(CallExpr, GenericCall)
-POSTVISIT(CompoundAssignOperator, BinaryOperator)
-POSTVISIT(CXXOperatorCallExpr, GenericCall)
-POSTVISIT(CXXMemberCallExpr, GenericCall)
-POSTVISIT(ObjCIvarRefExpr, Stmt)
-
-#undef PREVISIT
-#undef POSTVISIT
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h
deleted file mode 100644
index dc76c9604741..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h
+++ /dev/null
@@ -1,103 +0,0 @@
-//== CheckerVisitor.h - Abstract visitor for checkers ------------*- 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 CheckerVisitor.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_CHECKERVISITOR
-#define LLVM_CLANG_GR_CHECKERVISITOR
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
-
-namespace clang {
-
-namespace ento {
-
-//===----------------------------------------------------------------------===//
-// Checker visitor interface. Used by subclasses of Checker to specify their
-// own checker visitor logic.
-//===----------------------------------------------------------------------===//
-
-/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses.
-/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
-template<typename ImplClass>
-class CheckerVisitor : public Checker {
-public:
- virtual void _PreVisit(CheckerContext &C, const Stmt *S) {
- PreVisit(C, S);
- }
-
- virtual void _PostVisit(CheckerContext &C, const Stmt *S) {
- PostVisit(C, S);
- }
-
- void PreVisit(CheckerContext &C, const Stmt *S) {
- switch (S->getStmtClass()) {
- default:
- assert(false && "Unsupport statement.");
- return;
-
-#define PREVISIT(NAME, FALLBACK) \
-case Stmt::NAME ## Class:\
-static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
-break;
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def"
- }
- }
-
- void PostVisit(CheckerContext &C, const Stmt *S) {
- switch (S->getStmtClass()) {
- default:
- assert(false && "Unsupport statement.");
- return;
-
-#define POSTVISIT(NAME, FALLBACK) \
-case Stmt::NAME ## Class:\
-static_cast<ImplClass*>(this)->\
-PostVisit ## NAME(C,static_cast<const NAME*>(S));\
-break;
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def"
- }
- }
-
- void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE) {
- static_cast<ImplClass*>(this)->PreVisitStmt(C, CE);
- }
- void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE) {
- static_cast<ImplClass*>(this)->PostVisitStmt(C, CE);
- }
-
- void PreVisitStmt(CheckerContext &C, const Stmt *S) {
- *C.respondsToCallback = false;
- }
-
- void PostVisitStmt(CheckerContext &C, const Stmt *S) {
- *C.respondsToCallback = false;
- }
-
- void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) {
- static_cast<ImplClass*>(this)->PreVisitStmt(C, E);
- }
-
-#define PREVISIT(NAME, FALLBACK) \
-void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\
- static_cast<ImplClass*>(this)->PreVisit ## FALLBACK(C, S);\
-}
-#define POSTVISIT(NAME, FALLBACK) \
-void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
- static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
-}
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.def"
-};
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 25c644734232..2c1d07c59b68 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -47,7 +47,11 @@ class CoreEngine {
public:
typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
+ BlocksExhausted;
+
+ typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
BlocksAborted;
+
private:
SubEngine& SubEng;
@@ -67,6 +71,10 @@ private:
/// The locations where we stopped doing work because we visited a location
/// too many times.
+ BlocksExhausted blocksExhausted;
+
+ /// The locations where we stopped because the engine aborted analysis,
+ /// usually because it could not reason about something.
BlocksAborted blocksAborted;
void generateNode(const ProgramPoint& Loc, const GRState* State,
@@ -110,7 +118,7 @@ public:
ExplodedGraph& getGraph() { return *G.get(); }
/// takeGraph - Returns the exploded graph. Ownership of the graph is
- /// transfered to the caller.
+ /// transferred to the caller.
ExplodedGraph* takeGraph() { return G.take(); }
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
@@ -123,10 +131,25 @@ public:
// Functions for external checking of whether we have unfinished work
bool wasBlockAborted() const { return !blocksAborted.empty(); }
- bool hasWorkRemaining() const { return wasBlockAborted() || WList->hasWork(); }
-
+ bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
+ bool hasWorkRemaining() const { return wasBlocksExhausted() ||
+ WList->hasWork() ||
+ wasBlockAborted(); }
+
+ /// Inform the CoreEngine that a basic block was aborted because
+ /// it could not be completely analyzed.
+ void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
+ blocksAborted.push_back(std::make_pair(block, node));
+ }
+
WorkList *getWorkList() const { return WList; }
+ BlocksExhausted::const_iterator blocks_exhausted_begin() const {
+ return blocksExhausted.begin();
+ }
+ BlocksExhausted::const_iterator blocks_exhausted_end() const {
+ return blocksExhausted.end();
+ }
BlocksAborted::const_iterator blocks_aborted_begin() const {
return blocksAborted.begin();
}
@@ -219,11 +242,8 @@ public:
/// getStmt - Return the current block-level expression associated with
/// this builder.
const Stmt* getStmt() const {
- CFGStmt CS = B[Idx].getAs<CFGStmt>();
- if (CS)
- return CS.getStmt();
- else
- return 0;
+ const CFGStmt *CS = B[Idx].getAs<CFGStmt>();
+ return CS ? CS->getStmt() : 0;
}
/// getBlock - Return the CFGBlock associated with the block-level expression
@@ -287,6 +307,8 @@ public:
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+ ExplodedNode* generateNode(const Stmt *Condition, const GRState* State);
+
ExplodedNode* generateNode(const GRState* State, bool branch);
const CFGBlock* getTargetBlock(bool branch) const {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index 732a40cb2145..193056e6b030 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -51,9 +51,10 @@ public:
iterator end() const { return ExprBindings.end(); }
- /// GetSVal - Fetches the current binding of the expression in the
+ /// getSVal - Fetches the current binding of the expression in the
/// Environment.
- SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder) const;
+ SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder,
+ bool useOnlyDirectBindings = false) const;
/// Profile - Profile the contents of an Environment object for use
/// in a FoldingSet.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 16f54ee7468d..8cd743f68f56 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -34,7 +34,6 @@ class ObjCForCollectionStmt;
namespace ento {
class AnalysisManager;
-class Checker;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
@@ -74,39 +73,6 @@ class ExprEngine : public SubEngine {
Selector* NSExceptionInstanceRaiseSelectors;
Selector RaiseSel;
- enum CallbackKind {
- PreVisitStmtCallback,
- PostVisitStmtCallback,
- processAssumeCallback,
- EvalRegionChangesCallback
- };
-
- typedef uint32_t CallbackTag;
-
- /// GetCallbackTag - Create a tag for a certain kind of callback. The 'Sub'
- /// argument can be used to differentiate callbacks that depend on another
- /// value from a small set of possibilities, such as statement classes.
- static inline CallbackTag GetCallbackTag(CallbackKind K, uint32_t Sub = 0) {
- assert(Sub == ((Sub << 8) >> 8) && "Tag sub-kind must fit into 24 bits");
- return K | (Sub << 8);
- }
-
- typedef llvm::DenseMap<void *, unsigned> CheckerMap;
- typedef std::vector<std::pair<void *, Checker*> > CheckersOrdered;
- typedef llvm::DenseMap<CallbackTag, CheckersOrdered *> CheckersOrderedCache;
-
- /// A registration map from checker tag to the index into the
- /// ordered checkers vector.
- CheckerMap CheckerM;
-
- /// An ordered vector of checkers that are called when evaluating
- /// various expressions and statements.
- CheckersOrdered Checkers;
-
- /// A map used for caching the checkers that respond to the callback for
- /// a particular callback tag.
- CheckersOrderedCache COCache;
-
/// The BugReporter associated with this engine. It is important that
/// this object be placed at the very end of member variables so that its
/// destructor is called before the rest of the ExprEngine is destroyed.
@@ -165,21 +131,6 @@ public:
ExplodedGraph& getGraph() { return G; }
const ExplodedGraph& getGraph() const { return G; }
- template <typename CHECKER>
- void registerCheck(CHECKER *check) {
- unsigned entry = Checkers.size();
- void *tag = CHECKER::getTag();
- Checkers.push_back(std::make_pair(tag, check));
- CheckerM[tag] = entry;
- }
-
- Checker *lookupChecker(void *tag) const;
-
- template <typename CHECKER>
- CHECKER *getChecker() const {
- return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag()));
- }
-
/// processCFGElement - Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a CFG element.
void processCFGElement(const CFGElement E, StmtNodeBuilder& builder);
@@ -262,11 +213,9 @@ public:
const SymbolManager& getSymbolManager() const { return SymMgr; }
// Functions for external checking of whether we have unfinished work
- bool wasBlockAborted() const { return Engine.wasBlockAborted(); }
+ bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); }
bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); }
- bool hasWorkRemaining() const {
- return wasBlockAborted() || Engine.getWorkList()->hasWork();
- }
+ bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); }
const CoreEngine &getCoreEngine() const { return Engine; }
@@ -281,27 +230,6 @@ public:
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0);
- /// CheckerVisit - Dispatcher for performing checker-specific logic
- /// at specific statements.
- void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
- CallbackKind Kind);
-
- void CheckerVisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Dst,
- ExplodedNodeSet &Src, bool isPrevisit);
-
- bool CheckerEvalCall(const CallExpr *CE,
- ExplodedNodeSet &Dst,
- ExplodedNode *Pred);
-
- void CheckerEvalNilReceiver(const ObjCMessage &msg,
- ExplodedNodeSet &Dst,
- const GRState *state,
- ExplodedNode *Pred);
-
- void CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
- ExplodedNodeSet &Src, SVal location, SVal val,
- bool isPrevisit);
-
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
void Visit(const Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst);
@@ -334,10 +262,8 @@ public:
/// VisitCall - Transfer function for function calls.
- void VisitCall(const CallExpr* CE, ExplodedNode* Pred,
- CallExpr::const_arg_iterator AI,
- CallExpr::const_arg_iterator AE,
- ExplodedNodeSet& Dst);
+ void VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
@@ -358,11 +284,6 @@ public:
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
void VisitGuardedExpr(const Expr* Ex, const Expr* L, const Expr* R,
ExplodedNode* Pred, ExplodedNodeSet& Dst);
-
- /// VisitCondInit - Transfer function for handling the initialization
- /// of a condition variable in an IfStmt, SwitchStmt, etc.
- void VisitCondInit(const VarDecl *VD, const Stmt *S, ExplodedNode *Pred,
- ExplodedNodeSet& Dst);
void VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
@@ -409,9 +330,9 @@ public:
void VisitOffsetOfExpr(const OffsetOfExpr* Ex, ExplodedNode* Pred,
ExplodedNodeSet& Dst);
- /// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
- void VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
- ExplodedNodeSet& Dst);
+ /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof.
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr* Ex,
+ ExplodedNode* Pred, ExplodedNodeSet& Dst);
/// VisitUnaryOperator - Transfer function logic for unary operators.
void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred,
@@ -432,12 +353,6 @@ public:
const MemRegion *Dest, const Stmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
- ExplodedNodeSet &Dst);
-
- void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
@@ -463,12 +378,10 @@ public:
const FunctionProtoType *FnType,
ExplodedNode *Pred, ExplodedNodeSet &Dst,
bool FstArgAsLValue = false);
-
- /// Evaluate method call itself. Used for CXXMethodCallExpr and
- /// CXXOperatorCallExpr.
- void evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
- const Expr *ThisExpr, ExplodedNode *Pred,
- ExplodedNodeSet &Src, ExplodedNodeSet &Dst);
+
+ /// Evaluate callee expression (for a function call).
+ void evalCallee(const CallExpr *callExpr, const ExplodedNodeSet &src,
+ ExplodedNodeSet &dest);
/// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
index 37694da6573c..a957c897b92a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
@@ -35,7 +35,6 @@ class ASTContext;
namespace ento {
class GRStateManager;
-class Checker;
typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
SubEngine&);
@@ -261,7 +260,7 @@ public:
const llvm::APSInt *getSymVal(SymbolRef sym) const;
/// Returns the SVal bound to the statement 'S' in the state's environment.
- SVal getSVal(const Stmt* S) const;
+ SVal getSVal(const Stmt* S, bool useOnlyDirectBindings = false) const;
SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
@@ -274,8 +273,6 @@ public:
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
- const llvm::APSInt *getSymVal(SymbolRef sym);
-
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
bool scanReachableSymbols(const SVal *I, const SVal *E,
@@ -627,10 +624,6 @@ public:
// Out-of-line method definitions for GRState.
//===----------------------------------------------------------------------===//
-inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) {
- return getStateManager().getSymVal(this, sym);
-}
-
inline const VarRegion* GRState::getRegion(const VarDecl *D,
const LocationContext *LC) const {
return getStateManager().getRegionManager().getVarRegion(D, LC);
@@ -690,14 +683,15 @@ inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
return getStateManager().getSymVal(this, sym);
}
-inline SVal GRState::getSVal(const Stmt* Ex) const {
- return Env.getSVal(Ex, *getStateManager().svalBuilder);
+inline SVal GRState::getSVal(const Stmt* Ex, bool useOnlyDirectBindings) const{
+ return Env.getSVal(Ex, *getStateManager().svalBuilder,
+ useOnlyDirectBindings);
}
inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
if (const Expr *Ex = dyn_cast<Expr>(S)) {
QualType T = Ex->getType();
- if (Loc::isLocType(T) || T->isIntegerType())
+ if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType())
return getSVal(S);
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 8d19b5199274..db7a930b556e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -769,7 +769,7 @@ public:
}
};
//===----------------------------------------------------------------------===//
-// Auxillary data classes for use with MemRegions.
+// Auxiliary data classes for use with MemRegions.
//===----------------------------------------------------------------------===//
class ElementRegion;
@@ -960,7 +960,7 @@ public:
getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
const LocationContext *LC);
- /// getCXXThisRegion - Retrieve the [artifical] region associated with the
+ /// getCXXThisRegion - Retrieve the [artificial] region associated with the
/// parameter 'this'.
const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
const LocationContext *LC);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index 710fc6b84f9e..6d8fc89a4839 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
@@ -72,6 +72,8 @@ public:
return getType(ctx);
}
+ ObjCMethodFamily getMethodFamily() const;
+
Selector getSelector() const;
const Expr *getInstanceReceiver() const {
@@ -169,14 +171,23 @@ class CallOrObjCMessage {
const CallExpr *CallE;
ObjCMessage Msg;
const GRState *State;
-
public:
CallOrObjCMessage(const CallExpr *callE, const GRState *state)
- : CallE(callE), State(state) { }
+ : CallE(callE), State(state) {}
CallOrObjCMessage(const ObjCMessage &msg, const GRState *state)
- : CallE(0), Msg(msg), State(state) { }
+ : CallE(0), Msg(msg), State(state) {}
QualType getResultType(ASTContext &ctx) const;
+
+ bool isFunctionCall() const {
+ return (bool) CallE;
+ }
+
+ bool isCXXCall() const {
+ return CallE && isa<CXXMemberCallExpr>(CallE);
+ }
+
+ SVal getCXXCallee() const;
unsigned getNumArgs() const {
if (CallE) return CallE->getNumArgs();
@@ -185,7 +196,8 @@ public:
SVal getArgSVal(unsigned i) const {
assert(i < getNumArgs());
- if (CallE) return State->getSVal(CallE->getArg(i));
+ if (CallE)
+ return State->getSVal(CallE->getArg(i));
return Msg.getArgSVal(i, State);
}
@@ -193,13 +205,15 @@ public:
const Expr *getArg(unsigned i) const {
assert(i < getNumArgs());
- if (CallE) return CallE->getArg(i);
+ if (CallE)
+ return CallE->getArg(i);
return Msg.getArgExpr(i);
}
SourceRange getArgSourceRange(unsigned i) const {
assert(i < getNumArgs());
- if (CallE) return CallE->getArg(i)->getSourceRange();
+ if (CallE)
+ return CallE->getArg(i)->getSourceRange();
return Msg.getArgSourceRange(i);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index fc2b76e04a66..0f9e56aa2ff8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -49,10 +49,10 @@ protected:
const unsigned ArrayIndexWidth;
public:
- // FIXME: Make these protected again one RegionStoreManager correctly
- // handles loads from differening bound value types.
- virtual SVal evalCastNL(NonLoc val, QualType castTy) = 0;
- virtual SVal evalCastL(Loc val, QualType castTy) = 0;
+ // FIXME: Make these protected again once RegionStoreManager correctly
+ // handles loads from different bound value types.
+ virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
+ virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
public:
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
@@ -66,30 +66,30 @@ public:
virtual ~SValBuilder() {}
- SVal evalCast(SVal V, QualType castTy, QualType originalType);
+ SVal evalCast(SVal val, QualType castTy, QualType originalType);
virtual SVal evalMinus(NonLoc val) = 0;
virtual SVal evalComplement(NonLoc val) = 0;
- virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode Op,
+ virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode Op,
+ virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode op,
Loc lhs, Loc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode Op,
+ virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) = 0;
/// getKnownValue - evaluates a given SVal. If the SVal has only one possible
/// (integer) value, that value is returned. Otherwise, returns NULL.
- virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V) = 0;
+ virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal val) = 0;
- SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
- SVal L, SVal R, QualType T);
+ SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal lhs, SVal rhs, QualType type);
- DefinedOrUnknownSVal evalEQ(const GRState *ST, DefinedOrUnknownSVal L,
- DefinedOrUnknownSVal R);
+ DefinedOrUnknownSVal evalEQ(const GRState *state, DefinedOrUnknownSVal lhs,
+ DefinedOrUnknownSVal rhs);
ASTContext &getContext() { return Context; }
const ASTContext &getContext() const { return Context; }
@@ -115,46 +115,48 @@ public:
// Forwarding methods to SymbolManager.
- const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
- unsigned VisitCount,
- const void* SymbolTag = 0) {
- return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag);
+ const SymbolConjured* getConjuredSymbol(const Stmt* stmt, QualType type,
+ unsigned visitCount,
+ const void* symbolTag = 0) {
+ return SymMgr.getConjuredSymbol(stmt, type, visitCount, symbolTag);
}
- const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
- const void* SymbolTag = 0) {
- return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
+ const SymbolConjured* getConjuredSymbol(const Expr* expr, unsigned visitCount,
+ const void* symbolTag = 0) {
+ return SymMgr.getConjuredSymbol(expr, visitCount, symbolTag);
}
/// makeZeroVal - Construct an SVal representing '0' for the specified type.
- DefinedOrUnknownSVal makeZeroVal(QualType T);
+ DefinedOrUnknownSVal makeZeroVal(QualType type);
- /// getRegionValueSymbolVal - make a unique symbol for value of R.
- DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *R);
+ /// getRegionValueSymbolVal - make a unique symbol for value of region.
+ DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *region);
- DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
- const Expr *E, unsigned Count);
- DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
- const Expr *E, QualType T,
- unsigned Count);
+ DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
+ const Expr *expr, unsigned count);
+ DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
+ const Expr *expr, QualType type,
+ unsigned count);
- DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
- const TypedRegion *R);
+ DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
+ SymbolRef parentSymbol, const TypedRegion *region);
- DefinedSVal getMetadataSymbolVal(const void *SymbolTag, const MemRegion *MR,
- const Expr *E, QualType T, unsigned Count);
+ DefinedSVal getMetadataSymbolVal(
+ const void *symbolTag, const MemRegion *region,
+ const Expr *expr, QualType type, unsigned count);
- DefinedSVal getFunctionPointer(const FunctionDecl *FD);
+ DefinedSVal getFunctionPointer(const FunctionDecl *func);
- DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy,
- const LocationContext *LC);
+ DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
+ const LocationContext *locContext);
- NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
- return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
+ NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) {
+ return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals));
}
- NonLoc makeLazyCompoundVal(const void *store, const TypedRegion *R) {
- return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(store, R));
+ NonLoc makeLazyCompoundVal(const StoreRef &store, const TypedRegion *region) {
+ return nonloc::LazyCompoundVal(
+ BasicVals.getLazyCompoundValData(store, region));
}
NonLoc makeZeroArrayIndex() {
@@ -165,60 +167,63 @@ public:
return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy));
}
- SVal convertToArrayIndex(SVal V);
+ SVal convertToArrayIndex(SVal val);
- nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) {
- return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(),
- I->getType()->isUnsignedIntegerType()));
+ nonloc::ConcreteInt makeIntVal(const IntegerLiteral* integer) {
+ return nonloc::ConcreteInt(
+ BasicVals.getValue(integer->getValue(),
+ integer->getType()->isUnsignedIntegerType()));
}
- nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *E) {
- return makeTruthVal(E->getValue());
+ nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean) {
+ return makeTruthVal(boolean->getValue());
}
- nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) {
- return nonloc::ConcreteInt(BasicVals.getValue(V));
+ nonloc::ConcreteInt makeIntVal(const llvm::APSInt& integer) {
+ return nonloc::ConcreteInt(BasicVals.getValue(integer));
}
- loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) {
- return loc::ConcreteInt(BasicVals.getValue(v));
+ loc::ConcreteInt makeIntLocVal(const llvm::APSInt &integer) {
+ return loc::ConcreteInt(BasicVals.getValue(integer));
}
- NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) {
- return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
+ NonLoc makeIntVal(const llvm::APInt& integer, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getValue(integer, isUnsigned));
}
- DefinedSVal makeIntVal(uint64_t X, QualType T) {
- if (Loc::isLocType(T))
- return loc::ConcreteInt(BasicVals.getValue(X, T));
+ DefinedSVal makeIntVal(uint64_t integer, QualType type) {
+ if (Loc::isLocType(type))
+ return loc::ConcreteInt(BasicVals.getValue(integer, type));
- return nonloc::ConcreteInt(BasicVals.getValue(X, T));
+ return nonloc::ConcreteInt(BasicVals.getValue(integer, type));
}
- NonLoc makeIntVal(uint64_t X, bool isUnsigned) {
- return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
+ NonLoc makeIntVal(uint64_t integer, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getIntValue(integer, isUnsigned));
}
- NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) {
- return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned));
+ NonLoc makeIntValWithPtrWidth(uint64_t integer, bool isUnsigned) {
+ return nonloc::ConcreteInt(
+ BasicVals.getIntWithPtrWidth(integer, isUnsigned));
}
- NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) {
- return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
+ NonLoc makeIntVal(uint64_t integer, unsigned bitWidth, bool isUnsigned) {
+ return nonloc::ConcreteInt(
+ BasicVals.getValue(integer, bitWidth, isUnsigned));
}
- NonLoc makeLocAsInteger(Loc V, unsigned Bits) {
- return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits));
+ NonLoc makeLocAsInteger(Loc loc, unsigned bits) {
+ return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits));
}
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
- const llvm::APSInt& rhs, QualType T);
+ const llvm::APSInt& rhs, QualType type);
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
- const SymExpr *rhs, QualType T);
+ const SymExpr *rhs, QualType type);
- nonloc::ConcreteInt makeTruthVal(bool b, QualType T) {
- return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
+ nonloc::ConcreteInt makeTruthVal(bool b, QualType type) {
+ return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type));
}
nonloc::ConcreteInt makeTruthVal(bool b) {
@@ -229,20 +234,20 @@ public:
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
}
- Loc makeLoc(SymbolRef Sym) {
- return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym));
+ Loc makeLoc(SymbolRef sym) {
+ return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
}
- Loc makeLoc(const MemRegion* R) {
- return loc::MemRegionVal(R);
+ Loc makeLoc(const MemRegion* region) {
+ return loc::MemRegionVal(region);
}
- Loc makeLoc(const AddrLabelExpr *E) {
- return loc::GotoLabel(E->getLabel());
+ Loc makeLoc(const AddrLabelExpr *expr) {
+ return loc::GotoLabel(expr->getLabel());
}
- Loc makeLoc(const llvm::APSInt& V) {
- return loc::ConcreteInt(BasicVals.getValue(V));
+ Loc makeLoc(const llvm::APSInt& integer) {
+ return loc::ConcreteInt(BasicVals.getValue(integer));
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 0251311c27ae..21c6ae760cc8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_GR_STORE_H
#define LLVM_CLANG_GR_STORE_H
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "llvm/ADT/DenseSet.h"
@@ -28,36 +29,10 @@ class StackFrameContext;
namespace ento {
-/// Store - This opaque type encapsulates an immutable mapping from
-/// locations to values. At a high-level, it represents the symbolic
-/// memory model. Different subclasses of StoreManager may choose
-/// different types to represent the locations and values.
-typedef const void* Store;
-
class GRState;
class GRStateManager;
class SubRegionMap;
-class StoreManager;
-
-class StoreRef {
- Store store;
- StoreManager &mgr;
-public:
- StoreRef(Store, StoreManager &);
- StoreRef(const StoreRef &);
- StoreRef &operator=(StoreRef const &);
-
- bool operator==(const StoreRef &x) const {
- assert(&mgr == &x.mgr);
- return x.store == store;
- }
- bool operator!=(const StoreRef &x) const { return !operator==(x); }
- ~StoreRef();
-
- Store getStore() const { return store; }
-};
-
class StoreManager {
protected:
SValBuilder &svalBuilder;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
new file mode 100644
index 000000000000..0662eadc93c3
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
@@ -0,0 +1,50 @@
+//== StoreRef.h - Smart pointer for store objects ---------------*- 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 type StoreRef.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_STOREREF_H
+#define LLVM_CLANG_GR_STOREREF_H
+
+#include <cassert>
+
+namespace clang {
+namespace ento {
+
+/// Store - This opaque type encapsulates an immutable mapping from
+/// locations to values. At a high-level, it represents the symbolic
+/// memory model. Different subclasses of StoreManager may choose
+/// different types to represent the locations and values.
+typedef const void* Store;
+
+class StoreManager;
+
+class StoreRef {
+ Store store;
+ StoreManager &mgr;
+public:
+ StoreRef(Store, StoreManager &);
+ StoreRef(const StoreRef &);
+ StoreRef &operator=(StoreRef const &);
+
+ bool operator==(const StoreRef &x) const {
+ assert(&mgr == &x.mgr);
+ return x.store == store;
+ }
+ bool operator!=(const StoreRef &x) const { return !operator==(x); }
+
+ ~StoreRef();
+
+ Store getStore() const { return store; }
+};
+
+}}
+#endif
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
new file mode 100644
index 000000000000..6ccccd0bff0c
--- /dev/null
+++ b/include/clang/Tooling/Tooling.h
@@ -0,0 +1,81 @@
+//===--- Tooling.h - Framework for standalone Clang tools -------*- 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 functions to run clang tools standalone instead
+// of running them as a plugin.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_TOOLING_H
+#define LLVM_CLANG_TOOLING_TOOLING_H
+
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class FrontendAction;
+
+namespace tooling {
+
+/// \brief Runs (and deletes) the tool on 'Code' with the -fsynatx-only flag.
+///
+/// \param ToolAction The action to run over the code.
+/// \param Code C++ code.
+///
+/// \return - True if 'ToolAction' was successfully executed.
+bool RunSyntaxOnlyToolOnCode(
+ clang::FrontendAction *ToolAction, llvm::StringRef Code);
+
+/// \brief Runs (and deletes) the tool with the given Clang flags.
+///
+/// \param ToolAction The action to run over the code.
+/// \param Argc The number of elements in Argv.
+/// \param Argv The command line arguments, including the path the binary
+/// was started with (Argv[0]).
+bool RunToolWithFlags(
+ clang::FrontendAction* ToolAction, int Argc, char *Argv[]);
+
+/// \brief Converts a vector<string> into a vector<char*> suitable to pass
+/// to main-style functions taking (int Argc, char *Argv[]).
+std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command);
+
+/// \brief Specifies the working directory and command of a compilation.
+struct CompileCommand {
+ /// \brief The working directory the command was executed from.
+ std::string Directory;
+
+ /// \brief The command line that was executed.
+ std::vector<std::string> CommandLine;
+};
+
+/// \brief Looks up the compile command for 'FileName' in 'JsonDatabase'.
+///
+/// \param FileName The path to an input file for which we want the compile
+/// command line. If the 'JsonDatabase' was created by CMake, this must be
+/// an absolute path inside the CMake source directory which does not have
+/// symlinks resolved.
+///
+/// \param JsonDatabase A JSON formatted list of compile commands. This lookup
+/// command supports only a subset of the JSON standard as written by CMake.
+///
+/// \param ErrorMessage If non-empty, an error occurred and 'ErrorMessage' will
+/// be set to contain the error message. In this case CompileCommand will
+/// contain an empty directory and command line.
+///
+/// \see JsonCompileCommandLineDatabase
+CompileCommand FindCompileArgsInJsonDatabase(
+ llvm::StringRef FileName, llvm::StringRef JsonDatabase,
+ std::string &ErrorMessage);
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_TOOLING_H
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 9c2455034d68..8316ea68e9e4 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -107,7 +107,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P))
CanonParams.push_back(
TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(), TTP->getDepth(),
+ SourceLocation(),
+ SourceLocation(),
+ TTP->getDepth(),
TTP->getIndex(), 0, false,
TTP->isParameterPack()));
else if (NonTypeTemplateParmDecl *NTTP
@@ -125,7 +127,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
}
Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(),
+ SourceLocation(),
+ SourceLocation(),
NTTP->getDepth(),
NTTP->getPosition(), 0,
T,
@@ -135,7 +138,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
ExpandedTInfos.data());
} else {
Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(),
+ SourceLocation(),
+ SourceLocation(),
NTTP->getDepth(),
NTTP->getPosition(), 0,
T,
@@ -186,11 +190,28 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
return 0;
}
+static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T,
+ const LangOptions &LOpts) {
+ if (LOpts.FakeAddressSpaceMap) {
+ // The fake address space map must have a distinct entry for each
+ // language-specific address space.
+ static const unsigned FakeAddrSpaceMap[] = {
+ 1, // opencl_global
+ 2, // opencl_local
+ 3 // opencl_constant
+ };
+ return FakeAddrSpaceMap;
+ } else {
+ return T.getAddressSpaceMap();
+ }
+}
+
ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
const TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
unsigned size_reserve) :
+ FunctionProtoTypes(this_()),
TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()),
GlobalNestedNameSpecifier(0), IsInt128Installed(false),
@@ -199,7 +220,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
cudaConfigureCallDecl(0),
NullTypeSourceInfo(QualType()),
- SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), Target(t),
+ SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)),
+ AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t),
Idents(idents), Selectors(sels),
BuiltinInfo(builtins),
DeclarationNames(*this),
@@ -353,7 +375,7 @@ void ASTContext::InitBuiltinTypes() {
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
if (LangOpts.CPlusPlus) { // C++ 3.9.1p5
- if (!LangOpts.ShortWChar)
+ if (TargetInfo::isTypeSigned(Target.getWCharType()))
InitBuiltinType(WCharTy, BuiltinType::WChar_S);
else // -fshort-wchar makes wchar_t be unsigned.
InitBuiltinType(WCharTy, BuiltinType::WChar_U);
@@ -380,6 +402,12 @@ void ASTContext::InitBuiltinTypes() {
// Placeholder type for functions.
InitBuiltinType(OverloadTy, BuiltinType::Overload);
+ // Placeholder type for bound members.
+ InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember);
+
+ // "any" type; useful for debugger-like clients.
+ InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny);
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
@@ -429,7 +457,6 @@ void ASTContext::eraseDeclAttrs(const Decl *D) {
}
}
-
MemberSpecializationInfo *
ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) {
assert(Var->isStaticDataMember() && "Not a static data member");
@@ -509,6 +536,20 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
}
+bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0);
+
+}
+
+bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (FD->isBitField() && LastFD && LastFD->isBitField() &&
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0);
+
+}
+
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
@@ -697,6 +738,7 @@ ASTContext::getTypeInfo(const Type *T) const {
std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType());
Width = EltInfo.first*CAT->getSize().getZExtValue();
Align = EltInfo.second;
+ Width = llvm::RoundUpToAlignment(Width, Align);
break;
}
case Type::ExtVector:
@@ -801,7 +843,8 @@ ASTContext::getTypeInfo(const Type *T) const {
Align = Target.getPointerAlign(0);
break;
case Type::BlockPointer: {
- unsigned AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace();
+ unsigned AS = getTargetAddressSpace(
+ cast<BlockPointerType>(T)->getPointeeType());
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
@@ -810,13 +853,14 @@ ASTContext::getTypeInfo(const Type *T) const {
case Type::RValueReference: {
// alignof and sizeof should never enter this code path here, so we go
// the pointer route.
- unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
+ unsigned AS = getTargetAddressSpace(
+ cast<ReferenceType>(T)->getPointeeType());
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
}
case Type::Pointer: {
- unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
+ unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
@@ -852,8 +896,8 @@ ASTContext::getTypeInfo(const Type *T) const {
const TagType *TT = cast<TagType>(T);
if (TT->getDecl()->isInvalidDecl()) {
- Width = 1;
- Align = 1;
+ Width = 8;
+ Align = 8;
break;
}
@@ -881,7 +925,7 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());
case Type::Typedef: {
- const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
+ const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
std::pair<uint64_t, unsigned> Info
= getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
// If the typedef has an aligned attribute on it, it overrides any computed
@@ -1463,7 +1507,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// the target.
llvm::APInt ArySize(ArySizeIn);
ArySize =
- ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
+ ArySize.zextOrTrunc(Target.getPointerWidth(getTargetAddressSpace(EltTy)));
llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
@@ -1862,7 +1906,9 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
QualType
ASTContext::getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const {
- const CallingConv CallConv = Info.getCC();
+ const CallingConv DefaultCC = Info.getCC();
+ const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
+ CC_X86StdCall : DefaultCC;
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1886,8 +1932,9 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
+ FunctionProtoType::ExtInfo newInfo = Info.withCallingConv(CallConv);
FunctionNoProtoType *New = new (*this, TypeAlignment)
- FunctionNoProtoType(ResultTy, Canonical, Info);
+ FunctionNoProtoType(ResultTy, Canonical, newInfo);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1902,7 +1949,7 @@ ASTContext::getFunctionType(QualType ResultTy,
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI);
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -1910,12 +1957,14 @@ ASTContext::getFunctionType(QualType ResultTy,
return QualType(FTP, 0);
// Determine whether the type being created is already canonical or not.
- bool isCanonical = !EPI.HasExceptionSpec && ResultTy.isCanonical();
+ bool isCanonical= EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical();
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
- const CallingConv CallConv = EPI.ExtInfo.getCC();
+ const CallingConv DefaultCC = EPI.ExtInfo.getCC();
+ const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
+ CC_X86StdCall : DefaultCC;
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
@@ -1927,11 +1976,8 @@ ASTContext::getFunctionType(QualType ResultTy,
CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i]));
FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
- if (CanonicalEPI.HasExceptionSpec) {
- CanonicalEPI.HasExceptionSpec = false;
- CanonicalEPI.HasAnyExceptionSpec = false;
- CanonicalEPI.NumExceptions = 0;
- }
+ CanonicalEPI.ExceptionSpecType = EST_None;
+ CanonicalEPI.NumExceptions = 0;
CanonicalEPI.ExtInfo
= CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
@@ -1947,12 +1993,19 @@ ASTContext::getFunctionType(QualType ResultTy,
// FunctionProtoType objects are allocated with extra bytes after them
// for two variable size arrays (for parameter and exception types) at the
- // end of them.
+ // end of them. Instead of the exception types, there could be a noexcept
+ // expression and a context pointer.
size_t Size = sizeof(FunctionProtoType) +
- NumArgs * sizeof(QualType) +
- EPI.NumExceptions * sizeof(QualType);
+ NumArgs * sizeof(QualType);
+ if (EPI.ExceptionSpecType == EST_Dynamic)
+ Size += EPI.NumExceptions * sizeof(QualType);
+ else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ Size += sizeof(Expr*);
+ }
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
- new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, EPI);
+ FunctionProtoType::ExtProtoInfo newEPI = EPI;
+ newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -1997,7 +2050,7 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
assert(Decl && "Passed null for Decl param");
assert(!Decl->TypeForDecl && "TypeForDecl present in slow case");
- if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
+ if (const TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Decl))
return getTypedefType(Typedef);
assert(!isa<TemplateTypeParmDecl>(Decl) &&
@@ -2024,9 +2077,10 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
}
/// getTypedefType - Return the unique reference to the type for the
-/// specified typename decl.
+/// specified typedef name decl.
QualType
-ASTContext::getTypedefType(const TypedefDecl *Decl, QualType Canonical) const {
+ASTContext::getTypedefType(const TypedefNameDecl *Decl,
+ QualType Canonical) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
if (Canonical.isNull())
@@ -2149,9 +2203,9 @@ QualType ASTContext::getSubstTemplateTypeParmPackType(
/// name.
QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
bool ParameterPack,
- IdentifierInfo *Name) const {
+ TemplateTypeParmDecl *TTPDecl) const {
llvm::FoldingSetNodeID ID;
- TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name);
+ TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, TTPDecl);
void *InsertPos = 0;
TemplateTypeParmType *TypeParm
= TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -2159,10 +2213,9 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
if (TypeParm)
return QualType(TypeParm, 0);
- if (Name) {
+ if (TTPDecl) {
QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack);
- TypeParm = new (*this, TypeAlignment)
- TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon);
+ TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(TTPDecl, Canon);
TemplateTypeParmType *TypeCheck
= TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -2183,6 +2236,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &Args,
QualType CanonType) const {
+ assert(!Name.getAsDependentTemplateName() &&
+ "No dependent template names here!");
QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
@@ -2200,6 +2255,9 @@ QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
QualType Canon) const {
+ assert(!Template.getAsDependentTemplateName() &&
+ "No dependent template names here!");
+
unsigned NumArgs = Args.size();
llvm::SmallVector<TemplateArgument, 4> ArgVec;
@@ -2216,6 +2274,12 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
QualType Canon) const {
+ assert(!Template.getAsDependentTemplateName() &&
+ "No dependent template names here!");
+ // Look through qualified template names.
+ if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Template = TemplateName(QTN->getTemplateDecl());
+
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
else
@@ -2240,6 +2304,12 @@ QualType
ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs) const {
+ assert(!Template.getAsDependentTemplateName() &&
+ "No dependent template names here!");
+ // Look through qualified template names.
+ if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Template = TemplateName(QTN->getTemplateDecl());
+
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
llvm::SmallVector<TemplateArgument, 4> CanonArgs;
@@ -2377,7 +2447,8 @@ ASTContext::getDependentTemplateSpecializationType(
const IdentifierInfo *Name,
unsigned NumArgs,
const TemplateArgument *Args) const {
- assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+ assert((!NNS || NNS->isDependent()) &&
+ "nested-name-specifier must be dependent");
llvm::FoldingSetNodeID ID;
DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS,
@@ -2701,6 +2772,22 @@ QualType ASTContext::getAutoType(QualType DeducedType) const {
return QualType(AT, 0);
}
+/// getAutoDeductType - Get type pattern for deducing against 'auto'.
+QualType ASTContext::getAutoDeductType() const {
+ if (AutoDeductTy.isNull())
+ AutoDeductTy = getAutoType(QualType());
+ assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern");
+ return AutoDeductTy;
+}
+
+/// getAutoRRefDeductType - Get type pattern for deducing against 'auto &&'.
+QualType ASTContext::getAutoRRefDeductType() const {
+ if (AutoRRefDeductTy.isNull())
+ AutoRRefDeductTy = getRValueReferenceType(getAutoDeductType());
+ assert(!AutoRRefDeductTy.isNull() && "can't build 'auto &&' pattern");
+ return AutoRRefDeductTy;
+}
+
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
@@ -3014,10 +3101,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
= T->getAs<DependentTemplateSpecializationType>()) {
NestedNameSpecifier *Prefix
= getCanonicalNestedNameSpecifier(DTST->getQualifier());
- TemplateName Name
- = getDependentTemplateName(Prefix, DTST->getIdentifier());
- T = getTemplateSpecializationType(Name,
- DTST->getArgs(), DTST->getNumArgs());
+
+ T = getDependentTemplateSpecializationType(DTST->getKeyword(),
+ Prefix, DTST->getIdentifier(),
+ DTST->getNumArgs(),
+ DTST->getArgs());
T = getCanonicalType(T);
}
@@ -3334,19 +3422,20 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const {
}
static RecordDecl *
-CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
+CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK,
+ DeclContext *DC, IdentifierInfo *Id) {
+ SourceLocation Loc;
if (Ctx.getLangOptions().CPlusPlus)
- return CXXRecordDecl::Create(Ctx, TK, DC, L, Id);
+ return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
else
- return RecordDecl::Create(Ctx, TK, DC, L, Id);
+ return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
}
-
+
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() const {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("NSConstantString"));
CFConstantStringTypeDecl->startDefinition();
@@ -3364,6 +3453,7 @@ QualType ASTContext::getCFConstantStringType() const {
// Create fields
for (unsigned i = 0; i < 4; ++i) {
FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
@@ -3388,7 +3478,7 @@ void ASTContext::setCFConstantStringType(QualType T) {
QualType ASTContext::getNSConstantStringType() const {
if (!NSConstantStringTypeDecl) {
NSConstantStringTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__builtin_NSString"));
NSConstantStringTypeDecl->startDefinition();
@@ -3404,6 +3494,7 @@ QualType ASTContext::getNSConstantStringType() const {
// Create fields
for (unsigned i = 0; i < 3; ++i) {
FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
@@ -3427,7 +3518,7 @@ void ASTContext::setNSConstantStringType(QualType T) {
QualType ASTContext::getObjCFastEnumerationStateType() const {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__objcFastEnumerationState"));
ObjCFastEnumerationStateTypeDecl->startDefinition();
@@ -3442,6 +3533,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() const {
for (size_t i = 0; i < 4; ++i) {
FieldDecl *Field = FieldDecl::Create(*this,
ObjCFastEnumerationStateTypeDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
@@ -3462,7 +3554,7 @@ QualType ASTContext::getBlockDescriptorType() const {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__block_descriptor"));
T->startDefinition();
@@ -3477,8 +3569,7 @@ QualType ASTContext::getBlockDescriptorType() const {
};
for (size_t i = 0; i < 2; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this,
- T,
+ FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
@@ -3507,7 +3598,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl,
&Idents.get("__block_descriptor_withcopydispose"));
T->startDefinition();
@@ -3526,8 +3617,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
};
for (size_t i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this,
- T,
+ FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
@@ -3586,8 +3676,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
++UniqueBlockByRefTypeID << '_' << DeclName;
RecordDecl *T;
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
- &Idents.get(Name.str()));
+ T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str()));
T->startDefinition();
QualType Int32Ty = IntTy;
assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported");
@@ -3615,6 +3704,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
if (!HasCopyAndDispose && i >=4 && i <= 5)
continue;
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
+ SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
@@ -4367,6 +4457,8 @@ TemplateName
ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateDecl *Template) const {
+ assert(NNS && "Missing nested-name-specifier in qualified template name");
+
// FIXME: Canonicalization?
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
@@ -4503,7 +4595,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
///
bool ASTContext::isObjCNSObjectType(QualType Ty) const {
if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
- if (TypedefDecl *TD = TDT->getDecl())
+ if (TypedefNameDecl *TD = TDT->getDecl())
if (TD->getAttr<ObjCNSObjectAttr>())
return true;
}
@@ -4795,13 +4887,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
}
/// canAssignObjCInterfacesInBlockPointer - This routine is specifically written
-/// for providing type-safty for objective-c pointers used to pass/return
+/// for providing type-safety for objective-c pointers used to pass/return
/// arguments in block literals. When passed as arguments, passing 'A*' where
/// 'id' is expected is not OK. Passing 'Sub *" where 'Super *" is expected is
/// not OK. For the return type, the opposite is not OK.
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
- const ObjCObjectPointerType *RHSOPT) {
+ const ObjCObjectPointerType *RHSOPT,
+ bool BlockReturnType) {
if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType())
return true;
@@ -4819,9 +4912,9 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
if (LHS && RHS) { // We have 2 user-defined types.
if (LHS != RHS) {
if (LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
- return false;
+ return BlockReturnType;
if (RHS->getDecl()->isSuperClassOf(LHS->getDecl()))
- return true;
+ return !BlockReturnType;
}
else
return true;
@@ -4887,10 +4980,10 @@ QualType ASTContext::areCommonBaseCompatible(
const ObjCObjectType *RHS = Rptr->getObjectType();
const ObjCInterfaceDecl* LDecl = LHS->getInterface();
const ObjCInterfaceDecl* RDecl = RHS->getInterface();
- if (!LDecl || !RDecl)
+ if (!LDecl || !RDecl || (LDecl == RDecl))
return QualType();
- while ((LDecl = LDecl->getSuperClass())) {
+ do {
LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl));
if (canAssignObjCInterfaces(LHS, RHS)) {
llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols;
@@ -4902,7 +4995,7 @@ QualType ASTContext::areCommonBaseCompatible(
Result = getObjCObjectPointerType(Result);
return Result;
}
- }
+ } while ((LDecl = LDecl->getSuperClass()));
return QualType();
}
@@ -4922,10 +5015,47 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
if (LHS->getNumProtocols() == 0)
return true;
- // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it
- // isn't a superset.
- if (RHS->getNumProtocols() == 0)
- return true; // FIXME: should return false!
+ // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't,
+ // more detailed analysis is required.
+ if (RHS->getNumProtocols() == 0) {
+ // OK, if LHS is a superclass of RHS *and*
+ // this superclass is assignment compatible with LHS.
+ // false otherwise.
+ bool IsSuperClass =
+ LHS->getInterface()->isSuperClassOf(RHS->getInterface());
+ if (IsSuperClass) {
+ // OK if conversion of LHS to SuperClass results in narrowing of types
+ // ; i.e., SuperClass may implement at least one of the protocols
+ // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok.
+ // But not SuperObj<P1,P2,P3> = lhs<P1,P2>.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols;
+ CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols);
+ // If super class has no protocols, it is not a match.
+ if (SuperClassInheritedProtocols.empty())
+ return false;
+
+ for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
+ LHSPE = LHS->qual_end();
+ LHSPI != LHSPE; LHSPI++) {
+ bool SuperImplementsProtocol = false;
+ ObjCProtocolDecl *LHSProto = (*LHSPI);
+
+ for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
+ SuperClassInheritedProtocols.begin(),
+ E = SuperClassInheritedProtocols.end(); I != E; ++I) {
+ ObjCProtocolDecl *SuperClassProto = (*I);
+ if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) {
+ SuperImplementsProtocol = true;
+ break;
+ }
+ }
+ if (!SuperImplementsProtocol)
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
LHSPE = LHS->qual_end();
@@ -5045,7 +5175,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool UnqualifiedResult = Unqualified;
if (!UnqualifiedResult)
UnqualifiedResult = (!RHS.hasQualifiers() && LHS.hasQualifiers());
- retType = mergeTypes(RHS, LHS, true, UnqualifiedResult);
+ retType = mergeTypes(LHS, RHS, true, UnqualifiedResult, true);
}
else
retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), false,
@@ -5079,6 +5209,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return QualType();
// Regparm is part of the calling convention.
+ if (lbaseInfo.getHasRegParm() != rbaseInfo.getHasRegParm())
+ return QualType();
if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm())
return QualType();
@@ -5091,6 +5223,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
allRTypes = false;
FunctionType::ExtInfo einfo(NoReturn,
+ lbaseInfo.getHasRegParm(),
lbaseInfo.getRegParm(),
lbaseInfo.getCC());
@@ -5185,7 +5318,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool OfBlockPointer,
- bool Unqualified) {
+ bool Unqualified, bool BlockReturnType) {
// C++ [expr]: If an expression initially has the type "reference to T", the
// type is adjusted to "T" prior to any further analysis, the expression
// designates the object or function denoted by the reference, and the
@@ -5419,7 +5552,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
if (OfBlockPointer) {
if (canAssignObjCInterfacesInBlockPointer(
LHS->getAs<ObjCObjectPointerType>(),
- RHS->getAs<ObjCObjectPointerType>()))
+ RHS->getAs<ObjCObjectPointerType>(),
+ BlockReturnType))
return LHS;
return QualType();
}
@@ -5557,10 +5691,6 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
}
}
-ExternalASTSource::~ExternalASTSource() { }
-
-void ExternalASTSource::PrintStats() { }
-
ASTMutationListener::~ASTMutationListener() { }
@@ -6015,3 +6145,19 @@ MangleContext *ASTContext::createMangleContext() {
}
CXXABI::~CXXABI() {}
+
+size_t ASTContext::getSideTableAllocatedMemory() const {
+ size_t bytes = 0;
+ bytes += ASTRecordLayouts.getMemorySize();
+ bytes += ObjCLayouts.getMemorySize();
+ bytes += KeyFunctions.getMemorySize();
+ bytes += ObjCImpls.getMemorySize();
+ bytes += BlockVarCopyInits.getMemorySize();
+ bytes += DeclAttrs.getMemorySize();
+ bytes += InstantiatedFromStaticDataMember.getMemorySize();
+ bytes += InstantiatedFromUsingDecl.getMemorySize();
+ bytes += InstantiatedFromUsingShadowDecl.getMemorySize();
+ bytes += InstantiatedFromUnnamedFieldDecl.getMemorySize();
+ return bytes;
+}
+
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 5bf8a38199b6..897b4a4c1f27 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -43,6 +43,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
QT = ST->desugar();
continue;
}
+ // ...or an attributed type...
+ if (const AttributedType *AT = dyn_cast<AttributedType>(Ty)) {
+ QT = AT->desugar();
+ continue;
+ }
// ... or an auto type.
if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
if (!AT->isSugared())
@@ -95,7 +100,7 @@ break; \
// Don't desugar through the primary typedef of an anonymous type.
if (const TagType *UTT = Underlying->getAs<TagType>())
if (const TypedefType *QTT = dyn_cast<TypedefType>(QT))
- if (UTT->getDecl()->getTypedefForAnonDecl() == QTT->getDecl())
+ if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl())
break;
// Record that we actually looked through an opaque type here.
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 21f10fb7ad99..dc881ba86960 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -97,7 +97,9 @@ namespace {
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
+ Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias);
Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitRecordDecl(RecordDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
@@ -139,7 +141,7 @@ namespace {
Expr *VisitCharacterLiteral(CharacterLiteral *E);
Expr *VisitParenExpr(ParenExpr *E);
Expr *VisitUnaryOperator(UnaryOperator *E);
- Expr *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
Expr *VisitBinaryOperator(BinaryOperator *E);
Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E);
Expr *VisitImplicitCastExpr(ImplicitCastExpr *E);
@@ -521,16 +523,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
if (Proto1->isVariadic() != Proto2->isVariadic())
return false;
- if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec())
+ if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())
return false;
- if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec())
- return false;
- if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
- return false;
- for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (Proto1->getExceptionSpecType() == EST_Dynamic) {
+ if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Proto1->getExceptionType(I),
+ Proto2->getExceptionType(I)))
+ return false;
+ }
+ } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
if (!IsStructurallyEquivalent(Context,
- Proto1->getExceptionType(I),
- Proto2->getExceptionType(I)))
+ Proto1->getNoexceptExpr(),
+ Proto2->getNoexceptExpr()))
return false;
}
if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
@@ -830,7 +837,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
// If one is a class template specialization and the other is not, these
- // structures are diferent.
+ // structures are different.
else if (Spec1 || Spec2)
return false;
@@ -1189,11 +1196,11 @@ bool StructuralEquivalenceContext::Finish() {
if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
// Check for equivalent structure names.
IdentifierInfo *Name1 = Record1->getIdentifier();
- if (!Name1 && Record1->getTypedefForAnonDecl())
- Name1 = Record1->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name1 && Record1->getTypedefNameForAnonDecl())
+ Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier();
IdentifierInfo *Name2 = Record2->getIdentifier();
- if (!Name2 && Record2->getTypedefForAnonDecl())
- Name2 = Record2->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name2 && Record2->getTypedefNameForAnonDecl())
+ Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier();
if (!::IsStructurallyEquivalent(Name1, Name2) ||
!::IsStructurallyEquivalent(*this, Record1, Record2))
Equivalent = false;
@@ -1205,11 +1212,11 @@ bool StructuralEquivalenceContext::Finish() {
if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
// Check for equivalent enum names.
IdentifierInfo *Name1 = Enum1->getIdentifier();
- if (!Name1 && Enum1->getTypedefForAnonDecl())
- Name1 = Enum1->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name1 && Enum1->getTypedefNameForAnonDecl())
+ Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier();
IdentifierInfo *Name2 = Enum2->getIdentifier();
- if (!Name2 && Enum2->getTypedefForAnonDecl())
- Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier();
+ if (!Name2 && Enum2->getTypedefNameForAnonDecl())
+ Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier();
if (!::IsStructurallyEquivalent(Name1, Name2) ||
!::IsStructurallyEquivalent(*this, Enum1, Enum2))
Equivalent = false;
@@ -1217,8 +1224,8 @@ bool StructuralEquivalenceContext::Finish() {
// Enum/non-enum mismatch
Equivalent = false;
}
- } else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) {
- if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) {
+ } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
+ if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
Typedef2->getIdentifier()) ||
!::IsStructurallyEquivalent(*this,
@@ -1355,6 +1362,8 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
+ case BuiltinType::UnknownAny: return Importer.getToContext().UnknownAnyTy;
+ case BuiltinType::BoundMember: return Importer.getToContext().BoundMemberTy;
case BuiltinType::ObjCId:
// FIXME: Make sure that the "to" context supports Objective-C!
@@ -1530,8 +1539,8 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
}
QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
- TypedefDecl *ToDecl
- = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl()));
+ TypedefNameDecl *ToDecl
+ = dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl()));
if (!ToDecl)
return QualType();
@@ -1967,8 +1976,9 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
// Create the "to" namespace, if needed.
NamespaceDecl *ToNamespace = MergeWithNamespace;
if (!ToNamespace) {
- ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo());
+ ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getLocStart()),
+ Loc, Name.getAsIdentifierInfo());
ToNamespace->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(ToNamespace);
@@ -1988,7 +1998,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
return ToNamespace;
}
-Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
+Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
// Import the major distinguishing characteristics of this typedef.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -2007,7 +2017,8 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
++Lookup.first) {
if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
continue;
- if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) {
+ if (TypedefNameDecl *FoundTypedef =
+ dyn_cast<TypedefNameDecl>(*Lookup.first)) {
if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(),
FoundTypedef->getUnderlyingType()))
return Importer.Imported(D, FoundTypedef);
@@ -2032,9 +2043,18 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
// Create the new typedef node.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
- TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
- Loc, Name.getAsIdentifierInfo(),
- TInfo);
+ SourceLocation StartL = Importer.Import(D->getLocStart());
+ TypedefNameDecl *ToTypedef;
+ if (IsAlias)
+ ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
+ StartL, Loc,
+ Name.getAsIdentifierInfo(),
+ TInfo);
+ else
+ ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC,
+ StartL, Loc,
+ Name.getAsIdentifierInfo(),
+ TInfo);
ToTypedef->setAccess(D->getAccess());
ToTypedef->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToTypedef);
@@ -2043,6 +2063,14 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
return ToTypedef;
}
+Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
+ return VisitTypedefNameDecl(D, /*IsAlias=*/false);
+}
+
+Decl *ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ return VisitTypedefNameDecl(D, /*IsAlias=*/true);
+}
+
Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// Import the major distinguishing characteristics of this enum.
DeclContext *DC, *LexicalDC;
@@ -2054,8 +2082,8 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// Figure out what enum name we're looking for.
unsigned IDNS = Decl::IDNS_Tag;
DeclarationName SearchName = Name;
- if (!SearchName && D->getTypedefForAnonDecl()) {
- SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName());
+ if (!SearchName && D->getTypedefNameForAnonDecl()) {
+ SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName());
IDNS = Decl::IDNS_Ordinary;
} else if (Importer.getToContext().getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Ordinary;
@@ -2070,7 +2098,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
continue;
Decl *Found = *Lookup.first;
- if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) {
if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
Found = Tag->getDecl();
}
@@ -2091,9 +2119,9 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
}
// Create the enum declaration.
- EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getTagKeywordLoc()), 0,
+ EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getLocStart()),
+ Loc, Name.getAsIdentifierInfo(), 0,
D->isScoped(), D->isScopedUsingClassTag(),
D->isFixed());
// Import the qualifier, if any.
@@ -2155,8 +2183,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// Figure out what structure name we're looking for.
unsigned IDNS = Decl::IDNS_Tag;
DeclarationName SearchName = Name;
- if (!SearchName && D->getTypedefForAnonDecl()) {
- SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName());
+ if (!SearchName && D->getTypedefNameForAnonDecl()) {
+ SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName());
IDNS = Decl::IDNS_Ordinary;
} else if (Importer.getToContext().getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Ordinary;
@@ -2172,7 +2200,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
continue;
Decl *Found = *Lookup.first;
- if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) {
if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
Found = Tag->getDecl();
}
@@ -2206,20 +2234,18 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// Create the record declaration.
RecordDecl *D2 = AdoptDecl;
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
if (!D2) {
if (isa<CXXRecordDecl>(D)) {
CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(),
D->getTagKind(),
- DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getTagKeywordLoc()));
+ DC, StartLoc, Loc,
+ Name.getAsIdentifierInfo());
D2 = D2CXX;
D2->setAccess(D->getAccess());
} else {
D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(),
- DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getTagKeywordLoc()));
+ DC, StartLoc, Loc, Name.getAsIdentifierInfo());
}
D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
@@ -2367,6 +2393,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
ToFunction = CXXConstructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
FromConstructor->isExplicit(),
D->isInlineSpecified(),
@@ -2374,6 +2401,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
} else if (isa<CXXDestructorDecl>(D)) {
ToFunction = CXXDestructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
D->isInlineSpecified(),
D->isImplicit());
@@ -2381,18 +2409,23 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
= dyn_cast<CXXConversionDecl>(D)) {
ToFunction = CXXConversionDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
D->isInlineSpecified(),
- FromConversion->isExplicit());
+ FromConversion->isExplicit(),
+ Importer.Import(D->getLocEnd()));
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
ToFunction = CXXMethodDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
+ D->getInnerLocStart(),
NameInfo, T, TInfo,
Method->isStatic(),
Method->getStorageClassAsWritten(),
- Method->isInlineSpecified());
+ Method->isInlineSpecified(),
+ Importer.Import(D->getLocEnd()));
} else {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
+ D->getInnerLocStart(),
NameInfo, T, TInfo, D->getStorageClass(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
@@ -2457,7 +2490,8 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
if (!BitWidth && D->getBitWidth())
return 0;
- FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
+ FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, BitWidth, D->isMutable());
ToField->setAccess(D->getAccess());
@@ -2542,6 +2576,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
ObjCIvarDecl *ToIvar = ObjCIvarDecl::Create(Importer.getToContext(),
cast<ObjCContainerDecl>(DC),
+ Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getAccessControl(),
BitWidth, D->getSynthesize());
@@ -2650,8 +2685,10 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Create the imported variable.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
- VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo(), T, TInfo,
+ VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getInnerLocStart()),
+ Loc, Name.getAsIdentifierInfo(),
+ T, TInfo,
D->getStorageClass(),
D->getStorageClassAsWritten());
ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
@@ -2718,6 +2755,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
// Create the imported parameter.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
D->getStorageClassAsWritten(),
@@ -3444,6 +3482,7 @@ Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
// FIXME: Import default argument.
return TemplateTypeParmDecl::Create(Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
+ Importer.Import(D->getLocStart()),
Importer.Import(D->getLocation()),
D->getDepth(),
D->getIndex(),
@@ -3476,6 +3515,7 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
return NonTypeTemplateParmDecl::Create(Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
+ Importer.Import(D->getInnerLocStart()),
Loc, D->getDepth(), D->getPosition(),
Name.getAsIdentifierInfo(),
T, D->isParameterPack(), TInfo);
@@ -3567,12 +3607,12 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
CXXRecordDecl *DTemplated = D->getTemplatedDecl();
// Create the declaration that is being templated.
+ SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
+ SourceLocation IdLoc = Importer.Import(DTemplated->getLocation());
CXXRecordDecl *D2Templated = CXXRecordDecl::Create(Importer.getToContext(),
DTemplated->getTagKind(),
- DC,
- Importer.Import(DTemplated->getLocation()),
- Name.getAsIdentifierInfo(),
- Importer.Import(DTemplated->getTagKeywordLoc()));
+ DC, StartLoc, IdLoc,
+ Name.getAsIdentifierInfo());
D2Templated->setAccess(DTemplated->getAccess());
D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
D2Templated->setLexicalDeclContext(LexicalDC);
@@ -3637,7 +3677,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
}
// Import the location of this declaration.
- SourceLocation Loc = Importer.Import(D->getLocation());
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
+ SourceLocation IdLoc = Importer.Import(D->getLocation());
// Import template arguments.
llvm::SmallVector<TemplateArgument, 2> TemplateArgs;
@@ -3669,7 +3710,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Create a new specialization.
D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(),
D->getTagKind(), DC,
- Loc, ClassTemplate,
+ StartLoc, IdLoc,
+ ClassTemplate,
TemplateArgs.data(),
TemplateArgs.size(),
/*PrevDecl=*/0);
@@ -3713,26 +3755,27 @@ Expr *ASTNodeImporter::VisitExpr(Expr *E) {
}
Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
- NestedNameSpecifier *Qualifier = 0;
- if (E->getQualifier()) {
- Qualifier = Importer.Import(E->getQualifier());
- if (!E->getQualifier())
- return 0;
- }
-
ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl()));
if (!ToD)
return 0;
+
+ NamedDecl *FoundD = 0;
+ if (E->getDecl() != E->getFoundDecl()) {
+ FoundD = cast_or_null<NamedDecl>(Importer.Import(E->getFoundDecl()));
+ if (!FoundD)
+ return 0;
+ }
QualType T = Importer.Import(E->getType());
if (T.isNull())
return 0;
- return DeclRefExpr::Create(Importer.getToContext(), Qualifier,
- Importer.Import(E->getQualifierRange()),
+ return DeclRefExpr::Create(Importer.getToContext(),
+ Importer.Import(E->getQualifierLoc()),
ToD,
Importer.Import(E->getLocation()),
T, E->getValueKind(),
+ FoundD,
/*FIXME:TemplateArgs=*/0);
}
@@ -3782,7 +3825,8 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
Importer.Import(E->getOperatorLoc()));
}
-Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *E) {
QualType ResultType = Importer.Import(E->getType());
if (E->isArgumentType()) {
@@ -3790,8 +3834,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (!TInfo)
return 0;
- return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(),
- TInfo, ResultType,
+ return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
+ TInfo, ResultType,
Importer.Import(E->getOperatorLoc()),
Importer.Import(E->getRParenLoc()));
}
@@ -3800,8 +3844,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (!SubExpr)
return 0;
- return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(),
- SubExpr, ResultType,
+ return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
+ SubExpr, ResultType,
Importer.Import(E->getOperatorLoc()),
Importer.Import(E->getRParenLoc()));
}
@@ -3854,7 +3898,7 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
Importer.Import(E->getOperatorLoc()));
}
-bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
+static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
if (E->path_empty()) return false;
// TODO: import cast paths
@@ -3973,19 +4017,19 @@ Decl *ASTImporter::Import(Decl *FromD) {
if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) {
// Keep track of anonymous tags that have an associated typedef.
- if (FromTag->getTypedefForAnonDecl())
+ if (FromTag->getTypedefNameForAnonDecl())
AnonTagsWithPendingTypedefs.push_back(FromTag);
- } else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(FromD)) {
+ } else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) {
// When we've finished transforming a typedef, see whether it was the
// typedef for an anonymous tag.
for (llvm::SmallVector<TagDecl *, 4>::iterator
FromTag = AnonTagsWithPendingTypedefs.begin(),
FromTagEnd = AnonTagsWithPendingTypedefs.end();
FromTag != FromTagEnd; ++FromTag) {
- if ((*FromTag)->getTypedefForAnonDecl() == FromTypedef) {
+ if ((*FromTag)->getTypedefNameForAnonDecl() == FromTypedef) {
if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) {
// We found the typedef for an anonymous tag; link them.
- ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD));
+ ToTag->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToD));
AnonTagsWithPendingTypedefs.erase(FromTag);
break;
}
@@ -4034,7 +4078,46 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
if (!FromNNS)
return 0;
- // FIXME: Implement!
+ NestedNameSpecifier *prefix = Import(FromNNS->getPrefix());
+
+ switch (FromNNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) {
+ return NestedNameSpecifier::Create(ToContext, prefix, II);
+ }
+ return 0;
+
+ case NestedNameSpecifier::Namespace:
+ if (NamespaceDecl *NS =
+ cast<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
+ return NestedNameSpecifier::Create(ToContext, prefix, NS);
+ }
+ return 0;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ if (NamespaceAliasDecl *NSAD =
+ cast<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
+ return NestedNameSpecifier::Create(ToContext, prefix, NSAD);
+ }
+ return 0;
+
+ case NestedNameSpecifier::Global:
+ return NestedNameSpecifier::GlobalSpecifier(ToContext);
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ QualType T = Import(QualType(FromNNS->getAsType(), 0u));
+ if (!T.isNull()) {
+ bool bTemplate = FromNNS->getKind() ==
+ NestedNameSpecifier::TypeSpecWithTemplate;
+ return NestedNameSpecifier::Create(ToContext, prefix,
+ bTemplate, T.getTypePtr());
+ }
+ }
+ return 0;
+ }
+
+ llvm_unreachable("Invalid nested name specifier kind");
return 0;
}
@@ -4156,12 +4239,12 @@ FileID ASTImporter::Import(FileID FromID) {
// Map the FileID for to the "to" source manager.
FileID ToID;
const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache();
- if (Cache->Entry) {
+ if (Cache->OrigEntry) {
// FIXME: We probably want to use getVirtualFile(), so we don't hit the
// disk again
// FIXME: We definitely want to re-use the existing MemoryBuffer, rather
// than mmap the files several times.
- const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName());
+ const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName());
ToID = ToSM.createFileID(Entry, ToIncludeLoc,
FromSLoc.getFile().getFileCharacteristic());
} else {
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 9fe18407a839..63583a02bfd1 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangAST
ExprClassification.cpp
ExprConstant.cpp
ExprCXX.cpp
+ ExternalASTSource.cpp
InheritViz.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index ca9ec18b3997..9ffe1f865689 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -415,7 +415,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
Path.Decls.first != Path.Decls.second;
++Path.Decls.first) {
// FIXME: Refactor the "is it a nested-name-specifier?" check
- if (isa<TypedefDecl>(*Path.Decls.first) ||
+ if (isa<TypedefNameDecl>(*Path.Decls.first) ||
(*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
return true;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 73fe117b1e4e..b21ba9a65e76 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -25,6 +25,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -33,53 +34,33 @@ using namespace clang;
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
-static const VisibilityAttr *GetExplicitVisibility(const Decl *d) {
- // Use the most recent declaration of a variable.
- if (const VarDecl *var = dyn_cast<VarDecl>(d))
- return var->getMostRecentDeclaration()->getAttr<VisibilityAttr>();
-
- // Use the most recent declaration of a function, and also handle
- // function template specializations.
- if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(d)) {
- if (const VisibilityAttr *attr
- = fn->getMostRecentDeclaration()->getAttr<VisibilityAttr>())
- return attr;
-
- // If the function is a specialization of a template with an
- // explicit visibility attribute, use that.
- if (FunctionTemplateSpecializationInfo *templateInfo
- = fn->getTemplateSpecializationInfo())
- return templateInfo->getTemplate()->getTemplatedDecl()
- ->getAttr<VisibilityAttr>();
+static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
+ // If this declaration has an explicit visibility attribute, use it.
+ if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) {
+ switch (A->getVisibility()) {
+ case VisibilityAttr::Default:
+ return DefaultVisibility;
+ case VisibilityAttr::Hidden:
+ return HiddenVisibility;
+ case VisibilityAttr::Protected:
+ return ProtectedVisibility;
+ }
- return 0;
+ return DefaultVisibility;
}
- // Otherwise, just check the declaration itself first.
- if (const VisibilityAttr *attr = d->getAttr<VisibilityAttr>())
- return attr;
-
- // If there wasn't explicit visibility there, and this is a
- // specialization of a class template, check for visibility
- // on the pattern.
- if (const ClassTemplateSpecializationDecl *spec
- = dyn_cast<ClassTemplateSpecializationDecl>(d))
- return spec->getSpecializedTemplate()->getTemplatedDecl()
- ->getAttr<VisibilityAttr>();
-
- return 0;
-}
-
-static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) {
- switch (A->getVisibility()) {
- case VisibilityAttr::Default:
- return DefaultVisibility;
- case VisibilityAttr::Hidden:
- return HiddenVisibility;
- case VisibilityAttr::Protected:
- return ProtectedVisibility;
+ // If we're on Mac OS X, an 'availability' for Mac OS X attribute
+ // implies visibility(default).
+ if (D->getASTContext().Target.getTriple().isOSDarwin()) {
+ for (specific_attr_iterator<AvailabilityAttr>
+ A = D->specific_attr_begin<AvailabilityAttr>(),
+ AEnd = D->specific_attr_end<AvailabilityAttr>();
+ A != AEnd; ++A)
+ if ((*A)->getPlatform()->getName().equals("macosx"))
+ return DefaultVisibility;
}
- return DefaultVisibility;
+
+ return llvm::Optional<Visibility>();
}
typedef NamedDecl::LinkageInfo LinkageInfo;
@@ -100,9 +81,11 @@ namespace {
struct LVFlags {
bool ConsiderGlobalVisibility;
bool ConsiderVisibilityAttributes;
+ bool ConsiderTemplateParameterTypes;
LVFlags() : ConsiderGlobalVisibility(true),
- ConsiderVisibilityAttributes(true) {
+ ConsiderVisibilityAttributes(true),
+ ConsiderTemplateParameterTypes(true) {
}
/// \brief Returns a set of flags that is only useful for computing the
@@ -111,6 +94,7 @@ struct LVFlags {
LVFlags F;
F.ConsiderGlobalVisibility = false;
F.ConsiderVisibilityAttributes = false;
+ F.ConsiderTemplateParameterTypes = false;
return F;
}
@@ -120,6 +104,7 @@ struct LVFlags {
LVFlags F = *this;
F.ConsiderGlobalVisibility = false;
F.ConsiderVisibilityAttributes = false;
+ F.ConsiderTemplateParameterTypes = false;
return F;
}
};
@@ -282,8 +267,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
LinkageInfo LV;
if (F.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
- LV.setVisibility(GetVisibilityFromAttr(VA), true);
+ if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ LV.setVisibility(*Vis, true);
F.ConsiderGlobalVisibility = false;
} else {
// If we're declared in a namespace with a visibility attribute,
@@ -292,9 +277,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
!isa<TranslationUnitDecl>(DC);
DC = DC->getParent()) {
if (!isa<NamespaceDecl>(DC)) continue;
- if (const VisibilityAttr *VA =
- cast<NamespaceDecl>(DC)->getAttr<VisibilityAttr>()) {
- LV.setVisibility(GetVisibilityFromAttr(VA), false);
+ if (llvm::Optional<Visibility> Vis
+ = cast<NamespaceDecl>(DC)->getExplicitVisibility()) {
+ LV.setVisibility(*Vis, false);
F.ConsiderGlobalVisibility = false;
break;
}
@@ -420,7 +405,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// has the typedef name for linkage purposes (7.1.3); or
} else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
// Unnamed tags have no linkage.
- if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl())
+ if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl())
return LinkageInfo::none();
// If this is a class template specialization, consider the
@@ -451,8 +436,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
- } else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
- LV.merge(getLVForTemplateParameterList(Template->getTemplateParameters()));
+ } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
+ if (F.ConsiderTemplateParameterTypes)
+ LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters()));
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
@@ -491,7 +477,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
(isa<TagDecl>(D) &&
- (D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl()))))
+ (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl()))))
return LinkageInfo::none();
LinkageInfo LV;
@@ -501,8 +487,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
// If we have an explicit visibility attribute, merge that in.
if (F.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
- LV.mergeVisibility(GetVisibilityFromAttr(VA), true);
+ if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ LV.mergeVisibility(*Vis, true);
// Ignore global visibility later, but not this attribute.
F.ConsiderGlobalVisibility = false;
@@ -536,7 +522,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
if (FunctionTemplateSpecializationInfo *Spec
= MD->getTemplateSpecializationInfo()) {
LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F));
- LV.merge(getLVForTemplateParameterList(
+ if (F.ConsiderTemplateParameterTypes)
+ LV.merge(getLVForTemplateParameterList(
Spec->getTemplate()->getTemplateParameters()));
TSK = Spec->getTemplateSpecializationKind();
@@ -571,7 +558,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
// Merge template argument/parameter information for member
// class template specializations.
LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F));
- LV.merge(getLVForTemplateParameterList(
+ if (F.ConsiderTemplateParameterTypes)
+ LV.merge(getLVForTemplateParameterList(
Spec->getSpecializedTemplate()->getTemplateParameters()));
}
@@ -632,10 +620,12 @@ void NamedDecl::ClearLinkageCache() {
// Clear cached linkage for function template decls, too.
if (FunctionTemplateDecl *temp =
- dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this)))
+ dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) {
+ temp->getTemplatedDecl()->ClearLinkageCache();
for (FunctionTemplateDecl::spec_iterator
i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
i->ClearLinkageCache();
+ }
}
@@ -660,6 +650,41 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const {
return LI;
}
+llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
+ // Use the most recent declaration of a variable.
+ if (const VarDecl *var = dyn_cast<VarDecl>(this))
+ return getVisibilityOf(var->getMostRecentDeclaration());
+
+ // Use the most recent declaration of a function, and also handle
+ // function template specializations.
+ if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
+ if (llvm::Optional<Visibility> V
+ = getVisibilityOf(fn->getMostRecentDeclaration()))
+ return V;
+
+ // If the function is a specialization of a template with an
+ // explicit visibility attribute, use that.
+ if (FunctionTemplateSpecializationInfo *templateInfo
+ = fn->getTemplateSpecializationInfo())
+ return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+
+ return llvm::Optional<Visibility>();
+ }
+
+ // Otherwise, just check the declaration itself first.
+ if (llvm::Optional<Visibility> V = getVisibilityOf(this))
+ return V;
+
+ // If there wasn't explicit visibility there, and this is a
+ // specialization of a class template, check for visibility
+ // on the pattern.
+ if (const ClassTemplateSpecializationDecl *spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
+
+ return llvm::Optional<Visibility>();
+}
+
static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
@@ -713,8 +738,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
LinkageInfo LV;
if (Flags.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(Function))
- LV.setVisibility(GetVisibilityFromAttr(VA));
+ if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
+ LV.setVisibility(*Vis);
}
if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) {
@@ -736,8 +761,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
if (Var->getStorageClass() == SC_PrivateExtern)
LV.setVisibility(HiddenVisibility);
else if (Flags.ConsiderVisibilityAttributes) {
- if (const VisibilityAttr *VA = GetExplicitVisibility(Var))
- LV.setVisibility(GetVisibilityFromAttr(VA));
+ if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
+ LV.setVisibility(*Vis);
}
if (const VarDecl *Prev = Var->getPreviousDeclaration()) {
@@ -954,28 +979,97 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
if (hasExtInfo()) {
- // Save type source info pointer.
- TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
- // Deallocate the extended decl info.
- getASTContext().Deallocate(getExtInfo());
- // Restore savedTInfo into (non-extended) decl info.
- DeclInfo = savedTInfo;
+ if (getExtInfo()->NumTemplParamLists == 0) {
+ // Save type source info pointer.
+ TypeSourceInfo *savedTInfo = getExtInfo()->TInfo;
+ // Deallocate the extended decl info.
+ getASTContext().Deallocate(getExtInfo());
+ // Restore savedTInfo into (non-extended) decl info.
+ DeclInfo = savedTInfo;
+ }
+ else
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
}
}
+void
+DeclaratorDecl::setTemplateParameterListsInfo(ASTContext &Context,
+ unsigned NumTPLists,
+ TemplateParameterList **TPLists) {
+ assert(NumTPLists > 0);
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo()) {
+ // Save (non-extended) type source info pointer.
+ TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+ // Allocate external info struct.
+ DeclInfo = new (getASTContext()) ExtInfo;
+ // Restore savedTInfo into (extended) decl info.
+ getExtInfo()->TInfo = savedTInfo;
+ }
+ // Set the template parameter lists info.
+ getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
+}
+
SourceLocation DeclaratorDecl::getOuterLocStart() const {
return getTemplateOrInnerLocStart(this);
}
+namespace {
+
+// Helper function: returns true if QT is or contains a type
+// having a postfix component.
+bool typeIsPostfix(clang::QualType QT) {
+ while (true) {
+ const Type* T = QT.getTypePtr();
+ switch (T->getTypeClass()) {
+ default:
+ return false;
+ case Type::Pointer:
+ QT = cast<PointerType>(T)->getPointeeType();
+ break;
+ case Type::BlockPointer:
+ QT = cast<BlockPointerType>(T)->getPointeeType();
+ break;
+ case Type::MemberPointer:
+ QT = cast<MemberPointerType>(T)->getPointeeType();
+ break;
+ case Type::LValueReference:
+ case Type::RValueReference:
+ QT = cast<ReferenceType>(T)->getPointeeType();
+ break;
+ case Type::PackExpansion:
+ QT = cast<PackExpansionType>(T)->getPattern();
+ break;
+ case Type::Paren:
+ case Type::ConstantArray:
+ case Type::DependentSizedArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ return true;
+ }
+ }
+}
+
+} // namespace
+
+SourceRange DeclaratorDecl::getSourceRange() const {
+ SourceLocation RangeEnd = getLocation();
+ if (TypeSourceInfo *TInfo = getTypeSourceInfo()) {
+ if (typeIsPostfix(TInfo->getType()))
+ RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd();
+ }
+ return SourceRange(getOuterLocStart(), RangeEnd);
+}
+
void
QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context,
unsigned NumTPLists,
TemplateParameterList **TPLists) {
assert((NumTPLists == 0 || TPLists != 0) &&
"Empty array of template parameters with positive size!");
- assert((NumTPLists == 0 || QualifierLoc) &&
- "Nonempty array of template parameters with no qualifier!");
// Free previous template parameters (if any).
if (NumTemplParamLists > 0) {
@@ -1010,10 +1104,11 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
return 0;
}
-VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten) {
- return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten);
+ return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten);
}
void VarDecl::setStorageClass(StorageClass SC) {
@@ -1021,20 +1116,13 @@ void VarDecl::setStorageClass(StorageClass SC) {
if (getStorageClass() != SC)
ClearLinkageCache();
- SClass = SC;
-}
-
-SourceLocation VarDecl::getInnerLocStart() const {
- SourceLocation Start = getTypeSpecStartLoc();
- if (Start.isInvalid())
- Start = getLocation();
- return Start;
+ VarDeclBits.SClass = SC;
}
SourceRange VarDecl::getSourceRange() const {
if (getInit())
return SourceRange(getOuterLocStart(), getInit()->getLocEnd());
- return SourceRange(getOuterLocStart(), getLocation());
+ return DeclaratorDecl::getSourceRange();
}
bool VarDecl::isExternC() const {
@@ -1250,11 +1338,12 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
//===----------------------------------------------------------------------===//
ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten,
Expr *DefArg) {
- return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo,
+ return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo,
S, SCAsWritten, DefArg);
}
@@ -1324,7 +1413,7 @@ bool FunctionDecl::isVariadic() const {
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->Body) {
+ if (I->Body || I->IsLateTemplateParsed) {
Definition = *I;
return true;
}
@@ -1338,6 +1427,9 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
if (I->Body) {
Definition = *I;
return I->Body.get(getASTContext().getExternalSource());
+ } else if (I->IsLateTemplateParsed) {
+ Definition = *I;
+ return 0;
}
}
@@ -1804,7 +1896,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
// Insert this function template specialization into the set of known
// function template specializations.
if (InsertPos)
- Template->getSpecializations().InsertNode(Info, InsertPos);
+ Template->addSpecialization(Info, InsertPos);
else {
// Try to insert the new node. If there is an existing node, leave it, the
// set will contain the canonical decls while
@@ -1925,14 +2017,20 @@ bool FunctionDecl::isOutOfLine() const {
return false;
}
+SourceRange FunctionDecl::getSourceRange() const {
+ return SourceRange(getOuterLocStart(), EndRangeLoc);
+}
+
//===----------------------------------------------------------------------===//
// FieldDecl Implementation
//===----------------------------------------------------------------------===//
FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id, QualType T,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
- return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
+ return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
+ BW, Mutable);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
@@ -1949,13 +2047,25 @@ unsigned FieldDecl::getFieldIndex() const {
if (CachedFieldIndex) return CachedFieldIndex - 1;
unsigned index = 0;
- RecordDecl::field_iterator
- i = getParent()->field_begin(), e = getParent()->field_end();
+ const RecordDecl *RD = getParent();
+ const FieldDecl *LastFD = 0;
+ bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+
+ RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
while (true) {
assert(i != e && "failed to find field in parent!");
if (*i == this)
break;
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are ignored.
+ if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD) ||
+ getASTContext().ZeroBitfieldFollowsBitfield((*i), LastFD)) {
+ ++i;
+ continue;
+ }
+ LastFD = (*i);
+ }
++i;
++index;
}
@@ -1964,6 +2074,12 @@ unsigned FieldDecl::getFieldIndex() const {
return index;
}
+SourceRange FieldDecl::getSourceRange() const {
+ if (isBitField())
+ return SourceRange(getInnerLocStart(), BitWidth->getLocEnd());
+ return DeclaratorDecl::getSourceRange();
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1981,8 +2097,8 @@ TagDecl* TagDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) {
- TypedefDeclOrQualifier = TDD;
+void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
+ TypedefNameDeclOrQualifier = TDD;
if (TypeForDecl)
const_cast<Type*>(TypeForDecl)->ClearLinkageCache();
ClearLinkageCache();
@@ -2030,35 +2146,52 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (QualifierLoc) {
// Make sure the extended qualifier info is allocated.
if (!hasExtInfo())
- TypedefDeclOrQualifier = new (getASTContext()) ExtInfo;
+ TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
}
else {
// Here Qualifier == 0, i.e., we are removing the qualifier (if any).
if (hasExtInfo()) {
- getASTContext().Deallocate(getExtInfo());
- TypedefDeclOrQualifier = (TypedefDecl*) 0;
+ if (getExtInfo()->NumTemplParamLists == 0) {
+ getASTContext().Deallocate(getExtInfo());
+ TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0;
+ }
+ else
+ getExtInfo()->QualifierLoc = QualifierLoc;
}
}
}
+void TagDecl::setTemplateParameterListsInfo(ASTContext &Context,
+ unsigned NumTPLists,
+ TemplateParameterList **TPLists) {
+ assert(NumTPLists > 0);
+ // Make sure the extended decl info is allocated.
+ if (!hasExtInfo())
+ // Allocate external info struct.
+ TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ // Set the template parameter lists info.
+ getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
+}
+
//===----------------------------------------------------------------------===//
// EnumDecl Implementation
//===----------------------------------------------------------------------===//
-EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, SourceLocation TKL,
+EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id,
EnumDecl *PrevDecl, bool IsScoped,
bool IsScopedUsingClassTag, bool IsFixed) {
- EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL,
+ EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl,
IsScoped, IsScopedUsingClassTag, IsFixed);
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation(),
+ return new (C) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
false, false, false);
}
@@ -2079,10 +2212,10 @@ void EnumDecl::completeDefinition(QualType NewType,
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
-RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, RecordDecl *PrevDecl,
- SourceLocation TKL)
- : TagDecl(DK, TK, DC, L, Id, PrevDecl, TKL) {
+RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, RecordDecl *PrevDecl)
+ : TagDecl(DK, TK, DC, IdLoc, Id, PrevDecl, StartLoc) {
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
@@ -2091,17 +2224,17 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
}
RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- SourceLocation TKL, RecordDecl* PrevDecl) {
-
- RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id, PrevDecl, TKL);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, RecordDecl* PrevDecl) {
+ RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id,
+ PrevDecl);
C.getTypeDeclType(R, PrevDecl);
return R;
}
RecordDecl *RecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), 0, 0,
- SourceLocation());
+ return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
}
bool RecordDecl::isInjectedClassName() const {
@@ -2200,14 +2333,22 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
}
LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *II) {
- return new (C) LabelDecl(DC, L, II, 0);
+ SourceLocation IdentL, IdentifierInfo *II) {
+ return new (C) LabelDecl(DC, IdentL, II, 0, IdentL);
+}
+
+LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation IdentL, IdentifierInfo *II,
+ SourceLocation GnuLabelL) {
+ assert(GnuLabelL != IdentL && "Use this only for GNU local labels");
+ return new (C) LabelDecl(DC, IdentL, II, 0, GnuLabelL);
}
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
- return new (C) NamespaceDecl(DC, L, Id);
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id) {
+ return new (C) NamespaceDecl(DC, StartLoc, IdLoc, Id);
}
NamespaceDecl *NamespaceDecl::getNextNamespace() {
@@ -2216,20 +2357,22 @@ NamespaceDecl *NamespaceDecl::getNextNamespace() {
}
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation loc,
- IdentifierInfo *name,
- QualType type) {
- return new (C) ImplicitParamDecl(DC, loc, name, type);
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
+ QualType Type) {
+ return new (C) ImplicitParamDecl(DC, IdLoc, Id, Type);
}
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten,
+ StorageClass SC, StorageClass SCAsWritten,
bool isInlineSpecified,
bool hasWrittenPrototype) {
- FunctionDecl *New = new (C) FunctionDecl(Function, DC, NameInfo, T, TInfo,
- S, SCAsWritten, isInlineSpecified);
+ FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo,
+ T, TInfo, SC, SCAsWritten,
+ isInlineSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
@@ -2260,13 +2403,37 @@ SourceRange EnumConstantDecl::getSourceRange() const {
}
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- TypeSourceInfo *TInfo) {
- return new (C) TypedefDecl(DC, L, Id, TInfo);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, TypeSourceInfo *TInfo) {
+ return new (C) TypedefDecl(DC, StartLoc, IdLoc, Id, TInfo);
+}
+
+TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ TypeSourceInfo *TInfo) {
+ return new (C) TypeAliasDecl(DC, StartLoc, IdLoc, Id, TInfo);
+}
+
+SourceRange TypedefDecl::getSourceRange() const {
+ SourceLocation RangeEnd = getLocation();
+ if (TypeSourceInfo *TInfo = getTypeSourceInfo()) {
+ if (typeIsPostfix(TInfo->getType()))
+ RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd();
+ }
+ return SourceRange(getLocStart(), RangeEnd);
+}
+
+SourceRange TypeAliasDecl::getSourceRange() const {
+ SourceLocation RangeEnd = getLocStart();
+ if (TypeSourceInfo *TInfo = getTypeSourceInfo())
+ RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd();
+ return SourceRange(getLocStart(), RangeEnd);
}
FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- StringLiteral *Str) {
- return new (C) FileScopeAsmDecl(DC, L, Str);
+ StringLiteral *Str,
+ SourceLocation AsmLoc,
+ SourceLocation RParenLoc) {
+ return new (C) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 81df00d6c7e8..6d517c544089 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -25,11 +25,11 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdio>
-#include <vector>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -173,9 +173,6 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
Decl::~Decl() { }
void Decl::setDeclContext(DeclContext *DC) {
- if (isOutOfSemaDC())
- delete getMultipleDC();
-
DeclCtx = DC;
}
@@ -244,6 +241,177 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
return false;
}
+bool Decl::isReferenced() const {
+ if (Referenced)
+ return true;
+
+ // Check redeclarations.
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+ if (I->Referenced)
+ return true;
+
+ return false;
+}
+
+/// \brief Determine the availability of the given declaration based on
+/// the target platform.
+///
+/// When it returns an availability result other than \c AR_Available,
+/// if the \p Message parameter is non-NULL, it will be set to a
+/// string describing why the entity is unavailable.
+///
+/// FIXME: Make these strings localizable, since they end up in
+/// diagnostics.
+static AvailabilityResult CheckAvailability(ASTContext &Context,
+ const AvailabilityAttr *A,
+ std::string *Message) {
+ llvm::StringRef TargetPlatform = Context.Target.getPlatformName();
+ llvm::StringRef PrettyPlatformName
+ = AvailabilityAttr::getPrettyPlatformName(TargetPlatform);
+ if (PrettyPlatformName.empty())
+ PrettyPlatformName = TargetPlatform;
+
+ VersionTuple TargetMinVersion = Context.Target.getPlatformMinVersion();
+ if (TargetMinVersion.empty())
+ return AR_Available;
+
+ // Match the platform name.
+ if (A->getPlatform()->getName() != TargetPlatform)
+ return AR_Available;
+
+ // Make sure that this declaration has not been marked 'unavailable'.
+ if (A->getUnavailable()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "not available on " << PrettyPlatformName;
+ }
+
+ return AR_Unavailable;
+ }
+
+ // Make sure that this declaration has already been introduced.
+ if (!A->getIntroduced().empty() &&
+ TargetMinVersion < A->getIntroduced()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "introduced in " << PrettyPlatformName << ' '
+ << A->getIntroduced();
+ }
+
+ return AR_NotYetIntroduced;
+ }
+
+ // Make sure that this declaration hasn't been obsoleted.
+ if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "obsoleted in " << PrettyPlatformName << ' '
+ << A->getObsoleted();
+ }
+
+ return AR_Unavailable;
+ }
+
+ // Make sure that this declaration hasn't been deprecated.
+ if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) {
+ if (Message) {
+ Message->clear();
+ llvm::raw_string_ostream Out(*Message);
+ Out << "first deprecated in " << PrettyPlatformName << ' '
+ << A->getDeprecated();
+ }
+
+ return AR_Deprecated;
+ }
+
+ return AR_Available;
+}
+
+AvailabilityResult Decl::getAvailability(std::string *Message) const {
+ AvailabilityResult Result = AR_Available;
+ std::string ResultMessage;
+
+ for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) {
+ if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
+ if (Result >= AR_Deprecated)
+ continue;
+
+ if (Message)
+ ResultMessage = Deprecated->getMessage();
+
+ Result = AR_Deprecated;
+ continue;
+ }
+
+ if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
+ if (Message)
+ *Message = Unavailable->getMessage();
+ return AR_Unavailable;
+ }
+
+ if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) {
+ AvailabilityResult AR = CheckAvailability(getASTContext(), Availability,
+ Message);
+
+ if (AR == AR_Unavailable)
+ return AR_Unavailable;
+
+ if (AR > Result) {
+ Result = AR;
+ if (Message)
+ ResultMessage.swap(*Message);
+ }
+ continue;
+ }
+ }
+
+ if (Message)
+ Message->swap(ResultMessage);
+ return Result;
+}
+
+bool Decl::canBeWeakImported(bool &IsDefinition) const {
+ IsDefinition = false;
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
+ if (!Var->hasExternalStorage() || Var->getInit()) {
+ IsDefinition = true;
+ return false;
+ }
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) {
+ if (FD->hasBody()) {
+ IsDefinition = true;
+ return false;
+ }
+ } else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this))
+ return false;
+ else if (!(getASTContext().getLangOptions().ObjCNonFragileABI &&
+ isa<ObjCInterfaceDecl>(this)))
+ return false;
+
+ return true;
+}
+
+bool Decl::isWeakImported() const {
+ bool IsDefinition;
+ if (!canBeWeakImported(IsDefinition))
+ return false;
+
+ for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) {
+ if (isa<WeakImportAttr>(*A))
+ return true;
+
+ if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) {
+ if (CheckAvailability(getASTContext(), Availability, 0)
+ == AR_NotYetIntroduced)
+ return true;
+ }
+ }
+
+ return false;
+}
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
@@ -270,6 +438,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Ordinary | IDNS_Type;
case Typedef:
+ case TypeAlias:
case UnresolvedUsingTypename:
case TemplateTypeParm:
return IDNS_Ordinary | IDNS_Type;
@@ -960,7 +1129,7 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
// FIXME: This feels like a hack. Should DeclarationName support
// template-ids, or is there a better way to keep specializations
// from being visible?
- if (isa<ClassTemplateSpecializationDecl>(D))
+ if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter())
return;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
if (FD->isFunctionTemplateSpecialization())
@@ -999,7 +1168,7 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
// FIXME: This feels like a hack. Should DeclarationName support
// template-ids, or is there a better way to keep specializations
// from being visible?
- if (isa<ClassTemplateSpecializationDecl>(D))
+ if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter())
return;
ASTContext *C = 0;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 46768c12d879..9099cd524f1a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -31,9 +31,13 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
- Abstract(false), HasTrivialConstructor(true),
- HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
- HasTrivialDestructor(true), ComputedVisibleConversions(false),
+ Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
+ HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
+ HasTrivialConstructor(true), HasConstExprNonCopyMoveConstructor(false),
+ HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
+ HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
+ HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false),
+ ComputedVisibleConversions(false),
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
DeclaredCopyAssignment(false), DeclaredDestructor(false),
NumBases(0), NumVBases(0), Bases(), VBases(),
@@ -41,20 +45,19 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- CXXRecordDecl *PrevDecl,
- SourceLocation TKL)
- : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, CXXRecordDecl *PrevDecl)
+ : RecordDecl(K, TK, DC, StartLoc, IdLoc, Id, PrevDecl),
DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
- DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, SourceLocation TKL,
+ DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl,
bool DelayTypeCreation) {
- CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id,
- PrevDecl, TKL);
+ CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc,
+ Id, PrevDecl);
// FIXME: DelayTypeCreation seems like such a hack
if (!DelayTypeCreation)
@@ -63,8 +66,8 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
}
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), 0, 0,
- SourceLocation());
+ return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
}
void
@@ -109,14 +112,38 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// A class with a non-empty base class is not empty.
// FIXME: Standard ref?
- if (!BaseClassDecl->isEmpty())
+ if (!BaseClassDecl->isEmpty()) {
+ if (!data().Empty) {
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- either has no non-static data members in the most derived
+ // class and at most one base class with non-static data members,
+ // or has no base classes with non-static data members, and
+ // If this is the second non-empty base, then neither of these two
+ // clauses can be true.
+ data().IsStandardLayout = false;
+ }
+
data().Empty = false;
+ data().HasNoNonEmptyBases = false;
+ }
// C++ [class.virtual]p1:
// A class that declares or inherits a virtual function is called a
// polymorphic class.
if (BaseClassDecl->isPolymorphic())
data().Polymorphic = true;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that: [...]
+ // -- has no non-standard-layout base classes
+ if (!BaseClassDecl->isStandardLayout())
+ data().IsStandardLayout = false;
+
+ // Record if this base is the first non-literal field or base.
+ if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType())
+ data().HasNonLiteralTypeFieldsOrBases = true;
// Now go through all virtual bases of this base and add them.
for (CXXRecordDecl::base_class_iterator VBase =
@@ -140,16 +167,25 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// C++ [class.ctor]p5:
// A constructor is trivial if its class has no virtual base classes.
data().HasTrivialConstructor = false;
-
- // C++ [class.copy]p6:
- // A copy constructor is trivial if its class has no virtual base
- // classes.
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if it is neither
+ // user-provided nor deleted and if
+ // -- class X has no virtual functions and no virtual base classes, and
data().HasTrivialCopyConstructor = false;
-
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if its class has no virtual
- // base classes.
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted and if
+ // -- class X has no virtual functions and no virtual base classes, and
data().HasTrivialCopyAssignment = false;
+ data().HasTrivialMoveAssignment = false;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that: [...]
+ // -- has [...] no virtual base classes
+ data().IsStandardLayout = false;
} else {
// C++ [class.ctor]p5:
// A constructor is trivial if all the direct base classes of its
@@ -157,17 +193,29 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (!BaseClassDecl->hasTrivialConstructor())
data().HasTrivialConstructor = false;
- // C++ [class.copy]p6:
- // A copy constructor is trivial if all the direct base classes of its
- // class have trivial copy constructors.
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if [...]
+ // [...]
+ // -- the constructor selected to copy/move each direct base class
+ // subobject is trivial, and
+ // FIXME: C++0x: We need to only consider the selected constructor
+ // instead of all of them.
if (!BaseClassDecl->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
-
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if all the direct base classes
- // of its class have trivial copy assignment operators.
+ if (!BaseClassDecl->hasTrivialMoveConstructor())
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if [...]
+ // [...]
+ // -- the assignment operator selected to copy/move each direct base
+ // class subobject is trivial, and
+ // FIXME: C++0x: We need to only consider the selected operator instead
+ // of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
+ if (!BaseClassDecl->hasTrivialMoveAssignment())
+ data().HasTrivialMoveAssignment = false;
}
// C++ [class.ctor]p3:
@@ -218,6 +266,23 @@ bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const {
return getCopyConstructor(Context, Qualifiers::Const) != 0;
}
+bool CXXRecordDecl::isTriviallyCopyable() const {
+ // C++0x [class]p5:
+ // A trivially copyable class is a class that:
+ // -- has no non-trivial copy constructors,
+ if (!hasTrivialCopyConstructor()) return false;
+ // -- has no non-trivial move constructors,
+ if (!hasTrivialMoveConstructor()) return false;
+ // -- has no non-trivial copy assignment operators,
+ if (!hasTrivialCopyAssignment()) return false;
+ // -- has no non-trivial move assignment operators, and
+ if (!hasTrivialMoveAssignment()) return false;
+ // -- has a trivial destructor.
+ if (!hasTrivialDestructor()) return false;
+
+ return true;
+}
+
/// \brief Perform a simplistic form of overload resolution that only considers
/// cv-qualifiers on a single parameter, and return the best overload candidate
/// (if there is one).
@@ -231,11 +296,11 @@ GetBestOverloadCandidateSimple(
unsigned Best = 0, N = Cands.size();
for (unsigned I = 1; I != N; ++I)
- if (Cands[Best].second.isSupersetOf(Cands[I].second))
+ if (Cands[Best].second.compatiblyIncludes(Cands[I].second))
Best = I;
for (unsigned I = 1; I != N; ++I)
- if (Cands[Best].second.isSupersetOf(Cands[I].second))
+ if (Cands[Best].second.compatiblyIncludes(Cands[I].second))
return 0;
return Cands[Best].first;
@@ -358,9 +423,24 @@ void CXXRecordDecl::addedMember(Decl *D) {
// None of the special member functions are trivial.
data().HasTrivialConstructor = false;
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if [...]
+ // -- class X has no virtual functions [...]
data().HasTrivialCopyConstructor = false;
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if [...]
+ // -- class X has no virtual functions [...]
data().HasTrivialCopyAssignment = false;
+ data().HasTrivialMoveAssignment = false;
// FIXME: Destructor?
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that: [...]
+ // -- has no virtual functions
+ data().IsStandardLayout = false;
}
}
@@ -423,18 +503,33 @@ void CXXRecordDecl::addedMember(Decl *D) {
// FIXME: C++0x: don't do this for "= default" default constructors.
data().HasTrivialConstructor = false;
- // Note when we have a user-declared copy constructor, which will
- // suppress the implicit declaration of a copy constructor.
- if (!FunTmpl && Constructor->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
- data().DeclaredCopyConstructor = true;
-
- // C++ [class.copy]p6:
- // A copy constructor is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy constructors.
- data().HasTrivialCopyConstructor = false;
+ // Note when we have a user-declared copy or move constructor, which will
+ // suppress the implicit declaration of those constructors.
+ if (!FunTmpl) {
+ if (Constructor->isCopyConstructor()) {
+ data().UserDeclaredCopyConstructor = true;
+ data().DeclaredCopyConstructor = true;
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if it is neither
+ // user-provided nor deleted
+ // FIXME: C++0x: don't do this for "= default" copy constructors.
+ data().HasTrivialCopyConstructor = false;
+ } else if (Constructor->isMoveConstructor()) {
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if it is neither
+ // user-provided nor deleted
+ // FIXME: C++0x: don't do this for "= default" move constructors.
+ data().HasTrivialMoveConstructor = false;
+ }
}
-
+ if (Constructor->isConstExpr() &&
+ !Constructor->isCopyOrMoveConstructor()) {
+ // Record if we see any constexpr constructors which are niether copy
+ // nor move constructors.
+ data().HasConstExprNonCopyMoveConstructor = true;
+ }
+
return;
}
@@ -472,35 +567,53 @@ void CXXRecordDecl::addedMember(Decl *D) {
return;
ASTContext &Context = getASTContext();
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>())
- ArgType = Ref->getPointeeType();
-
- ArgType = ArgType.getUnqualifiedType();
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
const_cast<CXXRecordDecl*>(this)));
-
+
+ bool isRValueRefArg = false;
+ QualType ArgType = FnType->getArgType(0);
+ if (const LValueReferenceType *Ref =
+ ArgType->getAs<LValueReferenceType>()) {
+ ArgType = Ref->getPointeeType();
+ } else if (const RValueReferenceType *Ref =
+ ArgType->getAs<RValueReferenceType>()) {
+ ArgType = Ref->getPointeeType();
+ isRValueRefArg = true;
+ }
if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
return;
-
- // This is a copy assignment operator.
- // FIXME: Move assignment operators.
-
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
-
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy operators.
- data().HasTrivialCopyAssignment = false;
-
+
// C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined copy
- // assignment operator [...].
+ // A POD-struct is an aggregate class that [...] has no user-defined
+ // copy assignment operator [...].
+ // FIXME: This should be probably determined dynamically in terms of
+ // other more precise attributes to correctly model how it is specified
+ // in C++0x. Setting it here happens to do the right thing.
data().PlainOldData = false;
+
+ if (!isRValueRefArg) {
+ // This is a copy assignment operator.
+
+ // Suppress the implicit declaration of a copy constructor.
+ data().UserDeclaredCopyAssignment = true;
+ data().DeclaredCopyAssignment = true;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ // FIXME: C++0x: don't do this for "= default" copy operators.
+ data().HasTrivialCopyAssignment = false;
+ } else {
+ // This is a move assignment operator.
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ // FIXME: C++0x: don't do this for "= default" copy operators.
+ data().HasTrivialMoveAssignment = false;
+ }
}
-
+
// Keep the list of conversion functions up-to-date.
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
// We don't record specializations.
@@ -539,8 +652,22 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().Aggregate = false;
data().PlainOldData = false;
}
-
- // C++ [class]p9:
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- has the same access control for all non-static data members,
+ switch (D->getAccess()) {
+ case AS_private: data().HasPrivateFields = true; break;
+ case AS_protected: data().HasProtectedFields = true; break;
+ case AS_public: data().HasPublicFields = true; break;
+ case AS_none: assert(0 && "Invalid access specifier");
+ };
+ if ((data().HasPrivateFields + data().HasProtectedFields +
+ data().HasPublicFields) > 1)
+ data().IsStandardLayout = false;
+
+ // C++0x [class]p9:
// A POD struct is a class that is both a trivial class and a
// standard-layout class, and has no non-static data members of type
// non-POD struct, non-POD union (or array of such types).
@@ -548,23 +675,98 @@ void CXXRecordDecl::addedMember(Decl *D) {
QualType T = Context.getBaseElementType(Field->getType());
if (!T->isPODType())
data().PlainOldData = false;
- if (T->isReferenceType())
+ if (T->isReferenceType()) {
data().HasTrivialConstructor = false;
-
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // -- has no non-static data members of type [...] reference,
+ data().IsStandardLayout = false;
+ }
+
+ // Record if this field is the first non-literal field or base.
+ if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
+ data().HasNonLiteralTypeFieldsOrBases = true;
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
if (!FieldRec->hasTrivialConstructor())
data().HasTrivialConstructor = false;
+
+ // C++0x [class.copy]p13:
+ // A copy/move constructor for class X is trivial if [...]
+ // [...]
+ // -- for each non-static data member of X that is of class type (or
+ // an array thereof), the constructor selected to copy/move that
+ // member is trivial;
+ // FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
data().HasTrivialCopyConstructor = false;
+ if (!FieldRec->hasTrivialMoveConstructor())
+ data().HasTrivialMoveConstructor = false;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if [...]
+ // [...]
+ // -- for each non-static data member of X that is of class type (or
+ // an array thereof), the assignment operator selected to
+ // copy/move that member is trivial;
+ // FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
data().HasTrivialCopyAssignment = false;
+ if (!FieldRec->hasTrivialMoveAssignment())
+ data().HasTrivialMoveAssignment = false;
+
if (!FieldRec->hasTrivialDestructor())
data().HasTrivialDestructor = false;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // -- has no non-static data members of type non-standard-layout
+ // class (or array of such types) [...]
+ if (!FieldRec->isStandardLayout())
+ data().IsStandardLayout = false;
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- has no base classes of the same type as the first non-static
+ // data member.
+ // We don't want to expend bits in the state of the record decl
+ // tracking whether this is the first non-static data member so we
+ // cheat a bit and use some of the existing state: the empty bit.
+ // Virtual bases and virtual methods make a class non-empty, but they
+ // also make it non-standard-layout so we needn't check here.
+ // A non-empty base class may leave the class standard-layout, but not
+ // if we have arrived here, and have at least on non-static data
+ // member. If IsStandardLayout remains true, then the first non-static
+ // data member must come through here with Empty still true, and Empty
+ // will subsequently be set to false below.
+ if (data().IsStandardLayout && data().Empty) {
+ for (CXXRecordDecl::base_class_const_iterator BI = bases_begin(),
+ BE = bases_end();
+ BI != BE; ++BI) {
+ if (Context.hasSameUnqualifiedType(BI->getType(), T)) {
+ data().IsStandardLayout = false;
+ break;
+ }
+ }
+ }
}
}
-
+
+ // C++0x [class]p7:
+ // A standard-layout class is a class that:
+ // [...]
+ // -- either has no non-static data members in the most derived
+ // class and at most one base class with non-static data members,
+ // or has no base classes with non-static data members, and
+ // At this point we know that we have a non-static data member, so the last
+ // clause holds.
+ if (!data().HasNoNonEmptyBases)
+ data().IsStandardLayout = false;
+
// If this is not a zero-length bit-field, then the class is not empty.
if (data().Empty) {
if (!Field->getBitWidth())
@@ -814,8 +1016,6 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
return 0;
CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
- assert(++I == E && "Found more than one destructor!");
-
return Dtor;
}
@@ -884,11 +1084,13 @@ bool CXXRecordDecl::mayBeAbstract() const {
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, StorageClass SCAsWritten, bool isInline) {
- return new (C) CXXMethodDecl(CXXMethod, RD, NameInfo, T, TInfo,
- isStatic, SCAsWritten, isInline);
+ bool isStatic, StorageClass SCAsWritten, bool isInline,
+ SourceLocation EndLocation) {
+ return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
+ isStatic, SCAsWritten, isInline, EndLocation);
}
bool CXXMethodDecl::isUsualDeallocationFunction() const {
@@ -1033,6 +1235,16 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
}
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
+ SourceLocation D, SourceLocation L,
+ CXXConstructorDecl *Target, Expr *Init,
+ SourceLocation R)
+ : Initializee(Target), MemberOrEllipsisLocation(D), Init(Init),
+ LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ IsWritten(false), SourceOrderOrNumArrayIndices(0)
+{
+}
+
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
FieldDecl *Member,
SourceLocation MemberLoc,
SourceLocation L, Expr *Init,
@@ -1076,7 +1288,7 @@ const Type *CXXCtorInitializer::getBaseClass() const {
}
SourceLocation CXXCtorInitializer::getSourceLocation() const {
- if (isAnyMemberInitializer())
+ if (isAnyMemberInitializer() || isDelegatingInitializer())
return getMemberLocation();
return getBaseClassLoc().getLocalSourceRange().getBegin();
@@ -1088,12 +1300,13 @@ SourceRange CXXCtorInitializer::getSourceRange() const {
CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXConstructorDecl(0, DeclarationNameInfo(),
+ return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(),
QualType(), 0, false, false, false);
}
CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isExplicit,
@@ -1102,8 +1315,8 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
- return new (C) CXXConstructorDecl(RD, NameInfo, T, TInfo, isExplicit,
- isInline, isImplicitlyDeclared);
+ return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo,
+ isExplicit, isInline, isImplicitlyDeclared);
}
bool CXXConstructorDecl::isDefaultConstructor() const {
@@ -1222,12 +1435,13 @@ CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXDestructorDecl(0, DeclarationNameInfo(),
+ return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationNameInfo(),
QualType(), 0, false, false);
}
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline,
@@ -1235,33 +1449,38 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C) CXXDestructorDecl(RD, NameInfo, T, TInfo, isInline,
+ return new (C) CXXDestructorDecl(RD, StartLoc, NameInfo, T, TInfo, isInline,
isImplicitlyDeclared);
}
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXConversionDecl(0, DeclarationNameInfo(),
- QualType(), 0, false, false);
+ return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(),
+ QualType(), 0, false, false,
+ SourceLocation());
}
CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicit) {
+ bool isInline, bool isExplicit,
+ SourceLocation EndLocation) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
- return new (C) CXXConversionDecl(RD, NameInfo, T, TInfo,
- isInline, isExplicit);
+ return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo,
+ isInline, isExplicit, EndLocation);
}
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
- SourceLocation L,
- LanguageIDs Lang, bool Braces) {
- return new (C) LinkageSpecDecl(DC, L, Lang, Braces);
+ SourceLocation ExternLoc,
+ SourceLocation LangLoc,
+ LanguageIDs Lang,
+ SourceLocation RBraceLoc) {
+ return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc);
}
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
@@ -1364,9 +1583,12 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
}
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, Expr *AssertExpr,
- StringLiteral *Message) {
- return new (C) StaticAssertDecl(DC, L, AssertExpr, Message);
+ SourceLocation StaticAssertLoc,
+ Expr *AssertExpr,
+ StringLiteral *Message,
+ SourceLocation RParenLoc) {
+ return new (C) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message,
+ RParenLoc);
}
static const char *getAccessName(AccessSpecifier AS) {
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 45f5188d4043..24d281e8b66d 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -398,6 +398,64 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() {
return this;
}
+ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
+ ObjCMethodFamily family = static_cast<ObjCMethodFamily>(Family);
+ if (family != static_cast<unsigned>(InvalidObjCMethodFamily))
+ return family;
+
+ // Check for an explicit attribute.
+ if (const ObjCMethodFamilyAttr *attr = getAttr<ObjCMethodFamilyAttr>()) {
+ // The unfortunate necessity of mapping between enums here is due
+ // to the attributes framework.
+ switch (attr->getFamily()) {
+ case ObjCMethodFamilyAttr::OMF_None: family = OMF_None; break;
+ case ObjCMethodFamilyAttr::OMF_alloc: family = OMF_alloc; break;
+ case ObjCMethodFamilyAttr::OMF_copy: family = OMF_copy; break;
+ case ObjCMethodFamilyAttr::OMF_init: family = OMF_init; break;
+ case ObjCMethodFamilyAttr::OMF_mutableCopy: family = OMF_mutableCopy; break;
+ case ObjCMethodFamilyAttr::OMF_new: family = OMF_new; break;
+ }
+ Family = static_cast<unsigned>(family);
+ return family;
+ }
+
+ family = getSelector().getMethodFamily();
+ switch (family) {
+ case OMF_None: break;
+
+ // init only has a conventional meaning for an instance method, and
+ // it has to return an object.
+ case OMF_init:
+ if (!isInstanceMethod() || !getResultType()->isObjCObjectPointerType())
+ family = OMF_None;
+ break;
+
+ // alloc/copy/new have a conventional meaning for both class and
+ // instance methods, but they require an object return.
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ if (!getResultType()->isObjCObjectPointerType())
+ family = OMF_None;
+ break;
+
+ // These selectors have a conventional meaning only for instance methods.
+ case OMF_dealloc:
+ case OMF_retain:
+ case OMF_release:
+ case OMF_autorelease:
+ case OMF_retainCount:
+ if (!isInstanceMethod())
+ family = OMF_None;
+ break;
+ }
+
+ // Cache the result.
+ Family = static_cast<unsigned>(family);
+ return family;
+}
+
void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
const ObjCInterfaceDecl *OID) {
QualType selfTy;
@@ -614,7 +672,8 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
//===----------------------------------------------------------------------===//
ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
- SourceLocation L, IdentifierInfo *Id,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW,
bool synthesized) {
@@ -651,7 +710,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
ID->setIvarList(0);
}
- return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW, synthesized);
+ return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo,
+ ac, BW, synthesized);
}
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
@@ -684,9 +744,10 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
//===----------------------------------------------------------------------===//
ObjCAtDefsFieldDecl
-*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T, Expr *BW) {
- return new (C) ObjCAtDefsFieldDecl(DC, L, Id, T, BW);
+ return new (C) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index c6ae128e42b5..2fd88d7c808d 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -45,6 +45,7 @@ namespace {
void VisitTranslationUnitDecl(TranslationUnitDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
+ void VisitTypeAliasDecl(TypeAliasDecl *D);
void VisitEnumDecl(EnumDecl *D);
void VisitRecordDecl(RecordDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
@@ -54,12 +55,13 @@ namespace {
void VisitLabelDecl(LabelDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitCXXRecordDecl(CXXRecordDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
- void VisitTemplateDecl(TemplateDecl *D);
+ void VisitTemplateDecl(const TemplateDecl *D);
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCClassDecl(ObjCClassDecl *D);
void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
@@ -109,7 +111,7 @@ static QualType GetBaseType(QualType T) {
}
static QualType getDeclType(Decl* D) {
- if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D))
+ if (TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(D))
return TDD->getUnderlyingType();
if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
return VD->getType();
@@ -307,6 +309,11 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
Out << S;
}
+void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ Out << "using " << D->getNameAsString() << " = "
+ << D->getUnderlyingType().getAsString(Policy);
+}
+
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
Out << "enum ";
if (D->isScoped()) {
@@ -412,22 +419,32 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (TypeQuals & Qualifiers::Restrict)
Proto += " restrict";
}
-
- if (FT && FT->hasExceptionSpec()) {
+
+ if (FT && FT->hasDynamicExceptionSpec()) {
Proto += " throw(";
- if (FT->hasAnyExceptionSpec())
+ if (FT->getExceptionSpecType() == EST_MSAny)
Proto += "...";
else
for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) {
if (I)
Proto += ", ";
-
-
+
std::string ExceptionType;
FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy);
Proto += ExceptionType;
}
Proto += ")";
+ } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
+ Proto += " noexcept";
+ if (FT->getExceptionSpecType() == EST_ComputedNoexcept) {
+ Proto += "(";
+ llvm::raw_string_ostream EOut(Proto);
+ FT->getNoexceptExpr()->printPretty(EOut, Context, 0, SubPolicy,
+ Indentation);
+ EOut.flush();
+ Proto += EOut.str();
+ Proto += ")";
+ }
}
if (D->hasAttr<NoReturnAttr>())
@@ -556,7 +573,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
T = Parm->getOriginalType();
T.getAsStringInternal(Name, Policy);
Out << Name;
- if (Expr *Init = D->getInit()) {
+ Expr *Init = D->getInit();
+ if (!Policy.SuppressInitializers && Init) {
if (D->hasCXXDirectInitializer())
Out << "(";
else {
@@ -580,6 +598,14 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Out << ")";
}
+void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ Out << "static_assert(";
+ D->getAssertExpr()->printPretty(Out, Context, 0, Policy, Indentation);
+ Out << ", ";
+ D->getMessage()->printPretty(Out, Context, 0, Policy, Indentation);
+ Out << ")";
+}
+
//----------------------------------------------------------------------------
// C++ declarations
//----------------------------------------------------------------------------
@@ -624,6 +650,9 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (AS != AS_none)
Print(AS);
Out << " " << Base->getType().getAsString(Policy);
+
+ if (Base->isPackExpansion())
+ Out << "...";
}
}
@@ -654,7 +683,7 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
+void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
Out << "template <";
TemplateParameterList *Params = D->getTemplateParameters();
@@ -666,9 +695,6 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
if (const TemplateTypeParmDecl *TTP =
dyn_cast<TemplateTypeParmDecl>(Param)) {
- QualType ParamType =
- Context.getTypeDeclType(const_cast<TemplateTypeParmDecl*>(TTP));
-
if (TTP->wasDeclaredWithTypename())
Out << "typename ";
else
@@ -677,7 +703,7 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
if (TTP->isParameterPack())
Out << "... ";
- Out << ParamType.getAsString(Policy);
+ Out << TTP->getNameAsString();
if (TTP->hasDefaultArgument()) {
Out << " = ";
@@ -700,12 +726,17 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy,
Indentation);
}
+ } else if (const TemplateTemplateParmDecl *TTPD =
+ dyn_cast<TemplateTemplateParmDecl>(Param)) {
+ VisitTemplateDecl(TTPD);
+ // FIXME: print the default argument, if present.
}
}
Out << "> ";
- if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(D)) {
Out << "class ";
if (TTP->isParameterPack())
Out << "...";
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a73deeab3a61..6272340691bf 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -95,6 +95,18 @@ unsigned TemplateParameterList::getDepth() const {
return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth();
}
+static void AdoptTemplateParameterList(TemplateParameterList *Params,
+ DeclContext *Owner) {
+ for (TemplateParameterList::iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ (*P)->setDeclContext(Owner);
+
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*P))
+ AdoptTemplateParameterList(TTP->getTemplateParameters(), Owner);
+ }
+}
+
//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -151,6 +163,49 @@ RedeclarableTemplateDecl::findSpecializationImpl(
return Entry ? SETraits::getMostRecentDeclaration(Entry) : 0;
}
+/// \brief Generate the injected template arguments for the given template
+/// parameter list, e.g., for the injected-class-name of a class template.
+static void GenerateInjectedTemplateArgs(ASTContext &Context,
+ TemplateParameterList *Params,
+ TemplateArgument *Args) {
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ Param != ParamEnd; ++Param) {
+ TemplateArgument Arg;
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ QualType ArgType = Context.getTypeDeclType(TTP);
+ if (TTP->isParameterPack())
+ ArgType = Context.getPackExpansionType(ArgType,
+ llvm::Optional<unsigned>());
+
+ Arg = TemplateArgument(ArgType);
+ } else if (NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ Expr *E = new (Context) DeclRefExpr(NTTP,
+ NTTP->getType().getNonLValueExprType(Context),
+ Expr::getValueKindForType(NTTP->getType()),
+ NTTP->getLocation());
+
+ if (NTTP->isParameterPack())
+ E = new (Context) PackExpansionExpr(Context.DependentTy, E,
+ NTTP->getLocation(),
+ llvm::Optional<unsigned>());
+ Arg = TemplateArgument(E);
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
+ if (TTP->isParameterPack())
+ Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+ else
+ Arg = TemplateArgument(TemplateName(TTP));
+ }
+
+ if ((*Param)->isTemplateParameterPack())
+ Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1);
+
+ *Args++ = Arg;
+ }
+}
+
//===----------------------------------------------------------------------===//
// FunctionTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -165,9 +220,15 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl) {
+ AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
}
+FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, EmptyShell) {
+ return new (C) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(),
+ 0, 0);
+}
+
RedeclarableTemplateDecl::CommonBase *
FunctionTemplateDecl::newCommon(ASTContext &C) {
Common *CommonPtr = new (C) Common;
@@ -181,6 +242,27 @@ FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
}
+void FunctionTemplateDecl::addSpecialization(
+ FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
+ getSpecializations().InsertNode(Info, InsertPos);
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, Info->Function);
+}
+
+std::pair<const TemplateArgument *, unsigned>
+FunctionTemplateDecl::getInjectedTemplateArgs() {
+ TemplateParameterList *Params = getTemplateParameters();
+ Common *CommonPtr = getCommonPtr();
+ if (!CommonPtr->InjectedArgs) {
+ CommonPtr->InjectedArgs
+ = new (getASTContext()) TemplateArgument [Params->size()];
+ GenerateInjectedTemplateArgs(getASTContext(), Params,
+ CommonPtr->InjectedArgs);
+ }
+
+ return std::make_pair(CommonPtr->InjectedArgs, Params->size());
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -196,11 +278,16 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
TemplateParameterList *Params,
NamedDecl *Decl,
ClassTemplateDecl *PrevDecl) {
+ AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl);
New->setPreviousDeclaration(PrevDecl);
return New;
}
+ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, EmptyShell Empty) {
+ return new (C) ClassTemplateDecl(Empty);
+}
+
void ClassTemplateDecl::LoadLazySpecializations() {
Common *CommonPtr = getCommonPtr();
if (CommonPtr->LazySpecializations) {
@@ -320,44 +407,8 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
ASTContext &Context = getASTContext();
TemplateParameterList *Params = getTemplateParameters();
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
- TemplateArgs.reserve(Params->size());
- for (TemplateParameterList::iterator Param = Params->begin(),
- ParamEnd = Params->end();
- Param != ParamEnd; ++Param) {
- TemplateArgument Arg;
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- QualType ArgType = Context.getTypeDeclType(TTP);
- if (TTP->isParameterPack())
- ArgType = Context.getPackExpansionType(ArgType,
- llvm::Optional<unsigned>());
-
- Arg = TemplateArgument(ArgType);
- } else if (NonTypeTemplateParmDecl *NTTP =
- dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- Expr *E = new (Context) DeclRefExpr(NTTP,
- NTTP->getType().getNonLValueExprType(Context),
- Expr::getValueKindForType(NTTP->getType()),
- NTTP->getLocation());
-
- if (NTTP->isParameterPack())
- E = new (Context) PackExpansionExpr(Context.DependentTy, E,
- NTTP->getLocation(),
- llvm::Optional<unsigned>());
- Arg = TemplateArgument(E);
- } else {
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
- if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
- else
- Arg = TemplateArgument(TemplateName(TTP));
- }
-
- if ((*Param)->isTemplateParameterPack())
- Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1);
-
- TemplateArgs.push_back(Arg);
- }
-
+ TemplateArgs.resize(Params->size());
+ GenerateInjectedTemplateArgs(getASTContext(), Params, TemplateArgs.data());
CommonPtr->InjectedClassNameType
= Context.getTemplateSpecializationType(TemplateName(this),
&TemplateArgs[0],
@@ -371,21 +422,34 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id, bool Typename,
- bool ParameterPack) {
- QualType Type = C.getTemplateTypeParmType(D, P, ParameterPack, Id);
- return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack);
+ SourceLocation KeyLoc, SourceLocation NameLoc,
+ unsigned D, unsigned P, IdentifierInfo *Id,
+ bool Typename, bool ParameterPack) {
+ TemplateTypeParmDecl *TTPDecl =
+ new (C) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename);
+ QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl);
+ TTPDecl->TypeForDecl = TTPType.getTypePtr();
+ return TTPDecl;
}
TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) TemplateTypeParmDecl(0, SourceLocation(), 0, false,
- QualType(), false);
+ return new (C) TemplateTypeParmDecl(0, SourceLocation(), SourceLocation(),
+ 0, false);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
- return DefaultArgument->getTypeLoc().getSourceRange().getBegin();
+ return hasDefaultArgument()
+ ? DefaultArgument->getTypeLoc().getBeginLoc()
+ : SourceLocation();
+}
+
+SourceRange TemplateTypeParmDecl::getSourceRange() const {
+ if (hasDefaultArgument() && !defaultArgumentWasInherited())
+ return SourceRange(getLocStart(),
+ DefaultArgument->getTypeLoc().getEndLoc());
+ else
+ return TypeDecl::getSourceRange();
}
unsigned TemplateTypeParmDecl::getDepth() const {
@@ -396,19 +460,25 @@ unsigned TemplateTypeParmDecl::getIndex() const {
return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex();
}
+bool TemplateTypeParmDecl::isParameterPack() const {
+ return TypeForDecl->getAs<TemplateTypeParmType>()->isParameterPack();
+}
+
//===----------------------------------------------------------------------===//
// NonTypeTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC,
- SourceLocation L, unsigned D,
- unsigned P, IdentifierInfo *Id,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
+ unsigned D, unsigned P,
+ IdentifierInfo *Id,
QualType T,
TypeSourceInfo *TInfo,
const QualType *ExpandedTypes,
unsigned NumExpandedTypes,
TypeSourceInfo **ExpandedTInfos)
- : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo),
+ : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
ParameterPack(true), ExpandedParameterPack(true),
NumExpandedTypes(NumExpandedTypes)
@@ -424,16 +494,18 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC,
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id, QualType T,
- bool ParameterPack, TypeSourceInfo *TInfo) {
- return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, ParameterPack,
- TInfo);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ unsigned D, unsigned P, IdentifierInfo *Id,
+ QualType T, bool ParameterPack,
+ TypeSourceInfo *TInfo) {
+ return new (C) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
+ T, ParameterPack, TInfo);
}
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D, unsigned P,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
const QualType *ExpandedTypes,
@@ -442,20 +514,17 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
unsigned Size = sizeof(NonTypeTemplateParmDecl)
+ NumExpandedTypes * 2 * sizeof(void*);
void *Mem = C.Allocate(Size);
- return new (Mem) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo,
+ return new (Mem) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc,
+ D, P, Id, T, TInfo,
ExpandedTypes, NumExpandedTypes,
ExpandedTInfos);
}
-SourceLocation NonTypeTemplateParmDecl::getInnerLocStart() const {
- SourceLocation Start = getTypeSpecStartLoc();
- if (Start.isInvalid())
- Start = getLocation();
- return Start;
-}
-
SourceRange NonTypeTemplateParmDecl::getSourceRange() const {
- return SourceRange(getOuterLocStart(), getLocation());
+ if (hasDefaultArgument() && !defaultArgumentWasInherited())
+ return SourceRange(getOuterLocStart(),
+ getDefaultArgument()->getSourceRange().getEnd());
+ return DeclaratorDecl::getSourceRange();
}
SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
@@ -499,12 +568,13 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
- DeclContext *DC, SourceLocation L,
+ DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
ClassTemplateSpecializationDecl *PrevDecl)
- : CXXRecordDecl(DK, TK, DC, L,
+ : CXXRecordDecl(DK, TK, DC, StartLoc, IdLoc,
SpecializedTemplate->getIdentifier(),
PrevDecl),
SpecializedTemplate(SpecializedTemplate),
@@ -514,14 +584,16 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
}
ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(Kind DK)
- : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), 0, 0),
+ : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), SourceLocation(), 0, 0),
ExplicitInfo(0),
SpecializationKind(TSK_Undeclared) {
}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
- DeclContext *DC, SourceLocation L,
+ DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
@@ -529,7 +601,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
ClassTemplateSpecializationDecl *Result
= new (Context)ClassTemplateSpecializationDecl(Context,
ClassTemplateSpecialization,
- TK, DC, L,
+ TK, DC, StartLoc, IdLoc,
SpecializedTemplate,
Args, NumArgs,
PrevDecl);
@@ -564,12 +636,51 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
return SpecializedTemplate.get<ClassTemplateDecl*>();
}
+SourceRange
+ClassTemplateSpecializationDecl::getSourceRange() const {
+ if (!ExplicitInfo)
+ return SourceRange();
+ SourceLocation Begin = getExternLoc();
+ if (Begin.isInvalid())
+ Begin = getTemplateKeywordLoc();
+ SourceLocation End = getRBraceLoc();
+ if (End.isInvalid())
+ End = getTypeAsWritten()->getTypeLoc().getEndLoc();
+ return SourceRange(Begin, End);
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
+ClassTemplatePartialSpecializationDecl::
+ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
+ DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ TemplateArgumentLoc *ArgInfos,
+ unsigned NumArgInfos,
+ ClassTemplatePartialSpecializationDecl *PrevDecl,
+ unsigned SequenceNumber)
+ : ClassTemplateSpecializationDecl(Context,
+ ClassTemplatePartialSpecialization,
+ TK, DC, StartLoc, IdLoc,
+ SpecializedTemplate,
+ Args, NumArgs, PrevDecl),
+ TemplateParams(Params), ArgsAsWritten(ArgInfos),
+ NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
+ InstantiatedFromMember(0, false)
+{
+ AdoptTemplateParameterList(Params, this);
+}
+
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::
-Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
+Create(ASTContext &Context, TagKind TK,DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
@@ -584,8 +695,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
ClonedArgs[I] = ArgInfos[I];
ClassTemplatePartialSpecializationDecl *Result
- = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK,
- DC, L, Params,
+ = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC,
+ StartLoc, IdLoc,
+ Params,
SpecializedTemplate,
Args, NumArgs,
ClonedArgs, N,
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 9d828fcfb85a..7d593bc46f6c 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -543,12 +543,20 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
// TypedefDecl
void visitTypedefDeclAttrs(TypedefDecl *D) {
- visitRedeclarableAttrs(D);
+ visitRedeclarableAttrs<TypedefNameDecl>(D);
}
void visitTypedefDeclChildren(TypedefDecl *D) {
dispatch(D->getTypeSourceInfo()->getTypeLoc());
}
+ // TypeAliasDecl
+ void visitTypeAliasDeclAttrs(TypeAliasDecl *D) {
+ visitRedeclarableAttrs<TypedefNameDecl>(D);
+ }
+ void visitTypeAliasDeclChildren(TypeAliasDecl *D) {
+ dispatch(D->getTypeSourceInfo()->getTypeLoc());
+ }
+
// TagDecl
void visitTagDeclAttrs(TagDecl *D) {
visitRedeclarableAttrs(D);
@@ -911,6 +919,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
case CC_X86StdCall: return set("cc", "x86_stdcall");
case CC_X86ThisCall: return set("cc", "x86_thiscall");
case CC_X86Pascal: return set("cc", "x86_pascal");
+ case CC_AAPCS: return set("cc", "aapcs");
+ case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
}
}
@@ -955,7 +965,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
void visitFunctionTypeAttrs(FunctionType *T) {
setFlag("noreturn", T->getNoReturnAttr());
setCallingConv(T->getCallConv());
- if (T->getRegParmType()) setInteger("regparm", T->getRegParmType());
+ if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType());
}
void visitFunctionTypeChildren(FunctionType *T) {
dispatch(T->getResultType());
@@ -975,15 +985,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
dispatch(*I);
pop();
- if (T->hasExceptionSpec()) {
+ if (T->hasDynamicExceptionSpec()) {
push("exception_specifiers");
- setFlag("any", T->hasAnyExceptionSpec());
+ setFlag("any", T->getExceptionSpecType() == EST_MSAny);
completeAttrs();
for (FunctionProtoType::exception_iterator
I = T->exception_begin(), E = T->exception_end(); I != E; ++I)
dispatch(*I);
pop();
}
+ // FIXME: noexcept specifier
}
void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 1c1061b5a229..6499f327b07e 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -35,18 +35,16 @@ using namespace clang;
/// but also int expressions which are produced by things like comparisons in
/// C.
bool Expr::isKnownToHaveBooleanValue() const {
+ const Expr *E = IgnoreParens();
+
// If this value has _Bool type, it is obvious 0/1.
- if (getType()->isBooleanType()) return true;
+ if (E->getType()->isBooleanType()) return true;
// If this is a non-scalar-integer type, we don't care enough to try.
- if (!getType()->isIntegralOrEnumerationType()) return false;
-
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(this))
- return PE->getSubExpr()->isKnownToHaveBooleanValue();
+ if (!E->getType()->isIntegralOrEnumerationType()) return false;
- if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) {
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Plus:
- case UO_Extension:
return UO->getSubExpr()->isKnownToHaveBooleanValue();
default:
return false;
@@ -55,10 +53,10 @@ bool Expr::isKnownToHaveBooleanValue() const {
// Only look through implicit casts. If the user writes
// '(int) (a && b)' treat it as an arbitrary int.
- if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(this))
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
return CE->getSubExpr()->isKnownToHaveBooleanValue();
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) {
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
default: return false;
case BO_LT: // Relational operators.
@@ -84,7 +82,7 @@ bool Expr::isKnownToHaveBooleanValue() const {
}
}
- if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this))
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
CO->getFalseExpr()->isKnownToHaveBooleanValue();
@@ -276,44 +274,20 @@ void DeclRefExpr::computeDependence() {
ExprBits.ContainsUnexpandedParameterPack = true;
}
-DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- ValueDecl *D, SourceLocation NameLoc,
- const TemplateArgumentListInfo *TemplateArgs,
- QualType T, ExprValueKind VK)
- : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
- DecoratedD(D,
- (Qualifier? HasQualifierFlag : 0) |
- (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
- Loc(NameLoc) {
- if (Qualifier) {
- NameQualifier *NQ = getNameQualifier();
- NQ->NNS = Qualifier;
- NQ->Range = QualifierRange;
- }
-
- if (TemplateArgs)
- getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
-
- computeDependence();
-}
-
-DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D, const DeclarationNameInfo &NameInfo,
+ NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
QualType T, ExprValueKind VK)
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
- DecoratedD(D,
- (Qualifier? HasQualifierFlag : 0) |
- (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
- Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) {
- if (Qualifier) {
- NameQualifier *NQ = getNameQualifier();
- NQ->NNS = Qualifier;
- NQ->Range = QualifierRange;
- }
-
+ D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) {
+ DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
+ if (QualifierLoc)
+ getInternalQualifierLoc() = QualifierLoc;
+ DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
+ if (FoundD)
+ getInternalFoundDecl() = FoundD;
+ DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0;
if (TemplateArgs)
getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
@@ -321,49 +295,56 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D,
SourceLocation NameLoc,
QualType T,
ExprValueKind VK,
+ NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs) {
- return Create(Context, Qualifier, QualifierRange, D,
+ return Create(Context, QualifierLoc, D,
DeclarationNameInfo(D->getDeclName(), NameLoc),
- T, VK, TemplateArgs);
+ T, VK, FoundD, TemplateArgs);
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *D,
const DeclarationNameInfo &NameInfo,
QualType T,
ExprValueKind VK,
+ NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs) {
+ // Filter out cases where the found Decl is the same as the value refenenced.
+ if (D == FoundD)
+ FoundD = 0;
+
std::size_t Size = sizeof(DeclRefExpr);
- if (Qualifier != 0)
- Size += sizeof(NameQualifier);
-
+ if (QualifierLoc != 0)
+ Size += sizeof(NestedNameSpecifierLoc);
+ if (FoundD)
+ Size += sizeof(NamedDecl *);
if (TemplateArgs)
Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
-
+
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
- return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameInfo,
- TemplateArgs, T, VK);
+ return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs,
+ T, VK);
}
-DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
bool HasQualifier,
+ bool HasFoundDecl,
bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs) {
std::size_t Size = sizeof(DeclRefExpr);
if (HasQualifier)
- Size += sizeof(NameQualifier);
-
+ Size += sizeof(NestedNameSpecifierLoc);
+ if (HasFoundDecl)
+ Size += sizeof(NamedDecl *);
if (HasExplicitTemplateArgs)
Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
-
+
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(EmptyShell());
}
@@ -371,7 +352,7 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
SourceRange DeclRefExpr::getSourceRange() const {
SourceRange R = getNameInfo().getSourceRange();
if (hasQualifier())
- R.setBegin(getQualifierRange().getBegin());
+ R.setBegin(getQualifierLoc().getBeginLoc());
if (hasExplicitTemplateArgs())
R.setEnd(getRAngleLoc());
return R;
@@ -518,7 +499,7 @@ double FloatingLiteral::getValueAsApproximateDouble() const {
StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
unsigned ByteLength, bool Wide,
- QualType Ty,
+ bool Pascal, QualType Ty,
const SourceLocation *Loc,
unsigned NumStrs) {
// Allocate enough space for the StringLiteral plus an array of locations for
@@ -534,6 +515,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
SL->StrData = AStrData;
SL->ByteLength = ByteLength;
SL->IsWide = Wide;
+ SL->IsPascal = Pascal;
SL->TokLocs[0] = Loc[0];
SL->NumConcatenated = NumStrs;
@@ -828,11 +810,11 @@ QualType CallExpr::getCallReturnType() const {
CalleeType = FnTypePtr->getPointeeType();
else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>())
CalleeType = BPT->getPointeeType();
- else if (const MemberPointerType *MPT
- = CalleeType->getAs<MemberPointerType>())
- CalleeType = MPT->getPointeeType();
+ else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember))
+ // This should never be overloaded and so should never return null.
+ CalleeType = Expr::findBoundMemberType(getCallee());
- const FunctionType *FnType = CalleeType->getAs<FunctionType>();
+ const FunctionType *FnType = CalleeType->castAs<FunctionType>();
return FnType->getResultType();
}
@@ -906,8 +888,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
}
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
- NestedNameSpecifier *qual,
- SourceRange qualrange,
+ NestedNameSpecifierLoc QualifierLoc,
ValueDecl *memberdecl,
DeclAccessPair founddecl,
DeclarationNameInfo nameinfo,
@@ -917,7 +898,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
ExprObjectKind ok) {
std::size_t Size = sizeof(MemberExpr);
- bool hasQualOrFound = (qual != 0 ||
+ bool hasQualOrFound = (QualifierLoc ||
founddecl.getDecl() != memberdecl ||
founddecl.getAccess() != memberdecl->getAccess());
if (hasQualOrFound)
@@ -931,15 +912,15 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
ty, vk, ok);
if (hasQualOrFound) {
- if (qual && qual->isDependent()) {
+ // FIXME: Wrong. We should be looking at the member declaration we found.
+ if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) {
E->setValueDependent(true);
E->setTypeDependent(true);
}
E->HasQualifierOrFoundDecl = true;
MemberNameQualifier *NQ = E->getMemberQualifier();
- NQ->NNS = qual;
- NQ->Range = qualrange;
+ NQ->QualifierLoc = QualifierLoc;
NQ->FoundDecl = founddecl;
}
@@ -951,6 +932,28 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
return E;
}
+SourceRange MemberExpr::getSourceRange() const {
+ SourceLocation StartLoc;
+ if (isImplicitAccess()) {
+ if (hasQualifier())
+ StartLoc = getQualifierLoc().getBeginLoc();
+ else
+ StartLoc = MemberLoc;
+ } else {
+ // FIXME: We don't want this to happen. Rather, we should be able to
+ // detect all kinds of implicit accesses more cleanly.
+ StartLoc = getBase()->getLocStart();
+ if (StartLoc.isInvalid())
+ StartLoc = MemberLoc;
+ }
+
+ SourceLocation EndLoc =
+ HasExplicitTemplateArgumentList? getRAngleLoc()
+ : getMemberNameInfo().getEndLoc();
+
+ return SourceRange(StartLoc, EndLoc);
+}
+
const char *CastExpr::getCastKindName() const {
switch (getCastKind()) {
case CK_Dependent:
@@ -1241,7 +1244,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
false),
InitExprs(C, numInits),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
- UnionFieldInit(0), HadArrayRangeDesignator(false)
+ HadArrayRangeDesignator(false)
{
for (unsigned I = 0; I != numInits; ++I) {
if (initExprs[I]->isTypeDependent())
@@ -1276,6 +1279,15 @@ Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
return Result;
}
+void InitListExpr::setArrayFiller(Expr *filler) {
+ ArrayFillerOrUnionFieldInit = filler;
+ // Fill out any "holes" in the array due to designated initializers.
+ Expr **inits = getInits();
+ for (unsigned i = 0, e = getNumInits(); i != e; ++i)
+ if (inits[i] == 0)
+ inits[i] = filler;
+}
+
SourceRange InitListExpr::getSourceRange() const {
if (SyntacticForm)
return SyntacticForm->getSourceRange();
@@ -1348,6 +1360,9 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->
isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ case GenericSelectionExprClass:
+ return cast<GenericSelectionExpr>(this)->getResultExpr()->
+ isUnusedResultAWarning(Loc, R1, R2, Ctx);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
@@ -1412,13 +1427,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
return false;
case ConditionalOperatorClass: {
- // The condition must be evaluated, but if either the LHS or RHS is a
- // warning, warn about them.
+ // If only one of the LHS or RHS is a warning, the operator might
+ // be being used for control flow. Only warn if both the LHS and
+ // RHS are warnings.
const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
- if (Exp->getLHS() &&
- Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx))
+ if (!Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx))
+ return false;
+ if (!Exp->getLHS())
return true;
- return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ return Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx);
}
case MemberExprClass:
@@ -1556,21 +1573,20 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
/// isOBJCGCCandidate - Check if an expression is objc gc'able.
/// returns true, if it is; false otherwise.
bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
- switch (getStmtClass()) {
+ const Expr *E = IgnoreParens();
+ switch (E->getStmtClass()) {
default:
return false;
case ObjCIvarRefExprClass:
return true;
case Expr::UnaryOperatorClass:
- return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
- case ParenExprClass:
- return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case ImplicitCastExprClass:
- return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case CStyleCastExprClass:
- return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case DeclRefExprClass: {
- const Decl *D = cast<DeclRefExpr>(this)->getDecl();
+ const Decl *D = cast<DeclRefExpr>(E)->getDecl();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasGlobalStorage())
return true;
@@ -1583,11 +1599,11 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
return false;
}
case MemberExprClass: {
- const MemberExpr *M = cast<MemberExpr>(this);
+ const MemberExpr *M = cast<MemberExpr>(E);
return M->getBase()->isOBJCGCCandidate(Ctx);
}
case ArraySubscriptExprClass:
- return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx);
+ return cast<ArraySubscriptExpr>(E)->getBase()->isOBJCGCCandidate(Ctx);
}
}
@@ -1597,6 +1613,30 @@ bool Expr::isBoundMemberFunction(ASTContext &Ctx) const {
return ClassifyLValue(Ctx) == Expr::LV_MemberFunction;
}
+QualType Expr::findBoundMemberType(const Expr *expr) {
+ assert(expr->getType()->isSpecificPlaceholderType(BuiltinType::BoundMember));
+
+ // Bound member expressions are always one of these possibilities:
+ // x->m x.m x->*y x.*y
+ // (possibly parenthesized)
+
+ expr = expr->IgnoreParens();
+ if (const MemberExpr *mem = dyn_cast<MemberExpr>(expr)) {
+ assert(isa<CXXMethodDecl>(mem->getMemberDecl()));
+ return mem->getMemberDecl()->getType();
+ }
+
+ if (const BinaryOperator *op = dyn_cast<BinaryOperator>(expr)) {
+ QualType type = op->getRHS()->getType()->castAs<MemberPointerType>()
+ ->getPointeeType();
+ assert(type->isFunctionType());
+ return type;
+ }
+
+ assert(isa<UnresolvedMemberExpr>(expr));
+ return QualType();
+}
+
static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
Expr::CanThrowResult CT2) {
// CanThrowResult constants are ordered so that the maximum is the correct
@@ -1613,7 +1653,7 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
return R;
}
-static Expr::CanThrowResult CanCalleeThrow(const Decl *D,
+static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
bool NullThrows = true) {
if (!D)
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
@@ -1643,7 +1683,7 @@ static Expr::CanThrowResult CanCalleeThrow(const Decl *D,
if (!FT)
return Expr::CT_Can;
- return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can;
+ return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
}
static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
@@ -1707,7 +1747,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CallExprClass:
case CXXOperatorCallExprClass:
case CXXMemberCallExprClass: {
- CanThrowResult CT = CanCalleeThrow(cast<CallExpr>(this)->getCalleeDecl());
+ CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@@ -1715,7 +1755,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXConstructExprClass:
case CXXTemporaryObjectExprClass: {
- CanThrowResult CT = CanCalleeThrow(
+ CanThrowResult CT = CanCalleeThrow(C,
cast<CXXConstructExpr>(this)->getConstructor());
if (CT == CT_Can)
return CT;
@@ -1724,8 +1764,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXNewExprClass: {
CanThrowResult CT = MergeCanThrow(
- CanCalleeThrow(cast<CXXNewExpr>(this)->getOperatorNew()),
- CanCalleeThrow(cast<CXXNewExpr>(this)->getConstructor(),
+ CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
+ CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
/*NullThrows*/false));
if (CT == CT_Can)
return CT;
@@ -1733,7 +1773,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXDeleteExprClass: {
- CanThrowResult CT = CanCalleeThrow(
+ CanThrowResult CT = CanCalleeThrow(C,
cast<CXXDeleteExpr>(this)->getOperatorDelete());
if (CT == CT_Can)
return CT;
@@ -1743,7 +1783,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
Arg = Cast->getSubExpr();
if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) {
if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) {
- CanThrowResult CT2 = CanCalleeThrow(
+ CanThrowResult CT2 = CanCalleeThrow(C,
cast<CXXRecordDecl>(RT->getDecl())->getDestructor());
if (CT2 == CT_Can)
return CT2;
@@ -1755,7 +1795,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXBindTemporaryExprClass: {
// The bound temporary has to be destroyed again, which might throw.
- CanThrowResult CT = CanCalleeThrow(
+ CanThrowResult CT = CanCalleeThrow(C,
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
@@ -1810,6 +1850,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
return CT_Dependent;
return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
+ case GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(this)->isResultDependent())
+ return CT_Dependent;
+ return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
+
// Some expressions are always dependent.
case DependentScopeDeclRefExprClass:
case CXXUnresolvedConstructExprClass:
@@ -1836,6 +1881,12 @@ Expr* Expr::IgnoreParens() {
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1859,6 +1910,12 @@ Expr *Expr::IgnoreParenCasts() {
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1883,6 +1940,11 @@ Expr *Expr::IgnoreParenLValueCasts() {
E = P->getSubExpr();
continue;
}
+ } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
}
break;
}
@@ -1906,6 +1968,12 @@ Expr *Expr::IgnoreParenImpCasts() {
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1948,6 +2016,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
+
return E;
}
}
@@ -2023,6 +2098,42 @@ bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
return true;
}
+bool Expr::isImplicitCXXThis() const {
+ const Expr *E = this;
+
+ // Strip away parentheses and casts we don't care about.
+ while (true) {
+ if (const ParenExpr *Paren = dyn_cast<ParenExpr>(E)) {
+ E = Paren->getSubExpr();
+ continue;
+ }
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_LValueToRValue ||
+ ICE->getCastKind() == CK_DerivedToBase ||
+ ICE->getCastKind() == CK_UncheckedDerivedToBase) {
+ E = ICE->getSubExpr();
+ continue;
+ }
+ }
+
+ if (const UnaryOperator* UnOp = dyn_cast<UnaryOperator>(E)) {
+ if (UnOp->getOpcode() == UO_Extension) {
+ E = UnOp->getSubExpr();
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ if (const CXXThisExpr *This = dyn_cast<CXXThisExpr>(E))
+ return This->isImplicit();
+
+ return false;
+}
+
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {
@@ -2103,6 +2214,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()
->isConstantInitializer(Ctx, IsForRef);
+ case GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(this)->isResultDependent())
+ return false;
+ return cast<GenericSelectionExpr>(this)->getResultExpr()
+ ->isConstantInitializer(Ctx, IsForRef);
case ChooseExprClass:
return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
->isConstantInitializer(Ctx, IsForRef);
@@ -2189,6 +2305,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// Accept ((void*)0) as a null pointer constant, as many other
// implementations do.
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const GenericSelectionExpr *GE =
+ dyn_cast<GenericSelectionExpr>(this)) {
+ return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions
@@ -2587,6 +2706,51 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
}
+GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack,
+ unsigned ResultIndex)
+ : Expr(GenericSelectionExprClass,
+ AssocExprs[ResultIndex]->getType(),
+ AssocExprs[ResultIndex]->getValueKind(),
+ AssocExprs[ResultIndex]->getObjectKind(),
+ AssocExprs[ResultIndex]->isTypeDependent(),
+ AssocExprs[ResultIndex]->isValueDependent(),
+ ContainsUnexpandedParameterPack),
+ AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
+ SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
+ 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);
+}
+
+GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack)
+ : Expr(GenericSelectionExprClass,
+ Context.DependentTy,
+ VK_RValue,
+ OK_Ordinary,
+ /*isTypeDependent=*/ true,
+ /*isValueDependent=*/ true,
+ ContainsUnexpandedParameterPack),
+ AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
+ SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
+ 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);
+}
+
//===----------------------------------------------------------------------===//
// DesignatedInitExpr
//===----------------------------------------------------------------------===//
@@ -2688,6 +2852,14 @@ void DesignatedInitExpr::setDesignators(ASTContext &C,
Designators[I] = Desigs[I];
}
+SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
+ DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this);
+ if (size() == 1)
+ return DIE->getDesignator(0)->getSourceRange();
+ return SourceRange(DIE->getDesignator(0)->getStartLocation(),
+ DIE->getDesignator(size()-1)->getEndLocation());
+}
+
SourceRange DesignatedInitExpr::getSourceRange() const {
SourceLocation StartLoc;
Designator &First =
@@ -2802,8 +2974,8 @@ const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); }
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
-// SizeOfAlignOfExpr
-Stmt::child_range SizeOfAlignOfExpr::children() {
+// UnaryExprOrTypeTraitExpr
+Stmt::child_range UnaryExprOrTypeTraitExpr::children() {
// If this is of a type and the type is a VLA type (and not a typedef), the
// size expression of the VLA needs to be treated as an executable expression.
// Why isn't this weirdness documented better in StmtIterator?
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 4f4a6b4944d9..1a1a0a36a65b 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -100,6 +100,10 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
SubExprs = new (C) Stmt*[TotalSize];
}
+bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
+ return getOperatorNew()->getType()->
+ castAs<FunctionProtoType>()->isNothrow(Ctx);
+}
// CXXDeleteExpr
QualType CXXDeleteExpr::getDestroyedType() const {
@@ -174,8 +178,7 @@ SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
UnresolvedLookupExpr *
UnresolvedLookupExpr::Create(ASTContext &C,
CXXRecordDecl *NamingClass,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool ADL,
const TemplateArgumentListInfo &Args,
@@ -184,10 +187,9 @@ UnresolvedLookupExpr::Create(ASTContext &C,
{
void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
ExplicitTemplateArgumentList::sizeFor(Args));
- return new (Mem) UnresolvedLookupExpr(C, NamingClass,
- Qualifier, QualifierRange, NameInfo,
+ return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
ADL, /*Overload*/ true, &Args,
- Begin, End);
+ Begin, End, /*StdIsAssociated=*/false);
}
UnresolvedLookupExpr *
@@ -204,7 +206,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
}
OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
- NestedNameSpecifier *Qualifier, SourceRange QRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
@@ -215,10 +217,11 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
KnownDependent,
(KnownContainsUnexpandedParameterPack ||
NameInfo.containsUnexpandedParameterPack() ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()))),
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()))),
Results(0), NumResults(End - Begin), NameInfo(NameInfo),
- Qualifier(Qualifier), QualifierRange(QRange),
- HasExplicitTemplateArgs(TemplateArgs != 0)
+ QualifierLoc(QualifierLoc), HasExplicitTemplateArgs(TemplateArgs != 0)
{
NumResults = End - Begin;
if (NumResults) {
@@ -365,8 +368,10 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const {
getArg(0)->getSourceRange().getEnd());
else
// Postfix operator
- return SourceRange(getArg(0)->getSourceRange().getEnd(),
+ return SourceRange(getArg(0)->getSourceRange().getBegin(),
getOperatorLoc());
+ } else if (Kind == OO_Arrow) {
+ return getArg(0)->getSourceRange();
} else if (Kind == OO_Call) {
return SourceRange(getArg(0)->getSourceRange().getBegin(), getRParenLoc());
} else if (Kind == OO_Subscript) {
@@ -381,14 +386,25 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const {
}
}
-Expr *CXXMemberCallExpr::getImplicitObjectArgument() {
- if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
+Expr *CXXMemberCallExpr::getImplicitObjectArgument() const {
+ if (const MemberExpr *MemExpr =
+ dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
return MemExpr->getBase();
// FIXME: Will eventually need to cope with member pointers.
return 0;
}
+CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
+ if (const MemberExpr *MemExpr =
+ dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
+ return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+
+ // FIXME: Will eventually need to cope with member pointers.
+ return 0;
+}
+
+
CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() {
Expr* ThisArg = getImplicitObjectArgument();
if (!ThisArg)
@@ -466,6 +482,36 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C,
return new (Buffer) CXXDynamicCastExpr(EmptyShell(), PathSize);
}
+/// isAlwaysNull - Return whether the result of the dynamic_cast is proven
+/// to always be null. For example:
+///
+/// struct A { };
+/// struct B final : A { };
+/// struct C { };
+///
+/// C *f(B* b) { return dynamic_cast<C*>(b); }
+bool CXXDynamicCastExpr::isAlwaysNull() const
+{
+ QualType SrcType = getSubExpr()->getType();
+ QualType DestType = getType();
+
+ if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) {
+ SrcType = SrcPTy->getPointeeType();
+ DestType = DestType->castAs<PointerType>()->getPointeeType();
+ }
+
+ const CXXRecordDecl *SrcRD =
+ cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl());
+
+ if (!SrcRD->hasAttr<FinalAttr>())
+ return false;
+
+ const CXXRecordDecl *DestRD =
+ cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl());
+
+ return !DestRD->isDerivedFrom(SrcRD);
+}
+
CXXReinterpretCastExpr *
CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
CastKind K, Expr *Op,
@@ -689,20 +735,20 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
VK_LValue, OK_Ordinary, true, true,
((Base && Base->containsUnexpandedParameterPack()) ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
HasExplicitTemplateArgs(TemplateArgs != 0),
- OperatorLoc(OperatorLoc),
- Qualifier(Qualifier), QualifierRange(QualifierRange),
+ OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) {
if (TemplateArgs) {
@@ -719,18 +765,19 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
VK_LValue, OK_Ordinary, true, true,
((Base && Base->containsUnexpandedParameterPack()) ||
- (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ (QualifierLoc &&
+ QualifierLoc.getNestedNameSpecifier()->
+ containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc),
- Qualifier(Qualifier), QualifierRange(QualifierRange),
+ QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) { }
@@ -738,15 +785,14 @@ CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
if (!TemplateArgs)
return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
+ QualifierLoc,
FirstQualifierFoundInScope,
MemberNameInfo);
@@ -757,7 +803,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
+ QualifierLoc,
FirstQualifierFoundInScope,
MemberNameInfo, TemplateArgs);
}
@@ -768,8 +814,8 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
unsigned NumTemplateArgs) {
if (!HasExplicitTemplateArgs)
return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(),
- 0, SourceLocation(), 0,
- SourceRange(), 0,
+ 0, SourceLocation(),
+ NestedNameSpecifierLoc(), 0,
DeclarationNameInfo());
std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
@@ -777,26 +823,53 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
CXXDependentScopeMemberExpr *E
= new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(),
- 0, SourceLocation(), 0,
- SourceRange(), 0,
+ 0, SourceLocation(),
+ NestedNameSpecifierLoc(), 0,
DeclarationNameInfo(), 0);
E->HasExplicitTemplateArgs = true;
return E;
}
+bool CXXDependentScopeMemberExpr::isImplicitAccess() const {
+ if (Base == 0)
+ return true;
+
+ return cast<Expr>(Base)->isImplicitCXXThis();
+}
+
+static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,
+ UnresolvedSetIterator end) {
+ do {
+ NamedDecl *decl = *begin;
+ if (isa<UnresolvedUsingValueDecl>(decl))
+ return false;
+ if (isa<UsingShadowDecl>(decl))
+ decl = cast<UsingShadowDecl>(decl)->getUnderlyingDecl();
+
+ // Unresolved member expressions should only contain methods and
+ // method templates.
+ assert(isa<CXXMethodDecl>(decl) || isa<FunctionTemplateDecl>(decl));
+
+ if (isa<FunctionTemplateDecl>(decl))
+ decl = cast<FunctionTemplateDecl>(decl)->getTemplatedDecl();
+ if (cast<CXXMethodDecl>(decl)->isStatic())
+ return false;
+ } while (++begin != end);
+
+ return true;
+}
+
UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End)
- : OverloadExpr(UnresolvedMemberExprClass, C,
- Qualifier, QualifierRange, MemberNameInfo,
+ : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, MemberNameInfo,
TemplateArgs, Begin, End,
// Dependent
((Base && Base->isTypeDependent()) ||
@@ -806,6 +879,18 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
BaseType->containsUnexpandedParameterPack())),
IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) {
+
+ // Check whether all of the members are non-static member functions,
+ // and if so, mark give this bound-member type instead of overload type.
+ if (hasOnlyNonStaticMemberFunctions(Begin, End))
+ setType(C.BoundMemberTy);
+}
+
+bool UnresolvedMemberExpr::isImplicitAccess() const {
+ if (Base == 0)
+ return true;
+
+ return cast<Expr>(Base)->isImplicitCXXThis();
}
UnresolvedMemberExpr *
@@ -813,8 +898,7 @@ UnresolvedMemberExpr::Create(ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
@@ -826,7 +910,7 @@ UnresolvedMemberExpr::Create(ASTContext &C,
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
return new (Mem) UnresolvedMemberExpr(C,
HasUnresolvedUsing, Base, BaseType,
- IsArrow, OperatorLoc, Qualifier, QualifierRange,
+ IsArrow, OperatorLoc, QualifierLoc,
MemberNameInfo, TemplateArgs, Begin, End);
}
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 890898a985e8..888a93c8aac0 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -61,8 +61,10 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
if (TR->isFunctionType() || TR == Ctx.OverloadTy)
kind = Cl::CL_Function;
// No void either, but qualified void is OK because it is "other than void".
- else if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers())
- kind = Cl::CL_Void;
+ // Void "lvalues" are classified as addressable void values, which are void
+ // expressions whose address can be taken.
+ else if (TR->isVoidType() && !TR.hasQualifiers())
+ kind = (kind == Cl::CL_LValue ? Cl::CL_AddressableVoid : Cl::CL_Void);
}
// Enable this assertion for testing.
@@ -71,10 +73,12 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break;
case Cl::CL_Function:
case Cl::CL_Void:
+ case Cl::CL_AddressableVoid:
case Cl::CL_DuplicateVectorComponents:
case Cl::CL_MemberFunction:
case Cl::CL_SubObjCPropertySetting:
case Cl::CL_ClassTemporary:
+ case Cl::CL_ObjCMessageRValue:
case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break;
}
@@ -128,7 +132,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// Expressions that are prvalues.
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXPseudoDestructorExprClass:
- case Expr::SizeOfAlignOfExprClass:
+ case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::CXXNewExprClass:
case Expr::CXXThisExprClass:
case Expr::CXXNullPtrLiteralExprClass:
@@ -148,6 +152,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXScalarValueInitExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::ArrayTypeTraitExprClass:
+ case Expr::ExpressionTraitExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCStringLiteralClass:
@@ -169,6 +175,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// C++ [expr.prim.general]p3: The result is an lvalue if the entity is a
// function or variable and a prvalue otherwise.
case Expr::DeclRefExprClass:
+ if (E->getType() == Ctx.UnknownAnyTy)
+ return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl())
+ ? Cl::CL_PRValue : Cl::CL_LValue;
return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl());
// We deal with names referenced from blocks the same way.
case Expr::BlockDeclRefExprClass:
@@ -229,6 +238,14 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ParenExprClass:
return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr());
+ // C1X 6.5.1.1p4: [A generic selection] is an lvalue, a function designator,
+ // or a void expression if its result expression is, respectively, an
+ // lvalue, a function designator, or a void expression.
+ case Expr::GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(E)->isResultDependent())
+ return Cl::CL_PRValue;
+ return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr());
+
case Expr::BinaryOperatorClass:
case Expr::CompoundAssignOperatorClass:
// C doesn't have any binary expressions that are lvalues.
@@ -293,7 +310,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ObjCMessageExprClass:
if (const ObjCMethodDecl *Method =
cast<ObjCMessageExpr>(E)->getMethodDecl()) {
- return ClassifyUnnamed(Ctx, Method->getResultType());
+ Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getResultType());
+ return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind;
}
return Cl::CL_PRValue;
@@ -373,6 +391,10 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) {
}
static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
+ if (E->getType() == Ctx.UnknownAnyTy)
+ return (isa<FunctionDecl>(E->getMemberDecl())
+ ? Cl::CL_PRValue : Cl::CL_LValue);
+
// Handle C first, it's easier.
if (!Ctx.getLangOptions().CPlusPlus) {
// C99 6.5.2.3p3
@@ -546,11 +568,13 @@ Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const {
case Cl::CL_LValue: return LV_Valid;
case Cl::CL_XValue: return LV_InvalidExpression;
case Cl::CL_Function: return LV_NotObjectType;
- case Cl::CL_Void: return LV_IncompleteVoidType;
+ case Cl::CL_Void: return LV_InvalidExpression;
+ case Cl::CL_AddressableVoid: return LV_IncompleteVoidType;
case Cl::CL_DuplicateVectorComponents: return LV_DuplicateVectorComponents;
case Cl::CL_MemberFunction: return LV_MemberFunction;
case Cl::CL_SubObjCPropertySetting: return LV_SubObjCPropertySetting;
case Cl::CL_ClassTemporary: return LV_ClassTemporary;
+ case Cl::CL_ObjCMessageRValue: return LV_InvalidMessageExpression;
case Cl::CL_PRValue: return LV_InvalidExpression;
}
llvm_unreachable("Unhandled kind");
@@ -564,11 +588,13 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
case Cl::CL_LValue: break;
case Cl::CL_XValue: return MLV_InvalidExpression;
case Cl::CL_Function: return MLV_NotObjectType;
- case Cl::CL_Void: return MLV_IncompleteVoidType;
+ case Cl::CL_Void: return MLV_InvalidExpression;
+ case Cl::CL_AddressableVoid: return MLV_IncompleteVoidType;
case Cl::CL_DuplicateVectorComponents: return MLV_DuplicateVectorComponents;
case Cl::CL_MemberFunction: return MLV_MemberFunction;
case Cl::CL_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
case Cl::CL_ClassTemporary: return MLV_ClassTemporary;
+ case Cl::CL_ObjCMessageRValue: return MLV_InvalidMessageExpression;
case Cl::CL_PRValue:
return VC.getModifiable() == Cl::CM_LValueCast ?
MLV_LValueCast : MLV_InvalidExpression;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 3a5eb66ea18f..c2caf8d40b16 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -42,25 +42,25 @@ using llvm::APFloat;
/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
/// evaluate the expression regardless of what the RHS is, but C only allows
/// certain things in certain situations.
-struct EvalInfo {
- const ASTContext &Ctx;
-
- /// EvalResult - Contains information about the evaluation.
- Expr::EvalResult &EvalResult;
-
- llvm::DenseMap<const OpaqueValueExpr*, APValue> OpaqueValues;
- const APValue *getOpaqueValue(const OpaqueValueExpr *e) {
- llvm::DenseMap<const OpaqueValueExpr*, APValue>::iterator
- i = OpaqueValues.find(e);
- if (i == OpaqueValues.end()) return 0;
- return &i->second;
- }
+namespace {
+ struct EvalInfo {
+ const ASTContext &Ctx;
+
+ /// EvalResult - Contains information about the evaluation.
+ Expr::EvalResult &EvalResult;
+
+ typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy;
+ MapTy OpaqueValues;
+ const APValue *getOpaqueValue(const OpaqueValueExpr *e) const {
+ MapTy::const_iterator i = OpaqueValues.find(e);
+ if (i == OpaqueValues.end()) return 0;
+ return &i->second;
+ }
- EvalInfo(const ASTContext &ctx, Expr::EvalResult& evalresult)
- : Ctx(ctx), EvalResult(evalresult) {}
-};
+ EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult)
+ : Ctx(ctx), EvalResult(evalresult) {}
+ };
-namespace {
struct ComplexValue {
private:
bool IsInt;
@@ -175,7 +175,7 @@ static bool EvalPointerValueAsBool(LValue& Value, bool& Result) {
const ValueDecl* Decl = DeclRef->getDecl();
if (Decl->hasAttr<WeakAttr>() ||
Decl->hasAttr<WeakRefAttr>() ||
- Decl->hasAttr<WeakImportAttr>())
+ Decl->isWeakImported())
return false;
return true;
@@ -274,6 +274,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
@@ -290,7 +293,8 @@ public:
bool VisitFloatingLiteral(FloatingLiteral *E) { return false; }
bool VisitStringLiteral(StringLiteral *E) { return false; }
bool VisitCharacterLiteral(CharacterLiteral *E) { return false; }
- bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return false; }
+ bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E)
+ { return false; }
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E)
{ return Visit(E->getLHS()) || Visit(E->getRHS()); }
bool VisitChooseExpr(ChooseExpr *E)
@@ -315,6 +319,8 @@ public:
bool VisitInitListExpr(InitListExpr *E) {
for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
if (Visit(E->getInit(i))) return true;
+ if (Expr *filler = E->getArrayFiller())
+ return Visit(filler);
return false;
}
@@ -371,6 +377,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitDeclRefExpr(DeclRefExpr *E);
bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); }
bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
@@ -500,6 +509,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitCastExpr(CastExpr* E);
@@ -589,7 +601,6 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
case CK_NoOp:
case CK_BitCast:
- case CK_LValueBitCast:
case CK_AnyPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
return Visit(SubExpr);
@@ -717,6 +728,8 @@ namespace {
APValue VisitParenExpr(ParenExpr *E)
{ return Visit(E->getSubExpr()); }
+ APValue VisitGenericSelectionExpr(GenericSelectionExpr *E)
+ { return Visit(E->getResultExpr()); }
APValue VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
APValue VisitUnaryPlus(const UnaryOperator *E)
@@ -755,68 +768,61 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
const Expr* SE = E->getSubExpr();
QualType SETy = SE->getType();
- APValue Result = APValue();
-
- // Check for vector->vector bitcast and scalar->vector splat.
- if (SETy->isVectorType()) {
- return this->Visit(const_cast<Expr*>(SE));
- } else if (SETy->isIntegerType()) {
- APSInt IntResult;
- if (!EvaluateInteger(SE, IntResult, Info))
- return APValue();
- Result = APValue(IntResult);
- } else if (SETy->isRealFloatingType()) {
- APFloat F(0.0);
- if (!EvaluateFloat(SE, F, Info))
- return APValue();
- Result = APValue(F);
- } else
- return APValue();
- // For casts of a scalar to ExtVector, convert the scalar to the element type
- // and splat it to all elements.
- if (E->getType()->isExtVectorType()) {
- if (EltTy->isIntegerType() && Result.isInt())
- Result = APValue(HandleIntToIntCast(EltTy, SETy, Result.getInt(),
- Info.Ctx));
- else if (EltTy->isIntegerType())
- Result = APValue(HandleFloatToIntCast(EltTy, SETy, Result.getFloat(),
- Info.Ctx));
- else if (EltTy->isRealFloatingType() && Result.isInt())
- Result = APValue(HandleIntToFloatCast(EltTy, SETy, Result.getInt(),
- Info.Ctx));
- else if (EltTy->isRealFloatingType())
- Result = APValue(HandleFloatToFloatCast(EltTy, SETy, Result.getFloat(),
- Info.Ctx));
- else
+ switch (E->getCastKind()) {
+ case CK_VectorSplat: {
+ APValue Result = APValue();
+ if (SETy->isIntegerType()) {
+ APSInt IntResult;
+ if (!EvaluateInteger(SE, IntResult, Info))
+ return APValue();
+ Result = APValue(IntResult);
+ } else if (SETy->isRealFloatingType()) {
+ APFloat F(0.0);
+ if (!EvaluateFloat(SE, F, Info))
+ return APValue();
+ Result = APValue(F);
+ } else {
return APValue();
+ }
// Splat and create vector APValue.
llvm::SmallVector<APValue, 4> Elts(NElts, Result);
return APValue(&Elts[0], Elts.size());
}
+ case CK_BitCast: {
+ if (SETy->isVectorType())
+ return Visit(const_cast<Expr*>(SE));
- // For casts of a scalar to regular gcc-style vector type, bitcast the scalar
- // to the vector. To construct the APValue vector initializer, bitcast the
- // initializing value to an APInt, and shift out the bits pertaining to each
- // element.
- APSInt Init;
- Init = Result.isInt() ? Result.getInt() : Result.getFloat().bitcastToAPInt();
-
- llvm::SmallVector<APValue, 4> Elts;
- for (unsigned i = 0; i != NElts; ++i) {
- APSInt Tmp = Init.extOrTrunc(EltWidth);
+ if (!SETy->isIntegerType())
+ return APValue();
- if (EltTy->isIntegerType())
- Elts.push_back(APValue(Tmp));
- else if (EltTy->isRealFloatingType())
- Elts.push_back(APValue(APFloat(Tmp)));
- else
+ APSInt Init;
+ if (!EvaluateInteger(SE, Init, Info))
return APValue();
- Init >>= EltWidth;
+ assert((EltTy->isIntegerType() || EltTy->isRealFloatingType()) &&
+ "Vectors must be composed of ints or floats");
+
+ llvm::SmallVector<APValue, 4> Elts;
+ for (unsigned i = 0; i != NElts; ++i) {
+ APSInt Tmp = Init.extOrTrunc(EltWidth);
+
+ if (EltTy->isIntegerType())
+ Elts.push_back(APValue(Tmp));
+ else
+ Elts.push_back(APValue(APFloat(Tmp)));
+
+ Init >>= EltWidth;
+ }
+ return APValue(&Elts[0], Elts.size());
+ }
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return Visit(const_cast<Expr*>(SE));
+ default:
+ return APValue();
}
- return APValue(&Elts[0], Elts.size());
}
APValue
@@ -837,6 +843,12 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// becomes every element of the vector, not just the first.
// This is the behavior described in the IBM AltiVec documentation.
if (NumInits == 1) {
+
+ // Handle the case where the vector is initialized by a another
+ // vector (OpenCL 6.1.6).
+ if (E->getInit(0)->getType()->isVectorType())
+ return this->Visit(const_cast<Expr*>(E->getInit(0)));
+
APValue InitValue;
if (EltTy->isIntegerType()) {
llvm::APSInt sInt(32);
@@ -953,6 +965,11 @@ public:
return true;
}
+ bool Success(CharUnits Size, const Expr *E) {
+ return Success(Size.getQuantity(), E);
+ }
+
+
bool Error(SourceLocation L, diag::kind D, const Expr *E) {
// Take the first error.
if (Info.EvalResult.Diag == 0) {
@@ -977,6 +994,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitIntegerLiteral(const IntegerLiteral *E) {
return Success(E->getValue(), E);
@@ -1015,7 +1035,7 @@ public:
bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
bool VisitCastExpr(CastExpr* E);
- bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
+ bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
return Success(E->getValue(), E);
@@ -1041,6 +1061,14 @@ public:
return Success(E->getValue(), E);
}
+ bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
+ return Success(E->getValue(), E);
+ }
+
+ bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
+ return Success(E->getValue(), E);
+ }
+
bool VisitChooseExpr(const ChooseExpr *E) {
return Visit(E->getChosenSubExpr(Info.Ctx));
}
@@ -1213,7 +1241,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) {
Size -= Offset;
else
Size = CharUnits::Zero();
- return Success(Size.getQuantity(), E);
+ return Success(Size, E);
}
bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
@@ -1596,36 +1624,59 @@ CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
}
-/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the
-/// expression's type.
-bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
- // Handle alignof separately.
- if (!E->isSizeOf()) {
+/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
+/// a result as the expression's type.
+bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *E) {
+ switch(E->getKind()) {
+ case UETT_AlignOf: {
if (E->isArgumentType())
- return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E);
+ return Success(GetAlignOfType(E->getArgumentType()), E);
else
- return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E);
+ return Success(GetAlignOfExpr(E->getArgumentExpr()), E);
}
- QualType SrcTy = E->getTypeOfArgument();
- // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
- // the result is the size of the referenced type."
- // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
- // result shall be the alignment of the referenced type."
- if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
- SrcTy = Ref->getPointeeType();
+ case UETT_VecStep: {
+ QualType Ty = E->getTypeOfArgument();
- // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
- // extension.
- if (SrcTy->isVoidType() || SrcTy->isFunctionType())
- return Success(1, E);
+ if (Ty->isVectorType()) {
+ unsigned n = Ty->getAs<VectorType>()->getNumElements();
- // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
- if (!SrcTy->isConstantSizeType())
- return false;
+ // The vec_step built-in functions that take a 3-component
+ // vector return 4. (OpenCL 1.1 spec 6.11.12)
+ if (n == 3)
+ n = 4;
+
+ return Success(n, E);
+ } else
+ return Success(1, E);
+ }
+
+ case UETT_SizeOf: {
+ QualType SrcTy = E->getTypeOfArgument();
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
+ SrcTy = Ref->getPointeeType();
+
+ // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
+ // extension.
+ if (SrcTy->isVoidType() || SrcTy->isFunctionType())
+ return Success(1, E);
+
+ // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ if (!SrcTy->isConstantSizeType())
+ return false;
+
+ // Get information about the size.
+ return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E);
+ }
+ }
- // Get information about the size.
- return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
+ llvm_unreachable("unknown expr/type trait");
+ return false;
}
bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
@@ -1694,7 +1745,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
}
}
}
- return Success(Result.getQuantity(), E);
+ return Success(Result, E);
}
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
@@ -1742,15 +1793,60 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
QualType DestType = E->getType();
QualType SrcType = SubExpr->getType();
- if (DestType->isBooleanType()) {
+ switch (E->getCastKind()) {
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_NullToPointer:
+ case CK_NullToMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_ConstructorConversion:
+ case CK_IntegralToPointer:
+ case CK_ToVoid:
+ case CK_VectorSplat:
+ case CK_IntegralToFloating:
+ case CK_FloatingCast:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast:
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ llvm_unreachable("invalid cast kind for integral value");
+
+ case CK_BitCast:
+ case CK_Dependent:
+ case CK_GetObjCProperty:
+ case CK_LValueBitCast:
+ case CK_UserDefinedConversion:
+ return false;
+
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return Visit(E->getSubExpr());
+
+ case CK_MemberPointerToBoolean:
+ case CK_PointerToBoolean:
+ case CK_IntegralToBoolean:
+ case CK_FloatingToBoolean:
+ case CK_FloatingComplexToBoolean:
+ case CK_IntegralComplexToBoolean: {
bool BoolResult;
if (!HandleConversionToBool(SubExpr, BoolResult, Info))
return false;
return Success(BoolResult, E);
}
- // Handle simple integer->integer casts.
- if (SrcType->isIntegralOrEnumerationType()) {
+ case CK_IntegralCast: {
if (!Visit(SubExpr))
return false;
@@ -1763,8 +1859,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
Result.getInt(), Info.Ctx), E);
}
- // FIXME: Clean this up!
- if (SrcType->isPointerType()) {
+ case CK_PointerToIntegral: {
LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
return false;
@@ -1783,42 +1878,24 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
}
- if (SrcType->isArrayType() || SrcType->isFunctionType()) {
- // This handles double-conversion cases, where there's both
- // an l-value promotion and an implicit conversion to int.
- LValue LV;
- if (!EvaluateLValue(SubExpr, LV, Info))
- return false;
-
- if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(Info.Ctx.VoidPtrTy))
- return false;
-
- LV.moveInto(Result);
- return true;
- }
-
- if (SrcType->isAnyComplexType()) {
+ case CK_IntegralComplexToReal: {
ComplexValue C;
if (!EvaluateComplex(SubExpr, C, Info))
return false;
- if (C.isComplexFloat())
- return Success(HandleFloatToIntCast(DestType, SrcType,
- C.getComplexFloatReal(), Info.Ctx),
- E);
- else
- return Success(HandleIntToIntCast(DestType, SrcType,
- C.getComplexIntReal(), Info.Ctx), E);
+ return Success(C.getComplexIntReal(), E);
}
- // FIXME: Handle vectors
- if (!SrcType->isRealFloatingType())
- return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ case CK_FloatingToIntegral: {
+ APFloat F(0.0);
+ if (!EvaluateFloat(SubExpr, F, Info))
+ return false;
- APFloat F(0.0);
- if (!EvaluateFloat(SubExpr, F, Info))
- return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+ }
+ }
- return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+ llvm_unreachable("unknown cast resulting in integral value");
+ return false;
}
bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -1871,6 +1948,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -2119,7 +2199,15 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
Expr* SubExpr = E->getSubExpr();
- if (SubExpr->getType()->isIntegralOrEnumerationType()) {
+ switch (E->getCastKind()) {
+ default:
+ return false;
+
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return Visit(SubExpr);
+
+ case CK_IntegralToFloating: {
APSInt IntResult;
if (!EvaluateInteger(SubExpr, IntResult, Info))
return false;
@@ -2127,7 +2215,8 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
IntResult, Info.Ctx);
return true;
}
- if (SubExpr->getType()->isRealFloatingType()) {
+
+ case CK_FloatingCast: {
if (!Visit(SubExpr))
return false;
Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(),
@@ -2135,13 +2224,14 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
return true;
}
- if (E->getCastKind() == CK_FloatingComplexToReal) {
+ case CK_FloatingComplexToReal: {
ComplexValue V;
if (!EvaluateComplex(SubExpr, V, Info))
return false;
Result = V.getComplexFloatReal();
return true;
}
+ }
return false;
}
@@ -2194,6 +2284,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitImaginaryLiteral(ImaginaryLiteral *E);
@@ -2253,7 +2346,6 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
case CK_BitCast:
- case CK_LValueBitCast:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
@@ -2293,6 +2385,7 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
case CK_Dependent:
case CK_GetObjCProperty:
+ case CK_LValueBitCast:
case CK_UserDefinedConversion:
return false;
@@ -2782,12 +2875,16 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ParenExprClass:
return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
+ case Expr::GenericSelectionExprClass:
+ return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx);
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::ArrayTypeTraitExprClass:
+ case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
return NoDiag();
case Expr::CallExprClass:
@@ -2879,9 +2976,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// are ICEs, the value of the offsetof must be an integer constant.
return CheckEvalInICE(E, Ctx);
}
- case Expr::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
- if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
+ case Expr::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
+ if ((Exp->getKind() == UETT_SizeOf) &&
+ Exp->getTypeOfArgument()->isVariableArrayType())
return ICEDiag(2, E->getLocStart());
return NoDiag();
}
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
new file mode 100644
index 000000000000..89bf56db1af7
--- /dev/null
+++ b/lib/AST/ExternalASTSource.cpp
@@ -0,0 +1,59 @@
+//===- ExternalASTSource.cpp - Abstract External AST Interface --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides the default implementation of the ExternalASTSource
+// interface, which enables construction of AST nodes from some external
+// source.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/DeclarationName.h"
+
+using namespace clang;
+
+ExternalASTSource::~ExternalASTSource() { }
+
+void ExternalASTSource::PrintStats() { }
+
+Decl *ExternalASTSource::GetExternalDecl(uint32_t ID) {
+ return 0;
+}
+
+Selector ExternalASTSource::GetExternalSelector(uint32_t ID) {
+ return Selector();
+}
+
+uint32_t ExternalASTSource::GetNumExternalSelectors() {
+ return 0;
+}
+
+Stmt *ExternalASTSource::GetExternalDeclStmt(uint64_t Offset) {
+ return 0;
+}
+
+CXXBaseSpecifier *
+ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
+ return 0;
+}
+
+DeclContextLookupResult
+ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ return DeclContext::lookup_result();
+}
+
+void ExternalASTSource::MaterializeVisibleDecls(const DeclContext *DC) { }
+
+bool
+ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ llvm::SmallVectorImpl<Decl*> &Result) {
+ return true;
+}
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index 533a2329c583..c47a9dadbadd 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/TypeOrdering.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
@@ -136,28 +135,34 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
- // Create temp directory
- SmallString<128> Filename;
- int FileFD = 0;
- if (error_code ec = sys::fs::unique_file(
- "clang-class-inheritance-hierarchy-%%-%%-%%-%%-" +
- Self.getAsString() + ".dot",
- FileFD, Filename)) {
- errs() << "Error creating temporary output file: " << ec.message() << '\n';
+ std::string ErrMsg;
+ sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
+ if (Filename.isEmpty()) {
+ llvm::errs() << "Error: " << ErrMsg << "\n";
+ return;
+ }
+ Filename.appendComponent(Self.getAsString() + ".dot");
+ if (Filename.makeUnique(true,&ErrMsg)) {
+ llvm::errs() << "Error: " << ErrMsg << "\n";
return;
}
- llvm::errs() << "Writing '" << Filename << "'... ";
+ llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
- llvm::raw_fd_ostream O(FileFD, true);
- InheritanceHierarchyWriter Writer(Context, O);
- Writer.WriteGraph(Self);
+ llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg);
- llvm::errs() << " done. \n";
- O.close();
+ if (ErrMsg.empty()) {
+ InheritanceHierarchyWriter Writer(Context, O);
+ Writer.WriteGraph(Self);
+ llvm::errs() << " done. \n";
- // Display the graph
- DisplayGraph(sys::Path(Filename));
+ O.close();
+
+ // Display the graph
+ DisplayGraph(Filename);
+ } else {
+ llvm::errs() << "error opening file for writing!\n";
+ }
}
}
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index bed02b4c0010..30aece3ee73b 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ AST support targetting the Itanium C++ ABI, which is
+// This provides C++ AST support targeting the Itanium C++ ABI, which is
// documented at:
// http://www.codesourcery.com/public/cxx-abi/abi.html
// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 939ca7a924aa..c460929c461d 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -50,18 +51,16 @@ static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
return 0;
}
-static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
- assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
- "Passed in decl is not a ctor or dtor!");
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+ if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+ return ftd->getTemplatedDecl();
- if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
- MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
-
- assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
- "Templated decl is not a ctor or dtor!");
- }
+ return fn;
+}
- return MD;
+static const NamedDecl *getStructor(const NamedDecl *decl) {
+ const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
+ return (fn ? getStructor(fn) : decl);
}
static const unsigned UnknownArity = ~0U;
@@ -138,27 +137,75 @@ class CXXNameMangler {
ItaniumMangleContext &Context;
llvm::raw_ostream &Out;
- const CXXMethodDecl *Structor;
+ /// The "structor" is the top-level declaration being mangled, if
+ /// that's not a template specialization; otherwise it's the pattern
+ /// for that specialization.
+ const NamedDecl *Structor;
unsigned StructorType;
/// SeqID - The next subsitution sequence number.
unsigned SeqID;
+ class FunctionTypeDepthState {
+ unsigned Bits;
+
+ enum { InResultTypeMask = 1 };
+
+ public:
+ FunctionTypeDepthState() : Bits(0) {}
+
+ /// The number of function types we're inside.
+ unsigned getDepth() const {
+ return Bits >> 1;
+ }
+
+ /// True if we're in the return type of the innermost function type.
+ bool isInResultType() const {
+ return Bits & InResultTypeMask;
+ }
+
+ FunctionTypeDepthState push() {
+ FunctionTypeDepthState tmp = *this;
+ Bits = (Bits & ~InResultTypeMask) + 2;
+ return tmp;
+ }
+
+ void enterResultType() {
+ Bits |= InResultTypeMask;
+ }
+
+ void leaveResultType() {
+ Bits &= ~InResultTypeMask;
+ }
+
+ void pop(FunctionTypeDepthState saved) {
+ assert(getDepth() == saved.getDepth() + 1);
+ Bits = saved.Bits;
+ }
+
+ } FunctionTypeDepth;
+
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
ASTContext &getASTContext() const { return Context.getASTContext(); }
public:
- CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_)
- : Context(C), Out(Out_), Structor(0), StructorType(0), SeqID(0) { }
+ CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ const NamedDecl *D = 0)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
+ SeqID(0) {
+ // These can't be mangled without a ctor type or dtor type.
+ assert(!D || (!isa<CXXDestructorDecl>(D) &&
+ !isa<CXXConstructorDecl>(D)));
+ }
CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
+ SeqID(0) { }
CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
- SeqID(0) { }
+ SeqID(0) { }
#if MANGLE_CHECKER
~CXXNameMangler() {
@@ -200,11 +247,16 @@ private:
void addSubstitution(TemplateName Template);
void addSubstitution(uintptr_t Ptr);
- void mangleUnresolvedScope(NestedNameSpecifier *Qualifier);
- void mangleUnresolvedName(NestedNameSpecifier *Qualifier,
- DeclarationName Name,
+ void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ bool recursive = false);
+ void mangleUnresolvedName(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
unsigned KnownArity = UnknownArity);
+ void mangleUnresolvedType(QualType type);
+
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -223,6 +275,7 @@ private:
void mangleNestedName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
+ void manglePrefix(NestedNameSpecifier *qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void mangleTemplatePrefix(const TemplateDecl *ND);
void mangleTemplatePrefix(TemplateName Template);
@@ -245,10 +298,11 @@ private:
void mangleNeonVectorType(const VectorType *T);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
- void mangleMemberExpr(const Expr *Base, bool IsArrow,
- NestedNameSpecifier *Qualifier,
- DeclarationName Name,
- unsigned KnownArity);
+ void mangleMemberExpr(const Expr *base, bool isArrow,
+ NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
+ unsigned knownArity);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
@@ -265,6 +319,8 @@ private:
void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
void mangleTemplateParameter(unsigned Index);
+
+ void mangleFunctionParam(const ParmVarDecl *parm);
};
}
@@ -334,10 +390,11 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
// another has a "\01foo". That is known to happen on ELF with the
// tricks normally used for producing aliases (PR9177). Fortunately the
// llvm mangler on ELF is a nop, so we can just avoid adding the \01
- // marker.
+ // marker. We also avoid adding the marker if this is an alias for an
+ // LLVM intrinsic.
llvm::StringRef UserLabelPrefix =
getASTContext().Target.getUserLabelPrefix();
- if (!UserLabelPrefix.empty())
+ if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
@@ -552,11 +609,24 @@ void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
addSubstitution(Template);
}
-void CXXNameMangler::mangleFloat(const llvm::APFloat &F) {
- // TODO: avoid this copy with careful stream management.
- llvm::SmallString<20> Buffer;
- F.bitcastToAPInt().toString(Buffer, 16, false);
- Out.write(Buffer.data(), Buffer.size());
+void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
+ // ABI:
+ // Floating-point literals are encoded using a fixed-length
+ // lowercase hexadecimal string corresponding to the internal
+ // representation (IEEE on Itanium), high-order bytes first,
+ // without leading zeroes. For example: "Lf bf800000 E" is -1.0f
+ // on Itanium.
+ // APInt::toString uses uppercase hexadecimal, and it's not really
+ // worth embellishing that interface for this use case, so we just
+ // do a second pass to lowercase things.
+ typedef llvm::SmallString<20> buffer_t;
+ buffer_t buffer;
+ f.bitcastToAPInt().toString(buffer, 16, false);
+
+ for (buffer_t::iterator i = buffer.begin(), e = buffer.end(); i != e; ++i)
+ if (isupper(*i)) *i = tolower(*i);
+
+ Out.write(buffer.data(), buffer.size());
}
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
@@ -597,59 +667,162 @@ void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
Out << '_';
}
-void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
- Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier);
- switch (Qualifier->getKind()) {
+void CXXNameMangler::mangleUnresolvedType(QualType type) {
+ if (const TemplateSpecializationType *TST =
+ type->getAs<TemplateSpecializationType>()) {
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // 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());
+ addSubstitution(QualType(TST, 0));
+ }
+ } else if (const DependentTemplateSpecializationType *DTST
+ = type->getAs<DependentTemplateSpecializationType>()) {
+ TemplateName Template
+ = getASTContext().getDependentTemplateName(DTST->getQualifier(),
+ DTST->getIdentifier());
+ mangleTemplatePrefix(Template);
+
+ // 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());
+ } else {
+ // We use the QualType mangle type variant here because it handles
+ // substitutions.
+ mangleType(type);
+ }
+}
+
+/// Mangle everything prior to the base-unresolved-name in an unresolved-name.
+///
+/// \param firstQualifierLookup - the entity found by unqualified lookup
+/// for the first name in the qualifier, if this is for a member expression
+/// \param recursive - true if this is being called recursively,
+/// i.e. if there is more prefix "to the right".
+void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ bool recursive) {
+
+ // x, ::x
+ // <unresolved-name> ::= [gs] <base-unresolved-name>
+
+ // T::x / decltype(p)::x
+ // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name>
+
+ // T::N::x /decltype(p)::N::x
+ // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E
+ // <base-unresolved-name>
+
+ // A::x, N::y, A<T>::z; "gs" means leading "::"
+ // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E
+ // <base-unresolved-name>
+
+ switch (qualifier->getKind()) {
case NestedNameSpecifier::Global:
- // nothing
- break;
+ Out << "gs";
+
+ // We want an 'sr' unless this is the entire NNS.
+ if (recursive)
+ Out << "sr";
+
+ // We never want an 'E' here.
+ return;
+
case NestedNameSpecifier::Namespace:
- mangleName(Qualifier->getAsNamespace());
+ if (qualifier->getPrefix())
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ else
+ Out << "sr";
+ mangleSourceName(qualifier->getAsNamespace()->getIdentifier());
break;
case NestedNameSpecifier::NamespaceAlias:
- mangleName(Qualifier->getAsNamespaceAlias()->getNamespace());
+ if (qualifier->getPrefix())
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ else
+ Out << "sr";
+ mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier());
break;
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- const Type *QTy = Qualifier->getAsType();
+ // Both cases want this.
+ Out << "sr";
- if (const TemplateSpecializationType *TST =
- dyn_cast<TemplateSpecializationType>(QTy)) {
- if (!mangleSubstitution(QualType(TST, 0))) {
- mangleTemplatePrefix(TST->getTemplateName());
-
- // 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());
- addSubstitution(QualType(TST, 0));
- }
- } else {
- // We use the QualType mangle type variant here because it handles
- // substitutions.
- mangleType(QualType(QTy, 0));
- }
+ // We only get here recursively if we're followed by identifiers.
+ if (recursive) Out << 'N';
+
+ mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+
+ // We never want to print 'E' directly after an unresolved-type,
+ // so we return directly.
+ return;
}
- break;
+
case NestedNameSpecifier::Identifier:
// Member expressions can have these without prefixes.
- if (Qualifier->getPrefix())
- mangleUnresolvedScope(Qualifier->getPrefix());
- mangleSourceName(Qualifier->getAsIdentifier());
+ if (qualifier->getPrefix()) {
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ } else if (firstQualifierLookup) {
+
+ // Try to make a proper qualifier out of the lookup result, and
+ // then just recurse on that.
+ NestedNameSpecifier *newQualifier;
+ if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) {
+ QualType type = getASTContext().getTypeDeclType(typeDecl);
+
+ // Pretend we had a different nested name specifier.
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ /*template*/ false,
+ type.getTypePtr());
+ } else if (NamespaceDecl *nspace =
+ dyn_cast<NamespaceDecl>(firstQualifierLookup)) {
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ nspace);
+ } else if (NamespaceAliasDecl *alias =
+ dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) {
+ newQualifier = NestedNameSpecifier::Create(getASTContext(),
+ /*prefix*/ 0,
+ alias);
+ } else {
+ // No sensible mangling to do here.
+ newQualifier = 0;
+ }
+
+ if (newQualifier)
+ return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive);
+
+ } else {
+ Out << "sr";
+ }
+
+ mangleSourceName(qualifier->getAsIdentifier());
break;
}
-}
-/// Mangles a name which was not resolved to a specific entity.
-void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *Qualifier,
- DeclarationName Name,
- unsigned KnownArity) {
- if (Qualifier)
- mangleUnresolvedScope(Qualifier);
- // FIXME: ambiguity of unqualified lookup with ::
+ // If this was the innermost part of the NNS, and we fell out to
+ // here, append an 'E'.
+ if (!recursive)
+ Out << 'E';
+}
- mangleUnqualifiedName(0, Name, KnownArity);
+/// Mangle an unresolved-name, which is generally used for names which
+/// weren't resolved to specific entities.
+void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName name,
+ unsigned knownArity) {
+ if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup);
+ mangleUnqualifiedName(0, name, knownArity);
}
static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
@@ -684,10 +857,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::Identifier: {
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
// We must avoid conflicts between internally- and externally-
- // linked variable declaration names in the same TU.
- // This naming convention is the same as that followed by GCC, though it
- // shouldn't actually matter.
- if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage &&
+ // linked variable and function declaration names in the same TU:
+ // void test() { extern void foo(); }
+ // static void foo();
+ // This naming convention is the same as that followed by GCC,
+ // though it shouldn't actually matter.
+ if (ND && ND->getLinkage() == InternalLinkage &&
ND->getDeclContext()->isFileContext())
Out << 'L';
@@ -734,7 +909,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
- if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
+ if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
assert(TD->getDeclContext() == D->getDeclContext() &&
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
@@ -906,6 +1081,38 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
mangleUnqualifiedName(ND);
}
+void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
+ switch (qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ // nothing
+ return;
+
+ case NestedNameSpecifier::Namespace:
+ mangleName(qualifier->getAsNamespace());
+ return;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ mangleName(qualifier->getAsNamespaceAlias()->getNamespace());
+ return;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+ return;
+
+ case NestedNameSpecifier::Identifier:
+ // Member expressions can have these without prefixes, but that
+ // should end up in mangleUnresolvedPrefix instead.
+ assert(qualifier->getPrefix());
+ manglePrefix(qualifier->getPrefix());
+
+ mangleSourceName(qualifier->getAsIdentifier());
+ return;
+ }
+
+ llvm_unreachable("unexpected nested name specifier");
+}
+
void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
// <prefix> ::= <prefix> <unqualified-name>
// ::= <template-prefix> <template-args>
@@ -959,7 +1166,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
return mangleTemplatePrefix(TD);
if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
- mangleUnresolvedScope(Qualified->getQualifier());
+ manglePrefix(Qualified->getQualifier());
if (OverloadedTemplateStorage *Overloaded
= Template.getAsOverloadedTemplate()) {
@@ -970,7 +1177,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
assert(Dependent && "Unknown template name kind?");
- mangleUnresolvedScope(Dependent->getQualifier());
+ manglePrefix(Dependent->getQualifier());
mangleUnscopedTemplateName(Template);
}
@@ -1033,7 +1240,7 @@ void CXXNameMangler::mangleType(TemplateName TN) {
// <class-enum-type> ::= <name>
// <name> ::= <nested-name>
- mangleUnresolvedScope(Dependent->getQualifier());
+ mangleUnresolvedPrefix(Dependent->getQualifier(), 0);
mangleSourceName(Dependent->getIdentifier());
break;
}
@@ -1313,8 +1520,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- assert(false &&
- "Overloaded and dependent types shouldn't get to name mangling");
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ llvm_unreachable("mangling a placeholder type");
break;
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
@@ -1339,13 +1547,22 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
// We should never be mangling something without a prototype.
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+ // Record that we're in a function type. See mangleFunctionParam
+ // for details on what we're trying to achieve here.
+ FunctionTypeDepthState saved = FunctionTypeDepth.push();
+
// <bare-function-type> ::= <signature type>+
- if (MangleReturnType)
+ if (MangleReturnType) {
+ FunctionTypeDepth.enterResultType();
mangleType(Proto->getResultType());
+ FunctionTypeDepth.leaveResultType();
+ }
if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
// <builtin-type> ::= v # void
Out << 'v';
+
+ FunctionTypeDepth.pop(saved);
return;
}
@@ -1354,6 +1571,8 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
Arg != ArgEnd; ++Arg)
mangleType(*Arg);
+ FunctionTypeDepth.pop(saved);
+
// <builtin-type> ::= z # ellipsis
if (Proto->isVariadic())
Out << 'z';
@@ -1590,13 +1809,13 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
void CXXNameMangler::mangleType(const DependentNameType *T) {
// Typename types are always nested
Out << 'N';
- mangleUnresolvedScope(T->getQualifier());
+ manglePrefix(T->getQualifier());
mangleSourceName(T->getIdentifier());
Out << 'E';
}
void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
- // Dependently-scoped template types are always nested
+ // Dependently-scoped template types are nested if they have a prefix.
Out << 'N';
// TODO: avoid making this TemplateName.
@@ -1676,23 +1895,54 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
/// Mangles a member expression. Implicit accesses are not handled,
/// but that should be okay, because you shouldn't be able to
/// make an implicit access in a function template declaration.
-void CXXNameMangler::mangleMemberExpr(const Expr *Base,
- bool IsArrow,
- NestedNameSpecifier *Qualifier,
- DeclarationName Member,
- unsigned Arity) {
- // gcc-4.4 uses 'dt' for dot expressions, which is reasonable.
- // OTOH, gcc also mangles the name as an expression.
- Out << (IsArrow ? "pt" : "dt");
- mangleExpression(Base);
- mangleUnresolvedName(Qualifier, Member, Arity);
+void CXXNameMangler::mangleMemberExpr(const Expr *base,
+ bool isArrow,
+ NestedNameSpecifier *qualifier,
+ NamedDecl *firstQualifierLookup,
+ DeclarationName member,
+ unsigned arity) {
+ // <expression> ::= dt <expression> <unresolved-name>
+ // ::= pt <expression> <unresolved-name>
+ Out << (isArrow ? "pt" : "dt");
+ mangleExpression(base);
+ mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity);
+}
+
+/// Look at the callee of the given call expression and determine if
+/// it's a parenthesized id-expression which would have triggered ADL
+/// otherwise.
+static bool isParenthesizedADLCallee(const CallExpr *call) {
+ const Expr *callee = call->getCallee();
+ const Expr *fn = callee->IgnoreParens();
+
+ // Must be parenthesized. IgnoreParens() skips __extension__ nodes,
+ // too, but for those to appear in the callee, it would have to be
+ // parenthesized.
+ if (callee == fn) return false;
+
+ // Must be an unresolved lookup.
+ const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn);
+ if (!lookup) return false;
+
+ assert(!lookup->requiresADL());
+
+ // Must be an unqualified lookup.
+ if (lookup->getQualifier()) return false;
+
+ // Must not have found a class member. Note that if one is a class
+ // member, they're all class members.
+ if (lookup->getNumDecls() > 0 &&
+ (*lookup->decls_begin())->isCXXClassMember())
+ return false;
+
+ // Otherwise, ADL would have been triggered.
+ return true;
}
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <trinary operator-name> <expression> <expression> <expression>
- // ::= cl <expression>* E # call
// ::= cv <type> expression # conversion with one argument
// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
// ::= st <type> # sizeof (a type)
@@ -1735,6 +1985,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::ChooseExprClass:
case Expr::CompoundLiteralExprClass:
case Expr::ExtVectorElementExprClass:
+ case Expr::GenericSelectionExprClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ObjCIvarRefExprClass:
@@ -1749,6 +2000,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::StmtExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::ArrayTypeTraitExprClass:
+ case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
case Expr::CXXUuidofExprClass:
case Expr::CXXNoexceptExprClass:
@@ -1784,7 +2037,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::CXXMemberCallExprClass: // fallthrough
case Expr::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
- Out << "cl";
+
+ // <expression> ::= cp <simple-id> <expression>* E
+ // We use this mangling only when the call would use ADL except
+ // for being parenthesized. Per discussion with David
+ // Vandervoorde, 2011.04.25.
+ if (isParenthesizedADLCallee(CE)) {
+ Out << "cp";
+ // The callee here is a parenthesized UnresolvedLookupExpr with
+ // no qualifier and should always get mangled as a <simple-id>
+ // anyway.
+
+ // <expression> ::= cl <expression>* E
+ } else {
+ Out << "cl";
+ }
+
mangleExpression(CE->getCallee(), CE->getNumArgs());
for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
mangleExpression(CE->getArg(I));
@@ -1815,7 +2083,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::MemberExprClass: {
const MemberExpr *ME = cast<MemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), ME->getMemberDecl()->getDeclName(),
+ ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(),
Arity);
break;
}
@@ -1823,7 +2091,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::UnresolvedMemberExprClass: {
const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), ME->getMemberName(),
+ ME->getQualifier(), 0, ME->getMemberName(),
Arity);
if (ME->hasExplicitTemplateArgs())
mangleTemplateArgs(ME->getExplicitTemplateArgs());
@@ -1834,19 +2102,16 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
const CXXDependentScopeMemberExpr *ME
= cast<CXXDependentScopeMemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), ME->getMember(),
- Arity);
+ ME->getQualifier(), ME->getFirstQualifierFoundInScope(),
+ ME->getMember(), Arity);
if (ME->hasExplicitTemplateArgs())
mangleTemplateArgs(ME->getExplicitTemplateArgs());
break;
}
case Expr::UnresolvedLookupExprClass: {
- // The ABI doesn't cover how to mangle overload sets, so we mangle
- // using something as close as possible to the original lookup
- // expression.
const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
- mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity);
+ mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity);
if (ULE->hasExplicitTemplateArgs())
mangleTemplateArgs(ULE->getExplicitTemplateArgs());
break;
@@ -1877,10 +2142,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
break;
}
- case Expr::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E);
- if (SAE->isSizeOf()) Out << 's';
- else Out << 'a';
+ case Expr::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
+ switch(SAE->getKind()) {
+ case UETT_SizeOf:
+ Out << 's';
+ break;
+ case UETT_AlignOf:
+ Out << 'a';
+ break;
+ case UETT_VecStep:
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot yet mangle vec_step expression");
+ Diags.Report(DiagID);
+ return;
+ }
if (SAE->isArgumentType()) {
Out << 't';
mangleType(SAE->getArgumentType());
@@ -1939,7 +2216,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::ArraySubscriptExprClass: {
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E);
- // Array subscript is treated as a syntactically wierd form of
+ // Array subscript is treated as a syntactically weird form of
// binary operator.
Out << "ix";
mangleExpression(AE->getLHS());
@@ -2009,6 +2286,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
Out << 'E';
break;
+ case Decl::ParmVar:
+ mangleFunctionParam(cast<ParmVarDecl>(D));
+ break;
+
case Decl::EnumConstant: {
const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
mangleIntegerLiteral(ED->getType(), ED->getInitVal());
@@ -2165,10 +2446,72 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
Diags.Report(DiagID);
return;
}
+ break;
}
}
}
+/// Mangle an expression which refers to a parameter variable.
+///
+/// <expression> ::= <function-param>
+/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0
+/// <function-param> ::= fp <top-level CV-qualifiers>
+/// <parameter-2 non-negative number> _ # L == 0, I > 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers> _ # L > 0, I == 0
+/// <function-param> ::= fL <L-1 non-negative number>
+/// p <top-level CV-qualifiers>
+/// <I-1 non-negative number> _ # L > 0, I > 0
+///
+/// L is the nesting depth of the parameter, defined as 1 if the
+/// parameter comes from the innermost function prototype scope
+/// enclosing the current context, 2 if from the next enclosing
+/// function prototype scope, and so on, with one special case: if
+/// we've processed the full parameter clause for the innermost
+/// function type, then L is one less. This definition conveniently
+/// makes it irrelevant whether a function's result type was written
+/// trailing or leading, but is otherwise overly complicated; the
+/// numbering was first designed without considering references to
+/// parameter in locations other than return types, and then the
+/// mangling had to be generalized without changing the existing
+/// manglings.
+///
+/// I is the zero-based index of the parameter within its parameter
+/// declaration clause. Note that the original ABI document describes
+/// this using 1-based ordinals.
+void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
+ unsigned parmDepth = parm->getFunctionScopeDepth();
+ unsigned parmIndex = parm->getFunctionScopeIndex();
+
+ // Compute 'L'.
+ // parmDepth does not include the declaring function prototype.
+ // FunctionTypeDepth does account for that.
+ assert(parmDepth < FunctionTypeDepth.getDepth());
+ unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth;
+ if (FunctionTypeDepth.isInResultType())
+ nestingDepth--;
+
+ if (nestingDepth == 0) {
+ Out << "fp";
+ } else {
+ Out << "fL" << (nestingDepth - 1) << 'p';
+ }
+
+ // Top-level qualifiers. We don't have to worry about arrays here,
+ // because parameters declared as arrays should already have been
+ // tranformed to have pointer type. FIXME: apparently these don't
+ // get mangled if used as an rvalue of a known non-class type?
+ assert(!parm->getType()->isArrayType()
+ && "parameter's type is still an array type?");
+ mangleQualifiers(parm->getType().getQualifiers());
+
+ // Parameter index.
+ if (parmIndex != 0) {
+ Out << (parmIndex - 1);
+ }
+ Out << '_';
+}
+
void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
@@ -2287,8 +2630,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
// an expression. We compensate for it here to produce the correct mangling.
NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
- bool compensateMangling = D->isCXXClassMember() &&
- !Parameter->getType()->isReferenceType();
+ bool compensateMangling = !Parameter->getType()->isReferenceType();
if (compensateMangling) {
Out << 'X';
mangleOperatorName(OO_Amp, 1);
@@ -2576,7 +2918,7 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D,
getASTContext().getSourceManager(),
"Mangling declaration");
- CXXNameMangler Mangler(*this, Out);
+ CXXNameMangler Mangler(*this, Out, D);
return Mangler.mangle(D);
}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 4de93bb4beab..206f6dd0c9eb 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ AST support targetting the Microsoft Visual C++
+// This provides C++ AST support targeting the Microsoft Visual C++
// ABI.
//
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 4bf7f23a0a9d..5424bebc81b0 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ name mangling targetting the Microsoft Visual C++ ABI.
+// This provides C++ name mangling targeting the Microsoft Visual C++ ABI.
//
//===----------------------------------------------------------------------===//
@@ -314,7 +314,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
- if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
+ if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
assert(TD->getDeclContext() == D->getDeclContext() &&
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
@@ -676,12 +676,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
// ::= M # float
// ::= N # double
// ::= O # long double (__float80 is mangled differently)
- // ::= _D # __int8 (yup, it's a distinct type in MSVC)
- // ::= _E # unsigned __int8
- // ::= _F # __int16
- // ::= _G # unsigned __int16
- // ::= _H # __int32
- // ::= _I # unsigned __int32
// ::= _J # long long, __int64
// ::= _K # unsigned long long, __int64
// ::= _L # __int128
@@ -706,7 +700,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Double: Out << 'N'; break;
// TODO: Determine size and mangle accordingly
case BuiltinType::LongDouble: Out << 'O'; break;
- // TODO: __int8 and friends
case BuiltinType::LongLong: Out << "_J"; break;
case BuiltinType::ULongLong: Out << "_K"; break;
case BuiltinType::Int128: Out << "_L"; break;
@@ -717,6 +710,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
+ case BuiltinType::BoundMember:
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
@@ -873,6 +868,8 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
if (CC == CC_Default)
CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C;
switch (CC) {
+ default:
+ assert(0 && "Unsupported CC for mangling");
case CC_Default:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 6f1ec058d74e..2878dff3edc4 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -371,3 +371,249 @@ TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
void *TypeData = LoadPointer(Data, Offset);
return TypeLoc(Qualifier->getAsType(), TypeData);
}
+
+namespace {
+ void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
+ unsigned &BufferCapacity) {
+ if (BufferSize + (End - Start) > BufferCapacity) {
+ // Reallocate the buffer.
+ unsigned NewCapacity
+ = std::max((unsigned)(BufferCapacity? BufferCapacity * 2
+ : sizeof(void*) * 2),
+ (unsigned)(BufferSize + (End - Start)));
+ char *NewBuffer = static_cast<char *>(malloc(NewCapacity));
+ memcpy(NewBuffer, Buffer, BufferSize);
+
+ if (BufferCapacity)
+ free(Buffer);
+ Buffer = NewBuffer;
+ BufferCapacity = NewCapacity;
+ }
+
+ memcpy(Buffer + BufferSize, Start, End - Start);
+ BufferSize += End-Start;
+ }
+
+ /// \brief Save a source location to the given buffer.
+ void SaveSourceLocation(SourceLocation Loc, char *&Buffer,
+ unsigned &BufferSize, unsigned &BufferCapacity) {
+ unsigned Raw = Loc.getRawEncoding();
+ Append(reinterpret_cast<char *>(&Raw),
+ reinterpret_cast<char *>(&Raw) + sizeof(unsigned),
+ Buffer, BufferSize, BufferCapacity);
+ }
+
+ /// \brief Save a pointer to the given buffer.
+ void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,
+ unsigned &BufferCapacity) {
+ Append(reinterpret_cast<char *>(&Ptr),
+ reinterpret_cast<char *>(&Ptr) + sizeof(void *),
+ Buffer, BufferSize, BufferCapacity);
+ }
+}
+
+NestedNameSpecifierLocBuilder::NestedNameSpecifierLocBuilder()
+ : Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { }
+
+NestedNameSpecifierLocBuilder::
+NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other)
+ : Representation(Other.Representation), Buffer(0),
+ BufferSize(0), BufferCapacity(0)
+{
+ if (!Other.Buffer)
+ return;
+
+ if (Other.BufferCapacity == 0) {
+ // Shallow copy is okay.
+ Buffer = Other.Buffer;
+ BufferSize = Other.BufferSize;
+ return;
+ }
+
+ // Deep copy
+ BufferSize = Other.BufferSize;
+ BufferCapacity = Other.BufferSize;
+ Buffer = static_cast<char *>(malloc(BufferCapacity));
+ memcpy(Buffer, Other.Buffer, BufferSize);
+}
+
+NestedNameSpecifierLocBuilder &
+NestedNameSpecifierLocBuilder::
+operator=(const NestedNameSpecifierLocBuilder &Other) {
+ Representation = Other.Representation;
+
+ if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {
+ // Re-use our storage.
+ BufferSize = Other.BufferSize;
+ memcpy(Buffer, Other.Buffer, BufferSize);
+ return *this;
+ }
+
+ // Free our storage, if we have any.
+ if (BufferCapacity) {
+ free(Buffer);
+ BufferCapacity = 0;
+ }
+
+ if (!Other.Buffer) {
+ // Empty.
+ Buffer = 0;
+ BufferSize = 0;
+ return *this;
+ }
+
+ if (Other.BufferCapacity == 0) {
+ // Shallow copy is okay.
+ Buffer = Other.Buffer;
+ BufferSize = Other.BufferSize;
+ return *this;
+ }
+
+ // Deep copy.
+ BufferSize = Other.BufferSize;
+ BufferCapacity = BufferSize;
+ Buffer = static_cast<char *>(malloc(BufferSize));
+ memcpy(Buffer, Other.Buffer, BufferSize);
+ return *this;
+}
+
+NestedNameSpecifierLocBuilder::~NestedNameSpecifierLocBuilder() {
+ if (BufferCapacity)
+ free(Buffer);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ SourceLocation TemplateKWLoc,
+ TypeLoc TL,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation,
+ TemplateKWLoc.isValid(),
+ TL.getTypePtr());
+
+ // Push source-location info into the buffer.
+ SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ IdentifierInfo *Identifier,
+ SourceLocation IdentifierLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation,
+ Identifier);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ NamespaceDecl *Namespace,
+ SourceLocation NamespaceLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation,
+ Namespace);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
+ NamespaceAliasDecl *Alias,
+ SourceLocation AliasLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier::Create(Context, Representation, Alias);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity);
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context,
+ SourceLocation ColonColonLoc) {
+ assert(!Representation && "Already have a nested-name-specifier!?");
+ Representation = NestedNameSpecifier::GlobalSpecifier(Context);
+
+ // Push source-location info into the buffer.
+ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+}
+
+void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
+ NestedNameSpecifier *Qualifier,
+ SourceRange R) {
+ Representation = Qualifier;
+
+ // Construct bogus (but well-formed) source information for the
+ // nested-name-specifier.
+ BufferSize = 0;
+ llvm::SmallVector<NestedNameSpecifier *, 4> Stack;
+ for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
+ Stack.push_back(NNS);
+ while (!Stack.empty()) {
+ NestedNameSpecifier *NNS = Stack.back();
+ Stack.pop_back();
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ TypeSourceInfo *TSInfo
+ = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
+ R.getBegin());
+ SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,
+ BufferCapacity);
+ break;
+ }
+
+ case NestedNameSpecifier::Global:
+ break;
+ }
+
+ // Save the location of the '::'.
+ SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(),
+ Buffer, BufferSize, BufferCapacity);
+ }
+}
+
+void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {
+ if (BufferCapacity)
+ free(Buffer);
+
+ if (!Other) {
+ Representation = 0;
+ BufferSize = 0;
+ return;
+ }
+
+ // Rather than copying the data (which is wasteful), "adopt" the
+ // pointer (which points into the ASTContext) but set the capacity to zero to
+ // indicate that we don't own it.
+ Representation = Other.getNestedNameSpecifier();
+ Buffer = static_cast<char *>(Other.getOpaqueData());
+ BufferSize = Other.getDataLength();
+ BufferCapacity = 0;
+}
+
+NestedNameSpecifierLoc
+NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const {
+ if (!Representation)
+ return NestedNameSpecifierLoc();
+
+ // If we adopted our data pointer from elsewhere in the AST context, there's
+ // no need to copy the memory.
+ if (BufferCapacity == 0)
+ return NestedNameSpecifierLoc(Representation, Buffer);
+
+ // FIXME: After copying the source-location information, should we free
+ // our (temporary) buffer and adopt the ASTContext-allocated memory?
+ // Doing so would optimize repeated calls to getWithLocInContext().
+ void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>());
+ memcpy(Mem, Buffer, BufferSize);
+ return NestedNameSpecifierLoc(Representation, Mem);
+}
+
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 4ed031f97499..0770e1f15143 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -19,7 +19,7 @@
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
-#include <map>
+#include "llvm/Support/CrashRecoveryContext.h"
using namespace clang;
@@ -564,6 +564,8 @@ protected:
unsigned IsUnion : 1;
unsigned IsMac68kAlign : 1;
+
+ unsigned IsMsStruct : 1;
/// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
/// this contains the number of bits in the last byte that can be used for
@@ -580,6 +582,8 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
+ CharUnits ZeroLengthBitfieldAlignment;
+
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
const CXXRecordDecl *PrimaryBase;
@@ -612,10 +616,12 @@ protected:
*EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
Alignment(CharUnits::One()), UnpackedAlignment(Alignment),
- Packed(false), IsUnion(false), IsMac68kAlign(false),
+ Packed(false), IsUnion(false),
+ IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
- NonVirtualAlignment(CharUnits::One()), PrimaryBase(0),
+ NonVirtualAlignment(CharUnits::One()),
+ ZeroLengthBitfieldAlignment(CharUnits::Zero()), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
@@ -657,7 +663,7 @@ protected:
void SelectPrimaryVBase(const CXXRecordDecl *RD);
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
@@ -757,9 +763,9 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
}
}
-uint64_t
+CharUnits
RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
- return Context.Target.getPointerWidth(0);
+ return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
}
/// DeterminePrimaryBase - Determine the primary base of the given class.
@@ -815,8 +821,8 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
// Update the size.
- setSize(getSizeInBits() + GetVirtualPointersSize(RD));
- setDataSize(getSizeInBits());
+ setSize(getSize() + GetVirtualPointersSize(RD));
+ setDataSize(getSize());
CharUnits UnpackedBaseAlign =
Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0));
@@ -1108,8 +1114,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
- uint64_t RecordSizeInBits = Context.toBits(Layout.getSize());
- setSize(std::max(getSizeInBits(), RecordSizeInBits));
+ setSize(std::max(getSize(), Layout.getSize()));
return CharUnits::Zero();
}
@@ -1124,27 +1129,24 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
// Round up the current record size to the base's alignment boundary.
- uint64_t Offset =
- llvm::RoundUpToAlignment(getDataSizeInBits(), Context.toBits(BaseAlign));
+ CharUnits Offset = getDataSize().RoundUpToAlignment(BaseAlign);
// Try to place the base.
- while (!EmptySubobjects->CanPlaceBaseAtOffset(Base,
- Context.toCharUnitsFromBits(Offset)))
- Offset += Context.toBits(BaseAlign);
+ while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
+ Offset += BaseAlign;
if (!Base->Class->isEmpty()) {
// Update the data size.
- setDataSize(Offset + Context.toBits(Layout.getNonVirtualSize()));
+ setDataSize(Offset + Layout.getNonVirtualSize());
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ setSize(std::max(getSize(), getDataSize()));
} else
- setSize(std::max(getSizeInBits(),
- Offset + Context.toBits(Layout.getSize())));
+ setSize(std::max(getSize(), Offset + Layout.getSize()));
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign, UnpackedBaseAlign);
- return Context.toCharUnitsFromBits(Offset);
+ return Offset;
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
@@ -1152,6 +1154,8 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
IsUnion = RD->isUnion();
Packed = D->hasAttr<PackedAttr>();
+
+ IsMsStruct = D->hasAttr<MsStructAttr>();
// mac68k alignment supersedes maximum field alignment and attribute aligned,
// and forces all structures to have 2-byte alignment. The IBM docs on it
@@ -1187,8 +1191,9 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
LayoutFields(RD);
- // FIXME: Size isn't always an exact multiple of the char width. Round up?
- NonVirtualSize = Context.toCharUnitsFromBits(getSizeInBits());
+ NonVirtualSize = Context.toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.Target.getCharAlign()));
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1233,7 +1238,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// We start laying out ivars not at the end of the superclass
// structure, but at the next byte following the last field.
setSize(SL.getDataSize());
- setDataSize(getSizeInBits());
+ setDataSize(getSize());
}
InitializeLayout(D);
@@ -1252,9 +1257,28 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
+ const FieldDecl *LastFD = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
+ if (IsMsStruct) {
+ const FieldDecl *FD = (*Field);
+ if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ // FIXME. Multiple zero bitfields may follow a bitfield.
+ // set ZeroLengthBitfieldAlignment to max. of its
+ // currrent and alignment of 'FD'.
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(FD->getType());
+ ZeroLengthBitfieldAlignment = FieldInfo.second;
+ continue;
+ }
+ // Zero-length bitfields following non-bitfield members are
+ // ignored:
+ if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
+ continue;
+ LastFD = FD;
+ }
LayoutField(*Field);
+ }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1285,7 +1309,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
}
assert(!Type.isNull() && "Did not find a type!");
- unsigned TypeAlign = Context.getTypeAlign(Type);
+ CharUnits TypeAlign = Context.getTypeAlignInChars(Type);
// We're not going to use any of the unfilled bits in the last byte.
UnfilledBitsInLastByte = 0;
@@ -1299,11 +1323,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
} else {
// The bitfield is allocated starting at the next offset aligned appropriately
// for T', with length n bits.
- FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), TypeAlign);
+ FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(),
+ Context.toBits(TypeAlign));
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1311,13 +1337,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
FieldOffsets.push_back(FieldOffset);
CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset,
- TypeAlign, FieldPacked, D);
+ Context.toBits(TypeAlign), FieldPacked, D);
// Update the size.
setSize(std::max(getSizeInBits(), getDataSizeInBits()));
// Remember max struct/class alignment.
- UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign));
+ UpdateAlignment(TypeAlign);
}
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
@@ -1380,7 +1406,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8));
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
}
@@ -1428,6 +1455,9 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+ if (ZeroLengthBitfieldAlignment > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ ZeroLengthBitfieldAlignment = CharUnits::Zero();
if (Context.getLangOptions().MSBitfields) {
// If MS bitfield layout is required, figure out what type is being
@@ -1487,7 +1517,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (IsUnion)
setSize(std::max(getSizeInBits(), FieldSizeInBits));
else
- setSize(Context.toBits(FieldOffset) + FieldSizeInBits);
+ setSize(FieldOffset + FieldSize);
// Update the data size.
setDataSize(getSizeInBits());
@@ -1504,17 +1534,18 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// which is not empty but of size 0; such as having fields of
// array of zero-length, remains of Size 0
if (RD->isEmpty())
- setSize(8);
+ setSize(CharUnits::One());
}
else
- setSize(8);
+ 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 UnpackedSize =
+ uint64_t UnpackedSizeInBits =
llvm::RoundUpToAlignment(getSizeInBits(),
Context.toBits(UnpackedAlignment));
+ CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)));
unsigned CharBitNum = Context.Target.getCharWidth();
@@ -1536,7 +1567,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// Warn if we packed it unnecessarily. If the alignment is 1 byte don't
// bother since there won't be alignment issues.
if (Packed && UnpackedAlignment > CharUnits::One() &&
- getSizeInBits() == UnpackedSize)
+ getSize() == UnpackedSize)
Diag(D->getLocation(), diag::warn_unnecessary_packed)
<< Context.getTypeDeclType(RD);
}
@@ -1664,17 +1695,19 @@ namespace {
EmptySubobjectMap *EmptySubobjects) :
RecordLayoutBuilder(Ctx, EmptySubobjects) {}
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
};
}
-uint64_t
+CharUnits
MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
// We should reserve space for two pointers if the class has both
// virtual functions and virtual bases.
+ CharUnits PointerWidth =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
if (RD->isPolymorphic() && RD->getNumVBases() > 0)
- return 2 * Context.Target.getPointerWidth(0);
- return Context.Target.getPointerWidth(0);
+ return 2 * PointerWidth;
+ return PointerWidth;
}
/// getASTRecordLayout - Get or compute information about the layout of the
@@ -1705,6 +1738,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
case CXXABI_Microsoft:
Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects));
}
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
+ RecordBuilderCleanup(Builder.get());
+
Builder->Layout(RD);
// FIXME: This is not always correct. See the part about bitfields at
@@ -1713,17 +1750,15 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
// FIXME: This should be done in FinalizeLayout.
- uint64_t DataSize =
- IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize;
- CharUnits NonVirtualSize =
- IsPODForThePurposeOfLayout ?
- toCharUnitsFromBits(DataSize) : Builder->NonVirtualSize;
+ CharUnits DataSize =
+ IsPODForThePurposeOfLayout ? Builder->getSize() : Builder->getDataSize();
+ CharUnits NonVirtualSize =
+ IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize;
- CharUnits RecordSize = toCharUnitsFromBits(Builder->Size);
NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder->getSize(),
Builder->Alignment,
- toCharUnitsFromBits(DataSize),
+ DataSize,
Builder->FieldOffsets.data(),
Builder->FieldOffsets.size(),
NonVirtualSize,
@@ -1736,12 +1771,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
- CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
-
NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
- toCharUnitsFromBits(Builder.Size),
+ Builder.getSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
}
@@ -1797,12 +1830,10 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
- CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
-
const ASTRecordLayout *NewEntry =
- new (*this) ASTRecordLayout(*this, RecordSize,
+ new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
- toCharUnitsFromBits(Builder.DataSize),
+ Builder.getDataSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 8a80275aa165..380ad94ca224 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -540,6 +540,40 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
std::copy(handlers, handlers + NumHandlers, Stmts + 1);
}
+CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
+ Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
+ Stmt *Body, SourceLocation FL,
+ SourceLocation CL, SourceLocation RPL)
+ : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) {
+ SubExprs[RANGE] = Range;
+ SubExprs[BEGINEND] = BeginEndStmt;
+ SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
+ SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
+ SubExprs[LOOPVAR] = LoopVar;
+ SubExprs[BODY] = Body;
+}
+
+Expr *CXXForRangeStmt::getRangeInit() {
+ DeclStmt *RangeStmt = getRangeStmt();
+ VarDecl *RangeDecl = dyn_cast_or_null<VarDecl>(RangeStmt->getSingleDecl());
+ assert(RangeDecl &&& "for-range should have a single var decl");
+ return RangeDecl->getInit();
+}
+
+const Expr *CXXForRangeStmt::getRangeInit() const {
+ return const_cast<CXXForRangeStmt*>(this)->getRangeInit();
+}
+
+VarDecl *CXXForRangeStmt::getLoopVariable() {
+ Decl *LV = cast<DeclStmt>(getLoopVarStmt())->getSingleDecl();
+ assert(LV && "No loop variable in CXXForRangeStmt");
+ return cast<VarDecl>(LV);
+}
+
+const VarDecl *CXXForRangeStmt::getLoopVariable() const {
+ return const_cast<CXXForRangeStmt*>(this)->getLoopVariable();
+}
+
IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL, Stmt *elsev)
: Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
@@ -628,14 +662,14 @@ void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
}
Stmt *SwitchCase::getSubStmt() {
- if (isa<CaseStmt>(this)) return cast<CaseStmt>(this)->getSubStmt();
+ if (isa<CaseStmt>(this))
+ return cast<CaseStmt>(this)->getSubStmt();
return cast<DefaultStmt>(this)->getSubStmt();
}
WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL)
-: Stmt(WhileStmtClass)
-{
+ : Stmt(WhileStmtClass) {
setConditionVariable(C, Var);
SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
SubExprs[BODY] = body;
@@ -676,3 +710,61 @@ const Expr* ReturnStmt::getRetValue() const {
Expr* ReturnStmt::getRetValue() {
return cast_or_null<Expr>(RetExpr);
}
+
+SEHTryStmt::SEHTryStmt(bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler)
+ : Stmt(SEHTryStmtClass),
+ IsCXXTry(IsCXXTry),
+ TryLoc(TryLoc)
+{
+ Children[TRY] = TryBlock;
+ Children[HANDLER] = Handler;
+}
+
+SEHTryStmt* SEHTryStmt::Create(ASTContext &C,
+ bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler) {
+ return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
+}
+
+SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
+ return dyn_cast<SEHExceptStmt>(getHandler());
+}
+
+SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const {
+ return dyn_cast<SEHFinallyStmt>(getHandler());
+}
+
+SEHExceptStmt::SEHExceptStmt(SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block)
+ : Stmt(SEHExceptStmtClass),
+ Loc(Loc)
+{
+ Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr);
+ Children[BLOCK] = Block;
+}
+
+SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C,
+ SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block) {
+ return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
+}
+
+SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc,
+ Stmt *Block)
+ : Stmt(SEHFinallyStmtClass),
+ Loc(Loc),
+ Block(Block)
+{}
+
+SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C,
+ SourceLocation Loc,
+ Stmt *Block) {
+ return new(C)SEHFinallyStmt(Loc,Block);
+}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 5c7dbb3ed990..fb024f33ab30 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -141,7 +141,7 @@ namespace {
void VisitFloatingLiteral(FloatingLiteral *Node);
void VisitStringLiteral(StringLiteral *Str);
void VisitUnaryOperator(UnaryOperator *Node);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
void VisitMemberExpr(MemberExpr *Node);
void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
void VisitBinaryOperator(BinaryOperator *Node);
@@ -236,6 +236,9 @@ void StmtDumper::DumpDeclarator(Decl *D) {
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
OS << "\"typedef " << localType->getUnderlyingType().getAsString()
<< ' ' << localType << '"';
+ } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
+ OS << "\"using " << localType << " = "
+ << localType->getUnderlyingType().getAsString() << '"';
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
OS << "\"";
// Emit storage class for vardecls.
@@ -284,6 +287,12 @@ void StmtDumper::DumpDeclarator(Decl *D) {
OS << ";\"";
} else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
OS << "label " << LD->getNameAsString();
+ } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
+ OS << "\"static_assert(\n";
+ DumpSubTree(SAD->getAssertExpr());
+ OS << ",\n";
+ DumpSubTree(SAD->getMessage());
+ OS << ");\"";
} else {
assert(0 && "Unexpected decl");
}
@@ -360,6 +369,11 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
OS << " ";
DumpDeclRef(Node->getDecl());
+ if (Node->getDecl() != Node->getFoundDecl()) {
+ OS << " (";
+ DumpDeclRef(Node->getFoundDecl());
+ OS << ")";
+ }
}
void StmtDumper::DumpDeclRef(Decl *d) {
@@ -441,9 +455,19 @@ void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
<< " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
-void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
DumpExpr(Node);
- OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " ";
+ switch(Node->getKind()) {
+ case UETT_SizeOf:
+ OS << " sizeof ";
+ break;
+ case UETT_AlignOf:
+ OS << " __alignof ";
+ break;
+ case UETT_VecStep:
+ OS << " vec_step ";
+ break;
+ }
if (Node->isArgumentType())
DumpType(Node->getArgumentType());
}
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 9a7265a043f2..9bf4aeaae83e 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -98,7 +98,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
if (VD->getInit())
return true;
}
- else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) {
+ else if (TypedefNameDecl* TD = dyn_cast<TypedefNameDecl>(D)) {
if (const VariableArrayType* VAPtr =
FindVA(TD->getUnderlyingType().getTypePtr())) {
setVAPtr(VAPtr);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 1cdd22088141..0d13502e8d58 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -66,6 +66,8 @@ namespace {
void PrintRawIfStmt(IfStmt *If);
void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
void PrintCallArgs(CallExpr *E);
+ void PrintRawSEHExceptHandler(SEHExceptStmt *S);
+ void PrintRawSEHFinallyStmt(SEHFinallyStmt *S);
void PrintExpr(Expr *E) {
if (E)
@@ -291,6 +293,18 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) {
}
}
+void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
+ Indent() << "for (";
+ PrintingPolicy SubPolicy(Policy);
+ SubPolicy.SuppressInitializers = true;
+ Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel);
+ OS << " : ";
+ PrintExpr(Node->getRangeInit());
+ OS << ") {\n";
+ PrintStmt(Node->getBody());
+ Indent() << "}\n";
+}
+
void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
Indent() << "goto " << Node->getLabel()->getName() << ";\n";
}
@@ -461,6 +475,46 @@ void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) {
OS << "\n";
}
+void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) {
+ Indent() << (Node->getIsCXXTry() ? "try " : "__try ");
+ PrintRawCompoundStmt(Node->getTryBlock());
+ SEHExceptStmt *E = Node->getExceptHandler();
+ SEHFinallyStmt *F = Node->getFinallyHandler();
+ if(E)
+ PrintRawSEHExceptHandler(E);
+ else {
+ assert(F && "Must have a finally block...");
+ PrintRawSEHFinallyStmt(F);
+ }
+ OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) {
+ OS << "__finally ";
+ PrintRawCompoundStmt(Node->getBlock());
+ OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) {
+ OS << "__except (";
+ VisitExpr(Node->getFilterExpr());
+ OS << ")\n";
+ PrintRawCompoundStmt(Node->getBlock());
+ OS << "\n";
+}
+
+void StmtPrinter::VisitSEHExceptStmt(SEHExceptStmt *Node) {
+ Indent();
+ PrintRawSEHExceptHandler(Node);
+ OS << "\n";
+}
+
+void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
+ Indent();
+ PrintRawSEHFinallyStmt(Node);
+ OS << "\n";
+}
+
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
@@ -706,8 +760,18 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
OS << ")";
}
-void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
- OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
+void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
+ switch(Node->getKind()) {
+ case UETT_SizeOf:
+ OS << "sizeof";
+ break;
+ case UETT_AlignOf:
+ OS << "__alignof";
+ break;
+ case UETT_VecStep:
+ OS << "vec_step";
+ break;
+ }
if (Node->isArgumentType())
OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
else {
@@ -715,6 +779,23 @@ void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
PrintExpr(Node->getArgumentExpr());
}
}
+
+void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
+ OS << "_Generic(";
+ PrintExpr(Node->getControllingExpr());
+ for (unsigned i = 0; i != Node->getNumAssocs(); ++i) {
+ OS << ", ";
+ QualType T = Node->getAssocType(i);
+ if (T.isNull())
+ OS << "default";
+ else
+ OS << T.getAsString(Policy);
+ OS << ": ";
+ PrintExpr(Node->getAssocExpr(i));
+ }
+ OS << ")";
+}
+
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
PrintExpr(Node->getLHS());
OS << "[";
@@ -1212,33 +1293,75 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
- default: llvm_unreachable("Unknown unary type trait");
case UTT_HasNothrowAssign: return "__has_nothrow_assign";
- case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
+ case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasTrivialAssign: return "__has_trivial_assign";
- case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
+ case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
case UTT_HasVirtualDestructor: return "__has_virtual_destructor";
case UTT_IsAbstract: return "__is_abstract";
+ case UTT_IsArithmetic: return "__is_arithmetic";
+ case UTT_IsArray: return "__is_array";
case UTT_IsClass: return "__is_class";
+ case UTT_IsCompleteType: return "__is_complete_type";
+ case UTT_IsCompound: return "__is_compound";
+ case UTT_IsConst: return "__is_const";
case UTT_IsEmpty: return "__is_empty";
case UTT_IsEnum: return "__is_enum";
+ case UTT_IsFloatingPoint: return "__is_floating_point";
+ case UTT_IsFunction: return "__is_function";
+ case UTT_IsFundamental: return "__is_fundamental";
+ case UTT_IsIntegral: return "__is_integral";
+ case UTT_IsLiteral: return "__is_literal";
+ case UTT_IsLvalueReference: return "__is_lvalue_reference";
+ case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer";
+ case UTT_IsMemberObjectPointer: return "__is_member_object_pointer";
+ case UTT_IsMemberPointer: return "__is_member_pointer";
+ case UTT_IsObject: return "__is_object";
case UTT_IsPOD: return "__is_pod";
+ case UTT_IsPointer: return "__is_pointer";
case UTT_IsPolymorphic: return "__is_polymorphic";
+ case UTT_IsReference: return "__is_reference";
+ case UTT_IsRvalueReference: return "__is_rvalue_reference";
+ case UTT_IsScalar: return "__is_scalar";
+ case UTT_IsSigned: return "__is_signed";
+ case UTT_IsStandardLayout: return "__is_standard_layout";
+ case UTT_IsTrivial: return "__is_trivial";
case UTT_IsUnion: return "__is_union";
+ case UTT_IsUnsigned: return "__is_unsigned";
+ case UTT_IsVoid: return "__is_void";
+ case UTT_IsVolatile: return "__is_volatile";
}
- return "";
+ llvm_unreachable("Type trait not covered by switch statement");
}
static const char *getTypeTraitName(BinaryTypeTrait BTT) {
switch (BTT) {
case BTT_IsBaseOf: return "__is_base_of";
+ case BTT_IsConvertible: return "__is_convertible";
+ case BTT_IsSame: return "__is_same";
case BTT_TypeCompatible: return "__builtin_types_compatible_p";
case BTT_IsConvertibleTo: return "__is_convertible_to";
}
- return "";
+ llvm_unreachable("Binary type trait not covered by switch");
+}
+
+static const char *getTypeTraitName(ArrayTypeTrait ATT) {
+ switch (ATT) {
+ case ATT_ArrayRank: return "__array_rank";
+ case ATT_ArrayExtent: return "__array_extent";
+ }
+ llvm_unreachable("Array type trait not covered by switch");
+}
+
+static const char *getExpressionTraitName(ExpressionTrait ET) {
+ switch (ET) {
+ case ET_IsLValueExpr: return "__is_lvalue_expr";
+ case ET_IsRValueExpr: return "__is_rvalue_expr";
+ }
+ llvm_unreachable("Expression type trait not covered by switch");
}
void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
@@ -1252,6 +1375,17 @@ void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
<< E->getRhsType().getAsString(Policy) << ")";
}
+void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ OS << getTypeTraitName(E->getTrait()) << "("
+ << E->getQueriedType().getAsString(Policy) << ")";
+}
+
+void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ OS << getExpressionTraitName(E->getTrait()) << "(";
+ PrintExpr(E->getQueriedExpression());
+ OS << ")";
+}
+
void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
OS << "noexcept(";
PrintExpr(E->getOperand());
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b54001167b42..44818e8c0847 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -177,6 +177,22 @@ void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) {
VisitStmt(S);
}
+void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHTryStmt(SEHTryStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+ VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHExceptStmt(SEHExceptStmt *S) {
+ VisitStmt(S);
+}
+
void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
VisitStmt(S);
}
@@ -290,9 +306,9 @@ void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
+void StmtProfiler::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *S) {
VisitExpr(S);
- ID.AddBoolean(S->isSizeOf());
+ ID.AddInteger(S->getKind());
if (S->isArgumentType())
VisitType(S->getArgumentType());
}
@@ -430,6 +446,18 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
ID.AddBoolean(S->isConstQualAdded());
}
+void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) {
+ VisitExpr(S);
+ for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
+ QualType T = S->getAssocType(i);
+ if (T.isNull())
+ ID.AddPointer(0);
+ else
+ VisitType(T);
+ VisitExpr(S->getAssocExpr(i));
+ }
+}
+
static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
@@ -786,6 +814,18 @@ void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) {
VisitType(S->getRhsType());
}
+void StmtProfiler::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getTrait());
+ VisitType(S->getQueriedType());
+}
+
+void StmtProfiler::VisitExpressionTraitExpr(ExpressionTraitExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getTrait());
+ VisitExpr(S->getQueriedExpression());
+}
+
void
StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
VisitExpr(S);
@@ -921,12 +961,16 @@ void StmtProfiler::VisitDecl(Decl *D) {
}
if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
- // The Itanium C++ ABI uses the type of a parameter when mangling
- // expressions that involve function parameters, so we will use the
- // parameter's type for establishing function parameter identity. That
- // way, our definition of "equivalent" (per C++ [temp.over.link])
- // matches the definition of "equivalent" used for name mangling.
+ // The Itanium C++ ABI uses the type, scope depth, and scope
+ // index of a parameter when mangling expressions that involve
+ // function parameters, so we will use the parameter's type for
+ // establishing function parameter identity. That way, our
+ // definition of "equivalent" (per C++ [temp.over.link]) is at
+ // least as strong as the definition of "equivalent" used for
+ // name mangling.
VisitType(Parm->getType());
+ ID.AddInteger(Parm->getFunctionScopeDepth());
+ ID.AddInteger(Parm->getFunctionScopeIndex());
return;
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 1764f4ab1f03..6114a5a051be 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -338,7 +338,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
//===----------------------------------------------------------------------===//
TemplateArgumentLocInfo::TemplateArgumentLocInfo() {
- memset(this, 0, sizeof(TemplateArgumentLocInfo));
+ memset((void*)this, 0, sizeof(TemplateArgumentLocInfo));
}
SourceRange TemplateArgumentLoc::getSourceRange() const {
@@ -356,14 +356,14 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return SourceRange();
case TemplateArgument::Template:
- if (getTemplateQualifierRange().isValid())
- return SourceRange(getTemplateQualifierRange().getBegin(),
+ if (getTemplateQualifierLoc())
+ return SourceRange(getTemplateQualifierLoc().getBeginLoc(),
getTemplateNameLoc());
return SourceRange(getTemplateNameLoc());
case TemplateArgument::TemplateExpansion:
- if (getTemplateQualifierRange().isValid())
- return SourceRange(getTemplateQualifierRange().getBegin(),
+ if (getTemplateQualifierLoc())
+ return SourceRange(getTemplateQualifierLoc().getBeginLoc(),
getTemplateEllipsisLoc());
return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc());
@@ -425,7 +425,7 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
Ellipsis = getTemplateEllipsisLoc();
NumExpansions = Argument.getNumTemplateExpansions();
return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
- getTemplateQualifierRange(),
+ getTemplateQualifierLoc(),
getTemplateNameLoc());
case TemplateArgument::Declaration:
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 6b378a001101..ebd07f486783 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -118,6 +118,10 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
= getAsSubstTemplateTemplateParmPack())
OS << SubstPack->getParameterPack()->getNameAsString();
+ else {
+ OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
+ (*OTS->begin())->printName(OS);
+ }
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index b03314e11d13..9eb497bea629 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -21,11 +21,24 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang;
+bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
+ return (*this != Other) &&
+ // CVR qualifiers superset
+ (((Mask & CVRMask) | (Other.Mask & CVRMask)) == (Mask & CVRMask)) &&
+ // ObjC GC qualifiers superset
+ ((getObjCGCAttr() == Other.getObjCGCAttr()) ||
+ (hasObjCGCAttr() && !Other.hasObjCGCAttr())) &&
+ // Address space superset.
+ ((getAddressSpace() == Other.getAddressSpace()) ||
+ (hasAddressSpace()&& !Other.hasAddressSpace()));
+}
+
bool QualType::isConstant(QualType T, ASTContext &Ctx) {
if (T.isConstQualified())
return true;
@@ -407,6 +420,16 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const {
return 0;
}
+const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const {
+ // There is no sugar for ObjCQualifiedClassType's, just return the canonical
+ // type pointer if it is the right class.
+ if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
+ if (OPT->isObjCQualifiedClassType())
+ return OPT;
+ }
+ return 0;
+}
+
const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) {
if (OPT->getInterfaceType())
@@ -858,37 +881,178 @@ bool Type::isPODType() const {
}
bool Type::isLiteralType() const {
- if (isIncompleteType())
+ if (isDependentType())
return false;
// C++0x [basic.types]p10:
// A type is a literal type if it is:
- switch (CanonicalType->getTypeClass()) {
- // We're whitelisting
- default: return false;
+ // [...]
+ // -- an array of literal type
+ // Extension: variable arrays cannot be literal types, since they're
+ // runtime-sized.
+ if (isVariableArrayType())
+ return false;
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types; those are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // C++0x [basic.types]p10:
+ // A type is a literal type if it is:
+ // -- a scalar type; or
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ // -- a reference type; or
+ if (BaseTy->isReferenceType()) return true;
+ // -- a class type that has all of the following properties:
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // -- a trivial destructor,
+ if (!ClassDecl->hasTrivialDestructor()) return false;
+ // -- every constructor call and full-expression in the
+ // brace-or-equal-initializers for non-static data members (if any)
+ // is a constant expression,
+ // FIXME: C++0x: Clang doesn't yet support non-static data member
+ // declarations with initializers, or constexprs.
+ // -- it is an aggregate type or has at least one constexpr
+ // constructor or constructor template that is not a copy or move
+ // constructor, and
+ if (!ClassDecl->isAggregate() &&
+ !ClassDecl->hasConstExprNonCopyMoveConstructor())
+ return false;
+ // -- all non-static data members and base classes of literal types
+ if (ClassDecl->hasNonLiteralTypeFieldsOrBases()) return false;
+ }
- // -- a scalar type
- case Builtin:
- case Complex:
- case Pointer:
- case MemberPointer:
- case Vector:
- case ExtVector:
- case ObjCObjectPointer:
- case Enum:
return true;
+ }
+ return false;
+}
- // -- a class type with ...
- case Record:
- // FIXME: Do the tests
+bool Type::isTrivialType() const {
+ if (isDependentType())
return false;
- // -- an array of literal type
- // Extension: variable arrays cannot be literal types, since they're
- // runtime-sized.
- case ConstantArray:
- return cast<ArrayType>(CanonicalType)->getElementType()->isLiteralType();
+ // C++0x [basic.types]p9:
+ // Scalar types, trivial class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called trivial
+ // types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // C++0x [class]p5:
+ // A trivial class is a class that has a trivial default constructor
+ if (!ClassDecl->hasTrivialConstructor()) return false;
+ // and is trivially copyable.
+ if (!ClassDecl->isTriviallyCopyable()) return false;
+ }
+
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+bool Type::isStandardLayoutType() const {
+ if (isDependentType())
+ return false;
+
+ // C++0x [basic.types]p9:
+ // Scalar types, standard-layout class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called
+ // standard-layout types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ if (!ClassDecl->isStandardLayout())
+ return false;
+
+ // Default to 'true' for non-C++ class types.
+ // FIXME: This is a bit dubious, but plain C structs should trivially meet
+ // all the requirements of standard layout classes.
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+// This is effectively the intersection of isTrivialType and
+// isStandardLayoutType. We implement it dircetly to avoid redundant
+// conversions from a type to a CXXRecordDecl.
+bool Type::isCXX11PODType() const {
+ if (isDependentType())
+ return false;
+
+ // C++11 [basic.types]p9:
+ // Scalar types, POD classes, arrays of such types, and cv-qualified
+ // versions of these types are collectively called trivial types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // C++11 [class]p10:
+ // A POD struct is a non-union class that is both a trivial class [...]
+ // C++11 [class]p5:
+ // A trivial class is a class that has a trivial default constructor
+ if (!ClassDecl->hasTrivialConstructor()) return false;
+ // and is trivially copyable.
+ if (!ClassDecl->isTriviallyCopyable()) return false;
+
+ // C++11 [class]p10:
+ // A POD struct is a non-union class that is both a trivial class and
+ // a standard-layout class [...]
+ if (!ClassDecl->isStandardLayout()) return false;
+
+ // C++11 [class]p10:
+ // A POD struct is a non-union class that is both a trivial class and
+ // a standard-layout class, and has no non-static data members of type
+ // non-POD struct, non-POD union (or array of such types). [...]
+ //
+ // We don't directly query the recursive aspect as the requiremets for
+ // both standard-layout classes and trivial classes apply recursively
+ // already.
+ }
+
+ return true;
}
+
+ // No other types can match.
+ return false;
}
bool Type::isPromotableIntegerType() const {
@@ -1040,9 +1204,9 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
QualType Canon)
: TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true,
/*VariablyModified=*/false,
- NNS->containsUnexpandedParameterPack()),
+ NNS && NNS->containsUnexpandedParameterPack()),
NNS(NNS), Name(Name), NumArgs(NumArgs) {
- assert(NNS && NNS->isDependent() &&
+ assert((!NNS || NNS->isDependent()) &&
"DependentTemplateSpecializatonType requires dependent qualifier");
for (unsigned I = 0; I != NumArgs; ++I) {
if (Args[I].containsUnexpandedParameterPack())
@@ -1120,7 +1284,9 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
+ case BoundMember: return "<bound member function type>";
case Dependent: return "<dependent type>";
+ case UnknownAny: return "<unknown type>";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
@@ -1157,6 +1323,8 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86FastCall: return "fastcall";
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
+ case CC_AAPCS: return "aapcs";
+ case CC_AAPCS_VFP: return "aapcs-vfp";
}
llvm_unreachable("Invalid calling convention.");
@@ -1173,8 +1341,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
NumArgs(numArgs), NumExceptions(epi.NumExceptions),
- HasExceptionSpec(epi.HasExceptionSpec),
- HasAnyExceptionSpec(epi.HasAnyExceptionSpec)
+ ExceptionSpecType(epi.ExceptionSpecType)
{
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
@@ -1187,20 +1354,50 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
argSlot[i] = args[i];
}
-
- // Fill in the exception array.
- QualType *exnSlot = argSlot + numArgs;
- for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
- if (epi.Exceptions[i]->isDependentType())
- setDependent();
- if (epi.Exceptions[i]->containsUnexpandedParameterPack())
- setContainsUnexpandedParameterPack();
+ if (getExceptionSpecType() == EST_Dynamic) {
+ // Fill in the exception array.
+ QualType *exnSlot = argSlot + numArgs;
+ for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
+ if (epi.Exceptions[i]->isDependentType())
+ setDependent();
- exnSlot[i] = epi.Exceptions[i];
+ if (epi.Exceptions[i]->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
+ exnSlot[i] = epi.Exceptions[i];
+ }
+ } else if (getExceptionSpecType() == EST_ComputedNoexcept) {
+ // Store the noexcept expression and context.
+ Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
+ *noexSlot = epi.NoexceptExpr;
}
}
+FunctionProtoType::NoexceptResult
+FunctionProtoType::getNoexceptSpec(ASTContext &ctx) const {
+ ExceptionSpecificationType est = getExceptionSpecType();
+ if (est == EST_BasicNoexcept)
+ return NR_Nothrow;
+
+ if (est != EST_ComputedNoexcept)
+ return NR_NoNoexcept;
+
+ Expr *noexceptExpr = getNoexceptExpr();
+ if (!noexceptExpr)
+ return NR_BadNoexcept;
+ if (noexceptExpr->isValueDependent())
+ return NR_Dependent;
+
+ llvm::APSInt value;
+ bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, 0,
+ /*evaluated*/false);
+ (void)isICE;
+ assert(isICE && "AST should not contain bad noexcept expressions.");
+
+ return value.getBoolValue() ? NR_Nothrow : NR_Throw;
+}
+
bool FunctionProtoType::isTemplateVariadic() const {
for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx)
if (isa<PackExpansionType>(getArgType(ArgIdx - 1)))
@@ -1211,23 +1408,28 @@ bool FunctionProtoType::isTemplateVariadic() const {
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
const QualType *ArgTys, unsigned NumArgs,
- const ExtProtoInfo &epi) {
+ const ExtProtoInfo &epi,
+ const ASTContext &Context) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
ID.AddBoolean(epi.Variadic);
ID.AddInteger(epi.TypeQuals);
ID.AddInteger(epi.RefQualifier);
- if (epi.HasExceptionSpec) {
- ID.AddBoolean(epi.HasAnyExceptionSpec);
+ ID.AddInteger(epi.ExceptionSpecType);
+ if (epi.ExceptionSpecType == EST_Dynamic) {
for (unsigned i = 0; i != epi.NumExceptions; ++i)
ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
+ } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
+ epi.NoexceptExpr->Profile(ID, Context, true);
}
epi.ExtInfo.Profile(ID);
}
-void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo());
+void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Ctx) {
+ Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo(),
+ Ctx);
}
QualType TypedefType::desugar() const {
@@ -1302,6 +1504,10 @@ bool EnumType::classof(const TagType *TT) {
return isa<EnumDecl>(TT->getDecl());
}
+IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
+ return isCanonicalUnqualified() ? 0 : getDecl()->getIdentifier();
+}
+
SubstTemplateTypeParmPackType::
SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
QualType Canon,
@@ -1357,10 +1563,11 @@ TemplateSpecializationType(TemplateName T,
unsigned NumArgs, QualType Canon)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
- T.isDependent(), false,
- T.containsUnexpandedParameterPack()),
+ T.isDependent(), false, T.containsUnexpandedParameterPack()),
Template(T), NumArgs(NumArgs)
{
+ assert(!T.getAsDependentTemplateName() &&
+ "Use DependentTemplateSpecializationType for dependent template-name");
assert((!Canon.isNull() ||
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
"No canonical type for non-dependent class template specialization");
@@ -1529,7 +1736,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
- (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl());
+ (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl());
return CachedProperties(LV.linkage(), LV.visibility(), IsLocalOrUnnamed);
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 14db7f83c2d0..34e7693e3075 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -102,6 +102,8 @@ SourceLocation TypeLoc::getBeginLoc() const {
// FIXME: Currently QualifiedTypeLoc does not have a source range
// case Qualified:
case Elaborated:
+ case DependentName:
+ case DependentTemplateSpecialization:
break;
default:
TypeLoc Next = Cur.getNextTypeLoc();
@@ -116,18 +118,37 @@ SourceLocation TypeLoc::getBeginLoc() const {
SourceLocation TypeLoc::getEndLoc() const {
TypeLoc Cur = *this;
+ TypeLoc Last;
while (true) {
switch (Cur.getTypeLocClass()) {
default:
+ if (!Last)
+ Last = Cur;
+ return Last.getLocalSourceRange().getEnd();
+ case Paren:
+ case ConstantArray:
+ case DependentSizedArray:
+ case IncompleteArray:
+ case VariableArray:
+ case FunctionProto:
+ case FunctionNoProto:
+ Last = Cur;
+ break;
+ case Pointer:
+ case BlockPointer:
+ case MemberPointer:
+ case LValueReference:
+ case RValueReference:
+ case PackExpansion:
+ if (!Last)
+ Last = Cur;
break;
case Qualified:
case Elaborated:
- Cur = Cur.getNextTypeLoc();
- continue;
+ break;
}
- break;
+ Cur = Cur.getNextTypeLoc();
}
- return Cur.getLocalSourceRange().getEnd();
}
@@ -213,6 +234,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::NullPtr:
case BuiltinType::Overload:
case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
@@ -229,6 +252,43 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
return TL;
}
+void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+}
+
+void DependentNameTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+ setNameLoc(Loc);
+}
+
+void
+DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ setKeywordLoc(Loc);
+ if (getTypePtr()->getQualifier()) {
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+ } else {
+ setQualifierLoc(NestedNameSpecifierLoc());
+ }
+
+ setNameLoc(Loc);
+ setLAngleLoc(Loc);
+ setRAngleLoc(Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
+ getTypePtr()->getArgs(),
+ getArgInfos(), Loc);
+}
+
void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
unsigned NumArgs,
const TemplateArgument *Args,
@@ -252,13 +312,22 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
break;
case TemplateArgument::Template:
- ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc,
- SourceLocation());
- break;
+ case TemplateArgument::TemplateExpansion: {
+ NestedNameSpecifierLocBuilder Builder;
+ TemplateName Template = Args[i].getAsTemplate();
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
+ Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
+ else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
- case TemplateArgument::TemplateExpansion:
- ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, Loc);
+ ArgInfos[i] = TemplateArgumentLocInfo(
+ Builder.getWithLocInContext(Context),
+ Loc,
+ Args[i].getKind() == TemplateArgument::Template
+ ? SourceLocation()
+ : Loc);
break;
+ }
}
}
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 139073987a0e..0c5df7fae671 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -400,6 +400,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
case CC_X86Pascal:
S += " __attribute__((pascal))";
break;
+ case CC_AAPCS:
+ S += " __attribute__((pcs(\"aapcs\")))";
+ break;
+ case CC_AAPCS_VFP:
+ S += " __attribute__((pcs(\"aapcs-vfp\")))";
+ break;
}
if (Info.getNoReturn())
S += " __attribute__((noreturn))";
@@ -421,12 +427,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
S += " &&";
break;
}
-
- if (T->hasExceptionSpec()) {
+
+ if (T->hasDynamicExceptionSpec()) {
S += " throw(";
- if (T->hasAnyExceptionSpec())
+ if (T->getExceptionSpecType() == EST_MSAny)
S += "...";
- else
+ else
for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) {
if (I)
S += ", ";
@@ -436,6 +442,16 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
S += ExceptionType;
}
S += ")";
+ } else if (isNoexceptExceptionSpec(T->getExceptionSpecType())) {
+ S += " noexcept";
+ if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
+ S += "(";
+ llvm::raw_string_ostream EOut(S);
+ T->getNoexceptExpr()->printPretty(EOut, 0, Policy);
+ EOut.flush();
+ S += EOut.str();
+ S += ")";
+ }
}
print(T->getResultType(), S);
@@ -530,7 +546,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
Buffer += Spec->getIdentifier()->getName();
Buffer += TemplateArgsStr;
} else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
- if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
+ if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())
Buffer += Typedef->getIdentifier()->getName();
else if (Tag->getIdentifier())
Buffer += Tag->getIdentifier()->getName();
@@ -547,9 +563,13 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
std::string Buffer;
bool HasKindDecoration = false;
+ // bool SuppressTagKeyword
+ // = Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword;
+
// We don't print tags unless this is an elaborated type.
// In C, we just assume every RecordType is an elaborated type.
- if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) {
+ if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword ||
+ D->getTypedefNameForAnonDecl())) {
HasKindDecoration = true;
Buffer += D->getKindName();
Buffer += ' ';
@@ -563,7 +583,7 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
if (const IdentifierInfo *II = D->getIdentifier())
Buffer += II->getNameStart();
- else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) {
+ else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) {
assert(Typedef->getIdentifier() && "Typedef without identifier?");
Buffer += Typedef->getIdentifier()->getNameStart();
} else {
@@ -632,12 +652,12 @@ void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T,
std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'.
S = ' ' + S;
-
- if (!T->getName())
+
+ if (IdentifierInfo *Id = T->getIdentifier())
+ S = Id->getName().str() + S;
+ else
S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' +
llvm::utostr_32(T->getIndex()) + S;
- else
- S = T->getName()->getName().str() + S;
}
void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
@@ -691,6 +711,7 @@ void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) {
std::string TypeStr;
PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKeyword = true;
InnerPolicy.SuppressScope = true;
TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr);
@@ -737,7 +758,8 @@ void TypePrinter::printDependentTemplateSpecialization(
if (T->getKeyword() != ETK_None)
OS << " ";
- T->getQualifier()->print(OS, Policy);
+ if (T->getQualifier())
+ T->getQualifier()->print(OS, Policy);
OS << T->getIdentifier()->getName();
OS << TemplateSpecializationType::PrintTemplateArgumentList(
T->getArgs(),
@@ -759,10 +781,14 @@ void TypePrinter::printPackExpansion(const PackExpansionType *T,
void TypePrinter::printAttributed(const AttributedType *T,
std::string &S) {
+ // Prefer the macro forms of the GC qualifiers.
+ if (T->getAttrKind() == AttributedType::attr_objc_gc)
+ return print(T->getEquivalentType(), S);
+
print(T->getModifiedType(), S);
// TODO: not all attributes are GCC-style attributes.
- S += "__attribute__((";
+ S += " __attribute__((";
switch (T->getAttrKind()) {
case AttributedType::attr_address_space:
S += "address_space(";
@@ -831,6 +857,16 @@ void TypePrinter::printAttributed(const AttributedType *T,
case AttributedType::attr_stdcall: S += "stdcall"; break;
case AttributedType::attr_thiscall: S += "thiscall"; break;
case AttributedType::attr_pascal: S += "pascal"; break;
+ case AttributedType::attr_pcs: {
+ S += "pcs(";
+ QualType t = T->getEquivalentType();
+ while (!t->isFunctionType())
+ t = t->getPointeeType();
+ S += (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ?
+ "\"aapcs\"" : "\"aapcs-vfp\"");
+ S += ")";
+ break;
+ }
}
S += "))";
}
@@ -1031,20 +1067,18 @@ std::string Qualifiers::getAsString() const {
void Qualifiers::getAsStringInternal(std::string &S,
const PrintingPolicy&) const {
AppendTypeQualList(S, getCVRQualifiers());
- if (unsigned AddressSpace = getAddressSpace()) {
+ if (unsigned addrspace = getAddressSpace()) {
if (!S.empty()) S += ' ';
S += "__attribute__((address_space(";
- S += llvm::utostr_32(AddressSpace);
+ S += llvm::utostr_32(addrspace);
S += ")))";
}
- if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
+ if (Qualifiers::GC gc = getObjCGCAttr()) {
if (!S.empty()) S += ' ';
- S += "__attribute__((objc_gc(";
- if (GCAttrType == Qualifiers::Weak)
- S += "weak";
+ if (gc == Qualifiers::Weak)
+ S += "__weak";
else
- S += "strong";
- S += ")))";
+ S += "__strong";
}
}
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 62097ef20dd9..ddc5e887031b 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -29,6 +29,24 @@
using namespace clang;
+AnalysisContext::AnalysisContext(const Decl *d,
+ idx::TranslationUnit *tu,
+ bool useUnoptimizedCFG,
+ bool addehedges,
+ bool addImplicitDtors,
+ bool addInitializers)
+ : D(d), TU(tu),
+ forcedBlkExprs(0),
+ builtCFG(false), builtCompleteCFG(false),
+ useUnoptimizedCFG(useUnoptimizedCFG),
+ ReferencedBlockVars(0)
+{
+ cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
+ cfgBuildOptions.AddEHEdges = addehedges;
+ cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
+ cfgBuildOptions.AddInitializers = addInitializers;
+}
+
void AnalysisContextManager::clear() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
@@ -56,57 +74,71 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
return NULL;
}
+void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) {
+ if (!forcedBlkExprs)
+ forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs();
+ // Default construct an entry for 'stmt'.
+ if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
+ stmt = pe->IgnoreParens();
+ (void) (*forcedBlkExprs)[stmt];
+}
+
+const CFGBlock *
+AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) {
+ assert(forcedBlkExprs);
+ if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
+ stmt = pe->IgnoreParens();
+ CFG::BuildOptions::ForcedBlkExprs::const_iterator itr =
+ forcedBlkExprs->find(stmt);
+ assert(itr != forcedBlkExprs->end());
+ return itr->second;
+}
+
CFG *AnalysisContext::getCFG() {
- if (UseUnoptimizedCFG)
+ if (useUnoptimizedCFG)
return getUnoptimizedCFG();
if (!builtCFG) {
- CFG::BuildOptions B;
- B.AddEHEdges = AddEHEdges;
- B.AddImplicitDtors = AddImplicitDtors;
- B.AddInitializers = AddInitializers;
- cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), B);
+ cfg.reset(CFG::buildCFG(D, getBody(),
+ &D->getASTContext(), cfgBuildOptions));
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCFG = true;
}
- return cfg;
+ return cfg.get();
}
CFG *AnalysisContext::getUnoptimizedCFG() {
if (!builtCompleteCFG) {
- CFG::BuildOptions B;
+ CFG::BuildOptions B = cfgBuildOptions;
B.PruneTriviallyFalseEdges = false;
- B.AddEHEdges = AddEHEdges;
- B.AddImplicitDtors = AddImplicitDtors;
- B.AddInitializers = AddInitializers;
- completeCFG = CFG::buildCFG(D, getBody(), &D->getASTContext(), B);
+ completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), B));
// Even when the cfg is not successfully built, we don't
// want to try building it again.
builtCompleteCFG = true;
}
- return completeCFG;
+ return completeCFG.get();
}
CFGStmtMap *AnalysisContext::getCFGStmtMap() {
if (cfgStmtMap)
- return cfgStmtMap;
+ return cfgStmtMap.get();
if (CFG *c = getCFG()) {
- cfgStmtMap = CFGStmtMap::Build(c, &getParentMap());
- return cfgStmtMap;
+ cfgStmtMap.reset(CFGStmtMap::Build(c, &getParentMap()));
+ return cfgStmtMap.get();
}
return 0;
}
-CFGReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() {
+CFGReverseBlockReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() {
if (CFA)
- return CFA;
+ return CFA.get();
if (CFG *c = getCFG()) {
- CFA = new CFGReachabilityAnalysis(*c);
- return CFA;
+ CFA.reset(new CFGReverseBlockReachabilityAnalysis(*c));
+ return CFA.get();
}
return 0;
@@ -118,42 +150,37 @@ void AnalysisContext::dumpCFG() {
ParentMap &AnalysisContext::getParentMap() {
if (!PM)
- PM = new ParentMap(getBody());
+ PM.reset(new ParentMap(getBody()));
return *PM;
}
PseudoConstantAnalysis *AnalysisContext::getPseudoConstantAnalysis() {
if (!PCA)
- PCA = new PseudoConstantAnalysis(getBody());
- return PCA;
+ PCA.reset(new PseudoConstantAnalysis(getBody()));
+ return PCA.get();
}
LiveVariables *AnalysisContext::getLiveVariables() {
if (!liveness) {
- CFG *c = getCFG();
- if (!c)
- return 0;
-
- liveness = new LiveVariables(*this);
- liveness->runOnCFG(*c);
- liveness->runOnAllBlocks(*c, 0, true);
+ if (CFG *c = getCFG()) {
+ liveness.reset(new LiveVariables(*this));
+ liveness->runOnCFG(*c);
+ liveness->runOnAllBlocks(*c, 0, true);
+ }
}
- return liveness;
+ return liveness.get();
}
LiveVariables *AnalysisContext::getRelaxedLiveVariables() {
- if (!relaxedLiveness) {
- CFG *c = getCFG();
- if (!c)
- return 0;
-
- relaxedLiveness = new LiveVariables(*this, false);
- relaxedLiveness->runOnCFG(*c);
- relaxedLiveness->runOnAllBlocks(*c, 0, true);
- }
+ if (!relaxedLiveness)
+ if (CFG *c = getCFG()) {
+ relaxedLiveness.reset(new LiveVariables(*this, false));
+ relaxedLiveness->runOnCFG(*c);
+ relaxedLiveness->runOnAllBlocks(*c, 0, true);
+ }
- return relaxedLiveness;
+ return relaxedLiveness.get();
}
AnalysisContext *AnalysisContextManager::getContext(const Decl *D,
@@ -370,14 +397,7 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
//===----------------------------------------------------------------------===//
AnalysisContext::~AnalysisContext() {
- delete cfg;
- delete completeCFG;
- delete cfgStmtMap;
- delete liveness;
- delete relaxedLiveness;
- delete PM;
- delete PCA;
- delete CFA;
+ delete forcedBlkExprs;
delete ReferencedBlockVars;
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index cc6e9c592a1e..de16334ce137 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -36,6 +36,8 @@ static SourceLocation GetEndLoc(Decl* D) {
return D->getLocation();
}
+class CFGBuilder;
+
/// The CFG builder uses a recursive algorithm to build the CFG. When
/// we process an expression, sometimes we know that we must add the
/// subexpressions as block-level expressions. For example:
@@ -55,13 +57,13 @@ public:
AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {}
- bool alwaysAdd() const { return kind & AlwaysAdd; }
+ bool alwaysAdd(CFGBuilder &builder,
+ const Stmt *stmt) const;
/// Return a copy of this object, except with the 'always-add' bit
/// set as specified.
AddStmtChoice withAlwaysAdd(bool alwaysAdd) const {
- return AddStmtChoice(alwaysAdd ? Kind(kind | AlwaysAdd) :
- Kind(kind & ~AlwaysAdd));
+ return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
}
private:
@@ -210,6 +212,25 @@ struct BlockScopePosPair {
LocalScope::const_iterator scopePosition;
};
+/// TryResult - a class representing a variant over the values
+/// 'true', 'false', or 'unknown'. This is returned by tryEvaluateBool,
+/// and is used by the CFGBuilder to decide if a branch condition
+/// can be decided up front during CFG construction.
+class TryResult {
+ int X;
+public:
+ TryResult(bool b) : X(b ? 1 : 0) {}
+ TryResult() : X(-1) {}
+
+ bool isTrue() const { return X == 1; }
+ bool isFalse() const { return X == 0; }
+ bool isKnown() const { return X >= 0; }
+ void negate() {
+ assert(isKnown());
+ X ^= 0x1;
+ }
+};
+
/// CFGBuilder - This class implements CFG construction from an AST.
/// The builder is stateful: an instance of the builder should be used to only
/// construct a single CFG.
@@ -238,7 +259,7 @@ class CFGBuilder {
CFGBlock* SwitchTerminatedBlock;
CFGBlock* DefaultCaseBlock;
CFGBlock* TryTerminatedBlock;
-
+
// Current position in local scope.
LocalScope::const_iterator ScopePos;
@@ -256,18 +277,30 @@ class CFGBuilder {
LabelSetTy AddressTakenLabels;
bool badCFG;
- CFG::BuildOptions BuildOpts;
+ const CFG::BuildOptions &BuildOpts;
+
+ // State to track for building switch statements.
+ bool switchExclusivelyCovered;
+ Expr::EvalResult *switchCond;
+
+ CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry;
+ const Stmt *lastLookup;
public:
- explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG
- Block(NULL), Succ(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
- TryTerminatedBlock(NULL), badCFG(false) {}
+ explicit CFGBuilder(ASTContext *astContext,
+ const CFG::BuildOptions &buildOpts)
+ : Context(astContext), cfg(new CFG()), // crew a new CFG
+ Block(NULL), Succ(NULL),
+ SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
+ TryTerminatedBlock(NULL), badCFG(false), BuildOpts(buildOpts),
+ switchExclusivelyCovered(false), switchCond(0),
+ cachedEntry(0), lastLookup(0) {}
// buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
- CFG::BuildOptions BO);
+ CFG* buildCFG(const Decl *D, Stmt *Statement);
+ bool alwaysAdd(const Stmt *stmt);
+
private:
// Visitors to walk an AST and construct the CFG.
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
@@ -279,6 +312,7 @@ private:
AddStmtChoice asc);
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
+ CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
AddStmtChoice asc);
CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
@@ -311,7 +345,8 @@ private:
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
CFGBlock *VisitReturnStmt(ReturnStmt* R);
- CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc);
+ CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
+ AddStmtChoice asc);
CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
CFGBlock *VisitSwitchStmt(SwitchStmt *S);
CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc);
@@ -359,9 +394,11 @@ private:
void addLocalScopeAndDtors(Stmt* S);
// Interface to CFGBlock - adding CFGElements.
- void appendStmt(CFGBlock *B, Stmt *S,
- AddStmtChoice asc = AddStmtChoice::AlwaysAdd) {
- B->appendStmt(S, cfg->getBumpVectorContext());
+ void appendStmt(CFGBlock *B, const Stmt *S) {
+ if (alwaysAdd(S))
+ cachedEntry->second = B;
+
+ B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext());
}
void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
B->appendInitializer(I, cfg->getBumpVectorContext());
@@ -387,47 +424,74 @@ private:
B->addSuccessor(S, cfg->getBumpVectorContext());
}
- /// TryResult - a class representing a variant over the values
- /// 'true', 'false', or 'unknown'. This is returned by tryEvaluateBool,
- /// and is used by the CFGBuilder to decide if a branch condition
- /// can be decided up front during CFG construction.
- class TryResult {
- int X;
- public:
- TryResult(bool b) : X(b ? 1 : 0) {}
- TryResult() : X(-1) {}
-
- bool isTrue() const { return X == 1; }
- bool isFalse() const { return X == 0; }
- bool isKnown() const { return X >= 0; }
- void negate() {
- assert(isKnown());
- X ^= 0x1;
- }
- };
+ /// Try and evaluate an expression to an integer constant.
+ bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
+ if (!BuildOpts.PruneTriviallyFalseEdges)
+ return false;
+ return !S->isTypeDependent() &&
+ !S->isValueDependent() &&
+ S->Evaluate(outResult, *Context);
+ }
/// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1
/// if we can evaluate to a known value, otherwise return -1.
TryResult tryEvaluateBool(Expr *S) {
- if (!BuildOpts.PruneTriviallyFalseEdges)
- return TryResult();
-
Expr::EvalResult Result;
- if (!S->isTypeDependent() && !S->isValueDependent() &&
- S->Evaluate(Result, *Context)) {
- if (Result.Val.isInt())
- return Result.Val.getInt().getBoolValue();
- if (Result.Val.isLValue()) {
- Expr *e = Result.Val.getLValueBase();
- const CharUnits &c = Result.Val.getLValueOffset();
- if (!e && c.isZero())
- return false;
- }
+ if (!tryEvaluate(S, Result))
+ return TryResult();
+
+ if (Result.Val.isInt())
+ return Result.Val.getInt().getBoolValue();
+
+ if (Result.Val.isLValue()) {
+ Expr *e = Result.Val.getLValueBase();
+ const CharUnits &c = Result.Val.getLValueOffset();
+ if (!e && c.isZero())
+ return false;
}
return TryResult();
}
+
};
+inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
+ const Stmt *stmt) const {
+ return builder.alwaysAdd(stmt) || kind == AlwaysAdd;
+}
+
+bool CFGBuilder::alwaysAdd(const Stmt *stmt) {
+ if (!BuildOpts.forcedBlkExprs)
+ return false;
+
+ if (lastLookup == stmt) {
+ if (cachedEntry) {
+ assert(cachedEntry->first == stmt);
+ return true;
+ }
+ return false;
+ }
+
+ lastLookup = stmt;
+
+ // Perform the lookup!
+ CFG::BuildOptions::ForcedBlkExprs *fb = *BuildOpts.forcedBlkExprs;
+
+ if (!fb) {
+ // No need to update 'cachedEntry', since it will always be null.
+ assert(cachedEntry == 0);
+ return false;
+ }
+
+ CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt);
+ if (itr == fb->end()) {
+ cachedEntry = 0;
+ return false;
+ }
+
+ cachedEntry = &*itr;
+ return true;
+}
+
// FIXME: Add support for dependent-sized array types in C++?
// Does it even make sense to build a CFG for an uninstantiated template?
static const VariableArrayType *FindVA(const Type *t) {
@@ -447,16 +511,11 @@ static const VariableArrayType *FindVA(const Type *t) {
/// body (compound statement). The ownership of the returned CFG is
/// transferred to the caller. If CFG construction fails, this method returns
/// NULL.
-CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
- CFG::BuildOptions BO) {
-
- Context = C;
+CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) {
assert(cfg.get());
if (!Statement)
return NULL;
- BuildOpts = BO;
-
// Create an empty block that will serve as the exit block for the CFG. Since
// this is the first block added to the CFG, it will be implicitly registered
// as the exit block.
@@ -853,6 +912,9 @@ tryAgain:
case Stmt::CXXTryStmtClass:
return VisitCXXTryStmt(cast<CXXTryStmt>(S));
+ case Stmt::CXXForRangeStmtClass:
+ return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
+
case Stmt::DeclStmtClass:
return VisitDeclStmt(cast<DeclStmt>(S));
@@ -908,8 +970,9 @@ tryAgain:
case Stmt::ReturnStmtClass:
return VisitReturnStmt(cast<ReturnStmt>(S));
- case Stmt::SizeOfAlignOfExprClass:
- return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), asc);
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
+ asc);
case Stmt::StmtExprClass:
return VisitStmtExpr(cast<StmtExpr>(S), asc);
@@ -926,9 +989,9 @@ tryAgain:
}
CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, S)) {
autoCreateBlock();
- appendStmt(Block, S, asc);
+ appendStmt(Block, S);
}
return VisitChildren(S);
@@ -949,9 +1012,9 @@ CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
AddStmtChoice asc) {
AddressTakenLabels.insert(A->getLabel());
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, A)) {
autoCreateBlock();
- appendStmt(Block, A, asc);
+ appendStmt(Block, A);
}
return Block;
@@ -959,9 +1022,9 @@ CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, U)) {
autoCreateBlock();
- appendStmt(Block, U, asc);
+ appendStmt(Block, U);
}
return Visit(U->getSubExpr(), AddStmtChoice());
@@ -971,7 +1034,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
AddStmtChoice asc) {
if (B->isLogicalOp()) { // && or ||
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- appendStmt(ConfluenceBlock, B, asc);
+ appendStmt(ConfluenceBlock, B);
if (badCFG)
return 0;
@@ -1016,23 +1079,23 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
if (B->getOpcode() == BO_Comma) { // ,
autoCreateBlock();
- appendStmt(Block, B, asc);
+ appendStmt(Block, B);
addStmt(B->getRHS());
return addStmt(B->getLHS());
}
if (B->isAssignmentOp()) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, B)) {
autoCreateBlock();
- appendStmt(Block, B, asc);
+ appendStmt(Block, B);
}
Visit(B->getLHS());
return Visit(B->getRHS());
}
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, B)) {
autoCreateBlock();
- appendStmt(Block, B, asc);
+ appendStmt(Block, B);
}
CFGBlock *RBlock = Visit(B->getRHS());
@@ -1044,9 +1107,9 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
}
CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
}
return Block;
}
@@ -1073,7 +1136,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
return Block;
}
-static bool CanThrow(Expr *E) {
+static bool CanThrow(Expr *E, ASTContext &Ctx) {
QualType Ty = E->getType();
if (Ty->isFunctionPointerType())
Ty = Ty->getAs<PointerType>()->getPointeeType();
@@ -1083,7 +1146,7 @@ static bool CanThrow(Expr *E) {
const FunctionType *FT = Ty->getAs<FunctionType>();
if (FT) {
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
- if (Proto->hasEmptyExceptionSpec())
+ if (Proto->isNothrow(Ctx))
return false;
}
return true;
@@ -1099,7 +1162,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
bool AddEHEdge = false;
// Languages without exceptions are assumed to not throw.
- if (Context->getLangOptions().areExceptionsEnabled()) {
+ if (Context->getLangOptions().Exceptions) {
if (BuildOpts.AddEHEdges)
AddEHEdge = true;
}
@@ -1111,7 +1174,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
AddEHEdge = false;
}
- if (!CanThrow(C->getCallee()))
+ if (!CanThrow(C->getCallee(), *Context))
AddEHEdge = false;
if (!NoReturn && !AddEHEdge)
@@ -1124,7 +1187,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
}
Block = createBlock(!NoReturn);
- appendStmt(Block, C, asc);
+ appendStmt(Block, C);
if (NoReturn) {
// Wire this to the exit block directly.
@@ -1144,7 +1207,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
AddStmtChoice asc) {
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- appendStmt(ConfluenceBlock, C, asc);
+ appendStmt(ConfluenceBlock, C);
if (badCFG)
return 0;
@@ -1197,7 +1260,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// Create the confluence block that will "merge" the results of the ternary
// expression.
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- appendStmt(ConfluenceBlock, C, asc);
+ appendStmt(ConfluenceBlock, C);
if (badCFG)
return 0;
@@ -1353,7 +1416,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
addAutomaticObjDtors(ScopePos, BeginScopePos, I);
}
- // The block we were proccessing is now finished. Make it the successor
+ // The block we were processing is now finished. Make it the successor
// block.
if (Block) {
Succ = Block;
@@ -1436,7 +1499,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
if (VarDecl *VD = I->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, I, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, I->getConditionVariableDeclStmt());
addStmt(Init);
}
}
@@ -1574,7 +1637,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
if (VarDecl *VD = F->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, F, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, F->getConditionVariableDeclStmt());
EntryConditionBlock = addStmt(Init);
assert(Block == EntryConditionBlock);
}
@@ -1672,9 +1735,9 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
}
CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, M)) {
autoCreateBlock();
- appendStmt(Block, M, asc);
+ appendStmt(Block, M);
}
return Visit(M->getBase());
}
@@ -1736,7 +1799,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
Block = ExitConditionBlock;
// Walk the 'element' expression to see if there are any side-effects. We
- // generate new blocks as necesary. We DON'T add the statement by default to
+ // generate new blocks as necessary. We DON'T add the statement by default to
// the CFG unless it contains control-flow.
EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd);
if (Block) {
@@ -1799,7 +1862,7 @@ CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
// Add the @synchronized to the CFG.
autoCreateBlock();
- appendStmt(Block, S, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, S);
// Inline the sync expression.
return addStmt(S->getSynchExpr());
@@ -1858,7 +1921,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
if (VarDecl *VD = W->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, W, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, W->getConditionVariableDeclStmt());
EntryConditionBlock = addStmt(Init);
assert(Block == EntryConditionBlock);
}
@@ -2105,28 +2168,30 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
return Block;
}
-CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E,
- AddStmtChoice asc) {
+CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
+ AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
appendStmt(Block, E);
}
// VLA types have expressions that must be evaluated.
+ CFGBlock *lastBlock = Block;
+
if (E->isArgumentType()) {
for (const VariableArrayType *VA =FindVA(E->getArgumentType().getTypePtr());
VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- addStmt(VA->getSizeExpr());
+ lastBlock = addStmt(VA->getSizeExpr());
}
- return Block;
+ return lastBlock;
}
/// VisitStmtExpr - Utility method to handle (nested) statement
/// expressions (a GCC extension).
CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, SE)) {
autoCreateBlock();
appendStmt(Block, SE);
}
@@ -2180,6 +2245,18 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
assert(Terminator->getBody() && "switch must contain a non-NULL body");
Block = NULL;
+ // For pruning unreachable case statements, save the current state
+ // for tracking the condition value.
+ SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered,
+ false);
+
+ // Determine if the switch condition can be explicitly evaluated.
+ assert(Terminator->getCond() && "switch condition must be non-NULL");
+ Expr::EvalResult result;
+ bool b = tryEvaluate(Terminator->getCond(), result);
+ SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond,
+ b ? &result : 0);
+
// If body is not a compound statement create implicit scope
// and add destructors.
if (!isa<CompoundStmt>(Terminator->getBody()))
@@ -2192,12 +2269,14 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
}
// If we have no "default:" case, the default transition is to the code
- // following the switch body.
- addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock);
+ // following the switch body. Moreover, take into account if all the
+ // cases of a switch are covered (e.g., switching on an enum value).
+ addSuccessor(SwitchTerminatedBlock,
+ switchExclusivelyCovered || Terminator->isAllEnumCasesCovered()
+ ? 0 : DefaultCaseBlock);
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
- assert(Terminator->getCond() && "switch condition must be non-NULL");
Block = SwitchTerminatedBlock;
Block = addStmt(Terminator->getCond());
@@ -2206,19 +2285,60 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
if (VarDecl *VD = Terminator->getConditionVariable()) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
- appendStmt(Block, Terminator, AddStmtChoice::AlwaysAdd);
+ appendStmt(Block, Terminator->getConditionVariableDeclStmt());
addStmt(Init);
}
}
return Block;
}
+
+static bool shouldAddCase(bool &switchExclusivelyCovered,
+ const Expr::EvalResult *switchCond,
+ const CaseStmt *CS,
+ ASTContext &Ctx) {
+ if (!switchCond)
+ return true;
+
+ bool addCase = false;
+
+ if (!switchExclusivelyCovered) {
+ if (switchCond->Val.isInt()) {
+ // Evaluate the LHS of the case value.
+ Expr::EvalResult V1;
+ CS->getLHS()->Evaluate(V1, Ctx);
+ assert(V1.Val.isInt());
+ const llvm::APSInt &condInt = switchCond->Val.getInt();
+ const llvm::APSInt &lhsInt = V1.Val.getInt();
+
+ if (condInt == lhsInt) {
+ addCase = true;
+ switchExclusivelyCovered = true;
+ }
+ else if (condInt < lhsInt) {
+ if (const Expr *RHS = CS->getRHS()) {
+ // Evaluate the RHS of the case value.
+ Expr::EvalResult V2;
+ RHS->Evaluate(V2, Ctx);
+ assert(V2.Val.isInt());
+ if (V2.Val.getInt() <= condInt) {
+ addCase = true;
+ switchExclusivelyCovered = true;
+ }
+ }
+ }
+ }
+ else
+ addCase = true;
+ }
+ return addCase;
+}
CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
// CaseStmts are essentially labels, so they are the first statement in a
// block.
CFGBlock *TopBlock = 0, *LastBlock = 0;
-
+
if (Stmt *Sub = CS->getSubStmt()) {
// For deeply nested chains of CaseStmts, instead of doing a recursion
// (which can blow out the stack), manually unroll and create blocks
@@ -2232,9 +2352,12 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
else
TopBlock = currentBlock;
- addSuccessor(SwitchTerminatedBlock, currentBlock);
- LastBlock = currentBlock;
+ addSuccessor(SwitchTerminatedBlock,
+ shouldAddCase(switchExclusivelyCovered, switchCond,
+ CS, *Context)
+ ? currentBlock : 0);
+ LastBlock = currentBlock;
CS = cast<CaseStmt>(Sub);
Sub = CS->getSubStmt();
}
@@ -2256,7 +2379,10 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
// Add this block to the list of successors for the block with the switch
// statement.
assert(SwitchTerminatedBlock);
- addSuccessor(SwitchTerminatedBlock, CaseBlock);
+ addSuccessor(SwitchTerminatedBlock,
+ shouldAddCase(switchExclusivelyCovered, switchCond,
+ CS, *Context)
+ ? CaseBlock : 0);
// We set Block to NULL to allow lazy creation of a new block (if necessary)
Block = NULL;
@@ -2391,6 +2517,122 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
return CatchBlock;
}
+CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) {
+ // C++0x for-range statements are specified as [stmt.ranged]:
+ //
+ // {
+ // auto && __range = range-init;
+ // for ( auto __begin = begin-expr,
+ // __end = end-expr;
+ // __begin != __end;
+ // ++__begin ) {
+ // for-range-declaration = *__begin;
+ // statement
+ // }
+ // }
+
+ // Save local scope position before the addition of the implicit variables.
+ SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+
+ // Create local scopes and destructors for range, begin and end variables.
+ if (Stmt *Range = S->getRangeStmt())
+ addLocalScopeForStmt(Range);
+ if (Stmt *BeginEnd = S->getBeginEndStmt())
+ addLocalScopeForStmt(BeginEnd);
+ addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
+
+ LocalScope::const_iterator ContinueScopePos = ScopePos;
+
+ // "for" is a control-flow statement. Thus we stop processing the current
+ // block.
+ CFGBlock* LoopSuccessor = NULL;
+ if (Block) {
+ if (badCFG)
+ return 0;
+ LoopSuccessor = Block;
+ } else
+ LoopSuccessor = Succ;
+
+ // Save the current value for the break targets.
+ // All breaks should go to the code following the loop.
+ SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
+
+ // The block for the __begin != __end expression.
+ CFGBlock* ConditionBlock = createBlock(false);
+ ConditionBlock->setTerminator(S);
+
+ // Now add the actual condition to the condition block.
+ if (Expr *C = S->getCond()) {
+ Block = ConditionBlock;
+ CFGBlock *BeginConditionBlock = addStmt(C);
+ if (badCFG)
+ return 0;
+ assert(BeginConditionBlock == ConditionBlock &&
+ "condition block in for-range was unexpectedly complex");
+ (void)BeginConditionBlock;
+ }
+
+ // The condition block is the implicit successor for the loop body as well as
+ // any code above the loop.
+ Succ = ConditionBlock;
+
+ // See if this is a known constant.
+ TryResult KnownVal(true);
+
+ if (S->getCond())
+ KnownVal = tryEvaluateBool(S->getCond());
+
+ // Now create the loop body.
+ {
+ assert(S->getBody());
+
+ // Save the current values for Block, Succ, and continue targets.
+ SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
+ SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
+
+ // Generate increment code in its own basic block. This is the target of
+ // continue statements.
+ Block = 0;
+ Succ = addStmt(S->getInc());
+ ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
+
+ // The starting block for the loop increment is the block that should
+ // represent the 'loop target' for looping back to the start of the loop.
+ ContinueJumpTarget.block->setLoopTarget(S);
+
+ // Finish up the increment block and prepare to start the loop body.
+ assert(Block);
+ if (badCFG)
+ return 0;
+ Block = 0;
+
+
+ // Add implicit scope and dtors for loop variable.
+ addLocalScopeAndDtors(S->getLoopVarStmt());
+
+ // Populate a new block to contain the loop body and loop variable.
+ Block = addStmt(S->getBody());
+ if (badCFG)
+ return 0;
+ Block = addStmt(S->getLoopVarStmt());
+ if (badCFG)
+ return 0;
+
+ // This new body block is a successor to our condition block.
+ addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block);
+ }
+
+ // Link up the condition block with the code that follows the loop (the
+ // false branch).
+ addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor);
+
+ // Add the initialization statements.
+ Block = createBlock();
+ addStmt(S->getBeginEndStmt());
+ return addStmt(S->getRangeStmt());
+}
+
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
AddStmtChoice asc) {
if (BuildOpts.AddImplicitDtors) {
@@ -2407,9 +2649,9 @@ CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
// We do not want to propagate the AlwaysAdd property.
asc = asc.withAlwaysAdd(false);
@@ -2421,16 +2663,16 @@ CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
AddStmtChoice asc) {
autoCreateBlock();
if (!C->isElidable())
- appendStmt(Block, C, asc.withAlwaysAdd(true));
+ appendStmt(Block, C);
return VisitChildren(C);
}
CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
// We do not want to propagate the AlwaysAdd property.
asc = asc.withAlwaysAdd(false);
}
@@ -2440,22 +2682,22 @@ CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
AddStmtChoice asc) {
autoCreateBlock();
- appendStmt(Block, C, asc.withAlwaysAdd(true));
+ appendStmt(Block, C);
return VisitChildren(C);
}
CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
AddStmtChoice asc) {
autoCreateBlock();
- appendStmt(Block, C, asc.withAlwaysAdd(true));
+ appendStmt(Block, C);
return VisitChildren(C);
}
CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
AddStmtChoice asc) {
- if (asc.alwaysAdd()) {
+ if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
- appendStmt(Block, E, asc);
+ appendStmt(Block, E);
}
return Visit(E->getSubExpr(), AddStmtChoice());
}
@@ -2699,9 +2941,53 @@ CFGBlock* CFG::createBlock() {
/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
/// CFG is returned to the caller.
CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C,
- BuildOptions BO) {
- CFGBuilder Builder;
- return Builder.buildCFG(D, Statement, C, BO);
+ const BuildOptions &BO) {
+ CFGBuilder Builder(C, BO);
+ return Builder.buildCFG(D, Statement);
+}
+
+const CXXDestructorDecl *
+CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
+ switch (getKind()) {
+ case CFGElement::Invalid:
+ case CFGElement::Statement:
+ case CFGElement::Initializer:
+ llvm_unreachable("getDestructorDecl should only be used with "
+ "ImplicitDtors");
+ case CFGElement::AutomaticObjectDtor: {
+ const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl();
+ QualType ty = var->getType();
+ ty = ty.getNonReferenceType();
+ if (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
+ ty = arrayType->getElementType();
+ }
+ const RecordType *recordType = ty->getAs<RecordType>();
+ const CXXRecordDecl *classDecl =
+ cast<CXXRecordDecl>(recordType->getDecl());
+ return classDecl->getDestructor();
+ }
+ case CFGElement::TemporaryDtor: {
+ const CXXBindTemporaryExpr *bindExpr =
+ cast<CFGTemporaryDtor>(this)->getBindTemporaryExpr();
+ const CXXTemporary *temp = bindExpr->getTemporary();
+ return temp->getDestructor();
+ }
+ case CFGElement::BaseDtor:
+ case CFGElement::MemberDtor:
+
+ // Not yet supported.
+ return 0;
+ }
+ llvm_unreachable("getKind() returned bogus value");
+ return 0;
+}
+
+bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
+ if (const CXXDestructorDecl *cdecl = getDestructorDecl(astContext)) {
+ QualType ty = cdecl->getType();
+ return cast<FunctionType>(ty)->getNoReturnAttr();
+ }
+ return false;
}
//===----------------------------------------------------------------------===//
@@ -2740,8 +3026,8 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
- if (CFGStmt S = BI->getAs<CFGStmt>())
- FindSubExprAssignments(S, SubExprAssignments);
+ if (const CFGStmt *S = BI->getAs<CFGStmt>())
+ FindSubExprAssignments(S->getStmt(), SubExprAssignments);
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
@@ -2749,10 +3035,10 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// block-level that are block-level expressions.
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) {
- CFGStmt CS = BI->getAs<CFGStmt>();
- if (!CS.isValid())
+ const CFGStmt *CS = BI->getAs<CFGStmt>();
+ if (!CS)
continue;
- if (Expr* Exp = dyn_cast<Expr>(CS.getStmt())) {
+ if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) {
if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
// Assignment expressions that are not nested within another
@@ -2814,15 +3100,15 @@ unsigned CFG::getNumBlkExprs() {
bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
const CFGBlock *From, const CFGBlock *To) {
- if (F.IgnoreDefaultsWithCoveredEnums) {
+ if (To && F.IgnoreDefaultsWithCoveredEnums) {
// If the 'To' has no label or is labeled but the label isn't a
// CaseStmt then filter this edge.
if (const SwitchStmt *S =
- dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) {
+ dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) {
if (S->isAllEnumCasesCovered()) {
- const Stmt *L = To->getLabel();
- if (!L || !isa<CaseStmt>(L))
- return true;
+ const Stmt *L = To->getLabel();
+ if (!L || !isa<CaseStmt>(L))
+ return true;
}
}
}
@@ -2845,8 +3131,8 @@ CFG::~CFG() {
namespace {
class StmtPrinterHelper : public PrinterHelper {
- typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
- typedef llvm::DenseMap<Decl*,std::pair<unsigned,unsigned> > DeclMapTy;
+ typedef llvm::DenseMap<const Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
+ typedef llvm::DenseMap<const Decl*,std::pair<unsigned,unsigned> > DeclMapTy;
StmtMapTy StmtMap;
DeclMapTy DeclMap;
signed currentBlock;
@@ -2855,42 +3141,62 @@ class StmtPrinterHelper : public PrinterHelper {
public:
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
- : currentBlock(0), currentStmt(0), LangOpts(LO) {
+ : currentBlock(0), currentStmt(0), LangOpts(LO)
+ {
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
unsigned j = 1;
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
BI != BEnd; ++BI, ++j ) {
- if (CFGStmt SE = BI->getAs<CFGStmt>()) {
+ if (const CFGStmt *SE = BI->getAs<CFGStmt>()) {
+ const Stmt *stmt= SE->getStmt();
std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
- StmtMap[SE] = P;
-
- if (DeclStmt* DS = dyn_cast<DeclStmt>(SE.getStmt())) {
- DeclMap[DS->getSingleDecl()] = P;
-
- } else if (IfStmt* IS = dyn_cast<IfStmt>(SE.getStmt())) {
- if (VarDecl* VD = IS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (ForStmt* FS = dyn_cast<ForStmt>(SE.getStmt())) {
- if (VarDecl* VD = FS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (WhileStmt* WS = dyn_cast<WhileStmt>(SE.getStmt())) {
- if (VarDecl* VD = WS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (SwitchStmt* SS = dyn_cast<SwitchStmt>(SE.getStmt())) {
- if (VarDecl* VD = SS->getConditionVariable())
- DeclMap[VD] = P;
-
- } else if (CXXCatchStmt* CS = dyn_cast<CXXCatchStmt>(SE.getStmt())) {
- if (VarDecl* VD = CS->getExceptionDecl())
- DeclMap[VD] = P;
+ StmtMap[stmt] = P;
+
+ switch (stmt->getStmtClass()) {
+ case Stmt::DeclStmtClass:
+ DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
+ break;
+ case Stmt::IfStmtClass: {
+ const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::ForStmtClass: {
+ const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::WhileStmtClass: {
+ const VarDecl *var =
+ cast<WhileStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::SwitchStmtClass: {
+ const VarDecl *var =
+ cast<SwitchStmt>(stmt)->getConditionVariable();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ case Stmt::CXXCatchStmtClass: {
+ const VarDecl *var =
+ cast<CXXCatchStmt>(stmt)->getExceptionDecl();
+ if (var)
+ DeclMap[var] = P;
+ break;
+ }
+ default:
+ break;
}
}
}
}
}
+
virtual ~StmtPrinterHelper() {}
@@ -2913,7 +3219,7 @@ public:
return true;
}
- bool handleDecl(Decl* D, llvm::raw_ostream& OS) {
+ bool handleDecl(const Decl* D, llvm::raw_ostream& OS) {
DeclMapTy::iterator I = DeclMap.find(D);
if (I == DeclMap.end())
@@ -3031,8 +3337,8 @@ public:
static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
const CFGElement &E) {
- if (CFGStmt CS = E.getAs<CFGStmt>()) {
- Stmt *S = CS;
+ if (const CFGStmt *CS = E.getAs<CFGStmt>()) {
+ Stmt *S = CS->getStmt();
if (Helper) {
@@ -3069,8 +3375,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
if (isa<Expr>(S))
OS << '\n';
- } else if (CFGInitializer IE = E.getAs<CFGInitializer>()) {
- CXXCtorInitializer* I = IE;
+ } else if (const CFGInitializer *IE = E.getAs<CFGInitializer>()) {
+ const CXXCtorInitializer *I = IE->getInitializer();
if (I->isBaseInitializer())
OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
else OS << I->getAnyMember()->getName();
@@ -3084,8 +3390,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
OS << " (Base initializer)\n";
else OS << " (Member initializer)\n";
- } else if (CFGAutomaticObjDtor DE = E.getAs<CFGAutomaticObjDtor>()){
- VarDecl* VD = DE.getVarDecl();
+ } else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){
+ const VarDecl* VD = DE->getVarDecl();
Helper->handleDecl(VD, OS);
const Type* T = VD->getType().getTypePtr();
@@ -3097,13 +3403,13 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
- } else if (CFGBaseDtor BE = E.getAs<CFGBaseDtor>()) {
- const CXXBaseSpecifier *BS = BE.getBaseSpecifier();
+ } else if (const CFGBaseDtor *BE = E.getAs<CFGBaseDtor>()) {
+ const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Base object destructor)\n";
- } else if (CFGMemberDtor ME = E.getAs<CFGMemberDtor>()) {
- FieldDecl *FD = ME.getFieldDecl();
+ } else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) {
+ const FieldDecl *FD = ME->getFieldDecl();
const Type *T = FD->getType().getTypePtr();
if (const Type *ET = T->getArrayElementTypeNoTypeQual())
@@ -3113,8 +3419,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
OS << " (Member object destructor)\n";
- } else if (CFGTemporaryDtor TE = E.getAs<CFGTemporaryDtor>()) {
- CXXBindTemporaryExpr *BT = TE.getBindTemporaryExpr();
+ } else if (const CFGTemporaryDtor *TE = E.getAs<CFGTemporaryDtor>()) {
+ const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Temporary object destructor)\n";
}
@@ -3344,32 +3650,6 @@ Stmt* CFGBlock::getTerminatorCondition() {
return E ? E->IgnoreParens() : NULL;
}
-bool CFGBlock::hasBinaryBranchTerminator() const {
- const Stmt *Terminator = this->Terminator;
- if (!Terminator)
- return false;
-
- Expr* E = NULL;
-
- switch (Terminator->getStmtClass()) {
- default:
- return false;
-
- case Stmt::ForStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::IfStmtClass:
- case Stmt::ChooseExprClass:
- case Stmt::BinaryConditionalOperatorClass:
- case Stmt::ConditionalOperatorClass:
- case Stmt::BinaryOperatorClass:
- return true;
- }
-
- return E ? E->IgnoreParens() : NULL;
-}
-
-
//===----------------------------------------------------------------------===//
// CFG Graphviz Visualization
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp
index 77865849014a..65cd0898573c 100644
--- a/lib/Analysis/CFGReachabilityAnalysis.cpp
+++ b/lib/Analysis/CFGReachabilityAnalysis.cpp
@@ -19,10 +19,10 @@
using namespace clang;
-CFGReachabilityAnalysis::CFGReachabilityAnalysis(const CFG &cfg)
+CFGReverseBlockReachabilityAnalysis::CFGReverseBlockReachabilityAnalysis(const CFG &cfg)
: analyzed(cfg.getNumBlockIDs(), false) {}
-bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src,
+bool CFGReverseBlockReachabilityAnalysis::isReachable(const CFGBlock *Src,
const CFGBlock *Dst) {
const unsigned DstBlockID = Dst->getBlockID();
@@ -39,7 +39,7 @@ bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src,
// Maps reachability to a common node by walking the predecessors of the
// destination node.
-void CFGReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
+void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
llvm::SmallVector<const CFGBlock *, 11> worklist;
llvm::BitVector visited(analyzed.size());
diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp
index 3a030f9bdd1e..1fd5eedfeb86 100644
--- a/lib/Analysis/CFGStmtMap.cpp
+++ b/lib/Analysis/CFGStmtMap.cpp
@@ -50,11 +50,11 @@ static void Accumulate(SMap &SM, CFGBlock *B) {
// First walk the block-level expressions.
for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) {
const CFGElement &CE = *I;
- CFGStmt CS = CE.getAs<CFGStmt>();
- if (!CS.isValid())
+ const CFGStmt *CS = CE.getAs<CFGStmt>();
+ if (!CS)
continue;
- CFGBlock *&Entry = SM[CS];
+ CFGBlock *&Entry = SM[CS->getStmt()];
// If 'Entry' is already initialized (e.g., a terminator was already),
// skip.
if (Entry)
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 84b211f2cfca..967fc2930f42 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -13,7 +13,6 @@ add_clang_library(clangAnalysis
ReachableCode.cpp
ScanfFormatString.cpp
UninitializedValues.cpp
- UninitializedValuesV2.cpp
)
add_dependencies(clangAnalysis ClangAttrClasses ClangAttrList
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 22b6c1aaf021..4c62f36e6c92 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace ento;
@@ -35,84 +36,27 @@ using llvm::StringRef;
// not release it."
//
-static bool isWordEnd(char ch, char prev, char next) {
- return ch == '\0'
- || (islower(prev) && isupper(ch)) // xxxC
- || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate
- || !isalpha(ch);
-}
-
-static const char* parseWord(const char* s) {
- char ch = *s, prev = '\0';
- assert(ch != '\0');
- char next = *(s+1);
- while (!isWordEnd(ch, prev, next)) {
- prev = ch;
- ch = next;
- next = *((++s)+1);
- }
- return s;
-}
-
-cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
- bool ignorePrefix) {
- IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
-
- if (!II)
- return NoConvention;
-
- const char *s = II->getNameStart();
-
- const char *orig = s;
- // A method/function name may contain a prefix. We don't know it is there,
- // however, until we encounter the first '_'.
- while (*s != '\0') {
- // Skip '_', numbers, ':', etc.
- if (*s == '_' || !isalpha(*s)) {
- ++s;
- continue;
- }
- break;
- }
-
- if (!ignorePrefix && s != orig)
+cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
+ switch (S.getMethodFamily()) {
+ case OMF_None:
+ case OMF_autorelease:
+ case OMF_dealloc:
+ case OMF_release:
+ case OMF_retain:
+ case OMF_retainCount:
return NoConvention;
- // Parse the first word, and look for specific keywords.
- const char *wordEnd = parseWord(s);
- assert(wordEnd > s);
- unsigned len = wordEnd - s;
+ case OMF_init:
+ return InitRule;
- switch (len) {
- default:
- return NoConvention;
- case 3:
- // Methods starting with 'new' follow the create rule.
- return (memcmp(s, "new", 3) == 0) ? CreateRule : NoConvention;
- case 4:
- // Methods starting with 'copy' follow the create rule.
- if (memcmp(s, "copy", 4) == 0)
- return CreateRule;
- // Methods starting with 'init' follow the init rule.
- if (memcmp(s, "init", 4) == 0)
- return InitRule;
- return NoConvention;
- case 5:
- return (memcmp(s, "alloc", 5) == 0) ? CreateRule : NoConvention;
- case 7:
- // Methods starting with 'mutableCopy' follow the create rule.
- if (memcmp(s, "mutable", 7) == 0) {
- // Look at the next word to see if it is "Copy".
- s = wordEnd;
- if (*s != '\0') {
- wordEnd = parseWord(s);
- len = wordEnd - s;
- if (len == 4 && memcmp(s, "Copy", 4) == 0)
- return CreateRule;
- }
- }
- return NoConvention;
+ case OMF_alloc:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ case OMF_new:
+ return CreateRule;
}
+ llvm_unreachable("unexpected naming convention");
+ return NoConvention;
}
bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index db9f7f2c834e..00b0b279e4a0 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -381,8 +381,32 @@ bool PrintfSpecifier::fixType(QualType QT) {
// Set length modifier
switch (BT->getKind()) {
- default:
- // The rest of the conversions are either optional or for non-builtin types
+ case BuiltinType::Bool:
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::UInt128:
+ case BuiltinType::Int128:
+ // Integral types which are non-trivial to correct.
+ return false;
+
+ case BuiltinType::Void:
+ case BuiltinType::NullPtr:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ case BuiltinType::Dependent:
+ case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ // Misc other stuff which doesn't make sense here.
+ return false;
+
+ case BuiltinType::UInt:
+ case BuiltinType::Int:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
LM.setKind(LengthModifier::None);
break;
@@ -398,8 +422,6 @@ bool PrintfSpecifier::fixType(QualType QT) {
LM.setKind(LengthModifier::AsShort);
break;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
case BuiltinType::Long:
case BuiltinType::ULong:
LM.setKind(LengthModifier::AsLong);
@@ -429,24 +451,19 @@ bool PrintfSpecifier::fixType(QualType QT) {
else if (QT->isRealFloatingType()) {
CS.setKind(ConversionSpecifier::fArg);
}
- else if (QT->isPointerType()) {
- CS.setKind(ConversionSpecifier::pArg);
- Precision.setHowSpecified(OptionalAmount::NotSpecified);
- HasAlternativeForm = 0;
- HasLeadingZeroes = 0;
- HasPlusPrefix = 0;
- }
else if (QT->isSignedIntegerType()) {
CS.setKind(ConversionSpecifier::dArg);
HasAlternativeForm = 0;
}
else if (QT->isUnsignedIntegerType()) {
- CS.setKind(ConversionSpecifier::uArg);
+ // Preserve the original formatting, e.g. 'X', 'o'.
+ if (!cast<PrintfConversionSpecifier>(CS).isUIntArg())
+ CS.setKind(ConversionSpecifier::uArg);
HasAlternativeForm = 0;
HasPlusPrefix = 0;
}
else {
- return false;
+ assert(0 && "Unexpected type");
}
return true;
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 7afa586479b3..9ac456f53a67 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -31,11 +31,11 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
R1 = R2 = SourceRange();
if (sn < b.size()) {
- CFGStmt CS = b[sn].getAs<CFGStmt>();
+ const CFGStmt *CS = b[sn].getAs<CFGStmt>();
if (!CS)
return SourceLocation();
- S = CS.getStmt();
+ S = CS->getStmt();
} else if (b.getTerminator())
S = b.getTerminator();
else
@@ -49,7 +49,7 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
const BinaryOperator *BO = cast<BinaryOperator>(S);
if (BO->getOpcode() == BO_Comma) {
if (sn+1 < b.size())
- return b[sn+1].getAs<CFGStmt>().getStmt()->getLocStart();
+ return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart();
const CFGBlock *n = &b;
while (1) {
if (n->getTerminator())
@@ -60,7 +60,7 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
if (n->pred_size() != 1)
return SourceLocation();
if (!n->empty())
- return n[0][0].getAs<CFGStmt>().getStmt()->getLocStart();
+ return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart();
}
}
R1 = BO->getLHS()->getSourceRange();
@@ -193,7 +193,7 @@ unsigned ScanReachableFromBlock(const CFGBlock &Start,
unsigned count = 0;
llvm::SmallVector<const CFGBlock*, 32> WL;
- // Prep work queue
+ // Prep work queue
Reachable.set(Start.getBlockID());
++count;
WL.push_back(&Start);
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index c08cbedf4b94..88a2db751a43 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -7,311 +7,723 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements Uninitialized Values analysis for source-level CFGs.
+// This file implements uninitialized values analysis for source-level CFGs.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include <utility>
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Analysis/AnalysisDiagnostic.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
-
-#include "llvm/ADT/SmallPtrSet.h"
+#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
using namespace clang;
-//===----------------------------------------------------------------------===//
-// Dataflow initialization logic.
-//===----------------------------------------------------------------------===//
-
-namespace {
+static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
+ if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
+ !vd->isExceptionVariable() &&
+ vd->getDeclContext() == dc) {
+ QualType ty = vd->getType();
+ return ty->isScalarType() || ty->isVectorType();
+ }
+ return false;
+}
-class RegisterDecls
- : public CFGRecStmtDeclVisitor<RegisterDecls> {
+//------------------------------------------------------------------------====//
+// DeclToIndex: a mapping from Decls we track to value indices.
+//====------------------------------------------------------------------------//
- UninitializedValues::AnalysisDataTy& AD;
+namespace {
+class DeclToIndex {
+ llvm::DenseMap<const VarDecl *, unsigned> map;
public:
- RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
-
- void VisitVarDecl(VarDecl* VD) { AD.Register(VD); }
- CFG& getCFG() { return AD.getCFG(); }
+ DeclToIndex() {}
+
+ /// Compute the actual mapping from declarations to bits.
+ void computeMap(const DeclContext &dc);
+
+ /// Return the number of declarations in the map.
+ unsigned size() const { return map.size(); }
+
+ /// Returns the bit vector index for a given declaration.
+ llvm::Optional<unsigned> getValueIndex(const VarDecl *d) const;
};
+}
-} // end anonymous namespace
+void DeclToIndex::computeMap(const DeclContext &dc) {
+ unsigned count = 0;
+ DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
+ E(dc.decls_end());
+ for ( ; I != E; ++I) {
+ const VarDecl *vd = *I;
+ if (isTrackedVar(vd, &dc))
+ map[vd] = count++;
+ }
+}
-void UninitializedValues::InitializeValues(const CFG& cfg) {
- RegisterDecls R(getAnalysisData());
- cfg.VisitBlockStmts(R);
+llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
+ llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
+ if (I == map.end())
+ return llvm::Optional<unsigned>();
+ return I->second;
}
-//===----------------------------------------------------------------------===//
-// Transfer functions.
-//===----------------------------------------------------------------------===//
+//------------------------------------------------------------------------====//
+// CFGBlockValues: dataflow values for CFG blocks.
+//====------------------------------------------------------------------------//
-namespace {
-class TransferFuncs
- : public CFGStmtVisitor<TransferFuncs,bool> {
+// These values are defined in such a way that a merge can be done using
+// a bitwise OR.
+enum Value { Unknown = 0x0, /* 00 */
+ Initialized = 0x1, /* 01 */
+ Uninitialized = 0x2, /* 10 */
+ MayUninitialized = 0x3 /* 11 */ };
- UninitializedValues::ValTy V;
- UninitializedValues::AnalysisDataTy& AD;
+static bool isUninitialized(const Value v) {
+ return v >= Uninitialized;
+}
+static bool isAlwaysUninit(const Value v) {
+ return v == Uninitialized;
+}
+
+namespace {
+class ValueVector {
+ llvm::BitVector vec;
public:
- TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
+ ValueVector() {}
+ ValueVector(unsigned size) : vec(size << 1) {}
+ void resize(unsigned n) { vec.resize(n << 1); }
+ void merge(const ValueVector &rhs) { vec |= rhs.vec; }
+ bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; }
+ void reset() { vec.reset(); }
+
+ class reference {
+ ValueVector &vv;
+ const unsigned idx;
+
+ reference(); // Undefined
+ public:
+ reference(ValueVector &vv, unsigned idx) : vv(vv), idx(idx) {}
+ ~reference() {}
+
+ reference &operator=(Value v) {
+ vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false;
+ vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false;
+ return *this;
+ }
+ operator Value() {
+ unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0);
+ return (Value) x;
+ }
+ };
+
+ reference operator[](unsigned idx) { return reference(*this, idx); }
+};
- UninitializedValues::ValTy& getVal() { return V; }
- CFG& getCFG() { return AD.getCFG(); }
+typedef std::pair<ValueVector *, ValueVector *> BVPair;
- void SetTopValue(UninitializedValues::ValTy& X) {
- X.setDeclValues(AD);
- X.resetBlkExprValues(AD);
+class CFGBlockValues {
+ const CFG &cfg;
+ BVPair *vals;
+ ValueVector scratch;
+ DeclToIndex declToIndex;
+
+ ValueVector &lazyCreate(ValueVector *&bv);
+public:
+ CFGBlockValues(const CFG &cfg);
+ ~CFGBlockValues();
+
+ unsigned getNumEntries() const { return declToIndex.size(); }
+
+ void computeSetOfDeclarations(const DeclContext &dc);
+ ValueVector &getValueVector(const CFGBlock *block,
+ const CFGBlock *dstBlock);
+
+ BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate);
+
+ void mergeIntoScratch(ValueVector const &source, bool isFirst);
+ bool updateValueVectorWithScratch(const CFGBlock *block);
+ bool updateValueVectors(const CFGBlock *block, const BVPair &newVals);
+
+ bool hasNoDeclarations() const {
+ return declToIndex.size() == 0;
}
+
+ bool hasEntry(const VarDecl *vd) const {
+ return declToIndex.getValueIndex(vd).hasValue();
+ }
+
+ bool hasValues(const CFGBlock *block);
+
+ void resetScratch();
+ ValueVector &getScratch() { return scratch; }
+
+ ValueVector::reference operator[](const VarDecl *vd);
+};
+} // end anonymous namespace
- bool VisitDeclRefExpr(DeclRefExpr* DR);
- bool VisitBinaryOperator(BinaryOperator* B);
- bool VisitUnaryOperator(UnaryOperator* U);
- bool VisitStmt(Stmt* S);
- bool VisitCallExpr(CallExpr* C);
- bool VisitDeclStmt(DeclStmt* D);
- bool VisitAbstractConditionalOperator(AbstractConditionalOperator* C);
- bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
-
- bool Visit(Stmt *S);
- bool BlockStmt_VisitExpr(Expr* E);
+CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
+ unsigned n = cfg.getNumBlockIDs();
+ if (!n)
+ return;
+ vals = new std::pair<ValueVector*, ValueVector*>[n];
+ memset((void*)vals, 0, sizeof(*vals) * n);
+}
- void VisitTerminator(CFGBlock* B) { }
-
- void setCurrentBlock(const CFGBlock *block) {}
-};
+CFGBlockValues::~CFGBlockValues() {
+ unsigned n = cfg.getNumBlockIDs();
+ if (n == 0)
+ return;
+ for (unsigned i = 0; i < n; ++i) {
+ delete vals[i].first;
+ delete vals[i].second;
+ }
+ delete [] vals;
+}
-static const bool Initialized = false;
-static const bool Uninitialized = true;
+void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
+ declToIndex.computeMap(dc);
+ scratch.resize(declToIndex.size());
+}
-bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
+ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) {
+ if (!bv)
+ bv = new ValueVector(declToIndex.size());
+ return *bv;
+}
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
- if (VD->isLocalVarDecl()) {
+/// This function pattern matches for a '&&' or '||' that appears at
+/// the beginning of a CFGBlock that also (1) has a terminator and
+/// (2) has no other elements. If such an expression is found, it is returned.
+static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
+ if (block->empty())
+ return 0;
+
+ const CFGStmt *cstmt = block->front().getAs<CFGStmt>();
+ if (!cstmt)
+ return 0;
+
+ BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt->getStmt());
+
+ if (!b || !b->isLogicalOp())
+ return 0;
+
+ if (block->pred_size() == 2 &&
+ ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
+ block->size() == 1))
+ return b;
+
+ return 0;
+}
- if (AD.Observer)
- AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD);
+ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block,
+ const CFGBlock *dstBlock) {
+ unsigned idx = block->getBlockID();
+ if (dstBlock && getLogicalOperatorInChain(block)) {
+ if (*block->succ_begin() == dstBlock)
+ return lazyCreate(vals[idx].first);
+ assert(*(block->succ_begin()+1) == dstBlock);
+ return lazyCreate(vals[idx].second);
+ }
- // Pseudo-hack to prevent cascade of warnings. If an accessed variable
- // is uninitialized, then we are already going to flag a warning for
- // this variable, which a "source" of uninitialized values.
- // We can otherwise do a full "taint" of uninitialized values. The
- // client has both options by toggling AD.FullUninitTaint.
+ assert(vals[idx].second == 0);
+ return lazyCreate(vals[idx].first);
+}
- if (AD.FullUninitTaint)
- return V(VD,AD);
- }
+bool CFGBlockValues::hasValues(const CFGBlock *block) {
+ unsigned idx = block->getBlockID();
+ return vals[idx].second != 0;
+}
- return Initialized;
+BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block,
+ bool shouldLazyCreate) {
+ unsigned idx = block->getBlockID();
+ lazyCreate(vals[idx].first);
+ if (shouldLazyCreate)
+ lazyCreate(vals[idx].second);
+ return vals[idx];
}
-static VarDecl* FindBlockVarDecl(Expr* E) {
+void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
+ bool isFirst) {
+ if (isFirst)
+ scratch = source;
+ else
+ scratch.merge(source);
+}
+#if 0
+static void printVector(const CFGBlock *block, ValueVector &bv,
+ unsigned num) {
+
+ llvm::errs() << block->getBlockID() << " :";
+ for (unsigned i = 0; i < bv.size(); ++i) {
+ llvm::errs() << ' ' << bv[i];
+ }
+ llvm::errs() << " : " << num << '\n';
+}
+#endif
+
+bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
+ ValueVector &dst = getValueVector(block, 0);
+ bool changed = (dst != scratch);
+ if (changed)
+ dst = scratch;
+#if 0
+ printVector(block, scratch, 0);
+#endif
+ return changed;
+}
- // Blast through casts and parentheses to find any DeclRefExprs that
- // refer to a block VarDecl.
+bool CFGBlockValues::updateValueVectors(const CFGBlock *block,
+ const BVPair &newVals) {
+ BVPair &vals = getValueVectors(block, true);
+ bool changed = *newVals.first != *vals.first ||
+ *newVals.second != *vals.second;
+ *vals.first = *newVals.first;
+ *vals.second = *newVals.second;
+#if 0
+ printVector(block, *vals.first, 1);
+ printVector(block, *vals.second, 2);
+#endif
+ return changed;
+}
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
- if (VD->isLocalVarDecl()) return VD;
+void CFGBlockValues::resetScratch() {
+ scratch.reset();
+}
- return NULL;
+ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
+ const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
+ assert(idx.hasValue());
+ return scratch[idx.getValue()];
}
-bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
+//------------------------------------------------------------------------====//
+// Worklist: worklist for dataflow analysis.
+//====------------------------------------------------------------------------//
- if (VarDecl* VD = FindBlockVarDecl(B->getLHS()))
- if (B->isAssignmentOp()) {
- if (B->getOpcode() == BO_Assign)
- return V(VD,AD) = Visit(B->getRHS());
- else // Handle +=, -=, *=, etc. We do want '&', not '&&'.
- return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS());
- }
+namespace {
+class DataflowWorklist {
+ llvm::SmallVector<const CFGBlock *, 20> worklist;
+ llvm::BitVector enqueuedBlocks;
+public:
+ DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
+
+ void enqueue(const CFGBlock *block);
+ void enqueueSuccessors(const CFGBlock *block);
+ const CFGBlock *dequeue();
+
+};
+}
- return VisitStmt(B);
+void DataflowWorklist::enqueue(const CFGBlock *block) {
+ if (!block)
+ return;
+ unsigned idx = block->getBlockID();
+ if (enqueuedBlocks[idx])
+ return;
+ worklist.push_back(block);
+ enqueuedBlocks[idx] = true;
}
-bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
- for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
- VarDecl *VD = dyn_cast<VarDecl>(*I);
- if (VD && VD->isLocalVarDecl()) {
- if (Stmt* I = VD->getInit()) {
- // Visit the subexpression to check for uses of uninitialized values,
- // even if we don't propagate that value.
- bool isSubExprUninit = Visit(I);
- V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized;
- }
- else {
- // Special case for declarations of array types. For things like:
- //
- // char x[10];
- //
- // we should treat "x" as being initialized, because the variable
- // "x" really refers to the memory block. Clearly x[1] is
- // uninitialized, but expressions like "(char *) x" really do refer to
- // an initialized value. This simple dataflow analysis does not reason
- // about the contents of arrays, although it could be potentially
- // extended to do so if the array were of constant size.
- if (VD->getType()->isArrayType())
- V(VD,AD) = Initialized;
- else
- V(VD,AD) = Uninitialized;
- }
- }
+void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
+ for (CFGBlock::const_succ_iterator I = block->succ_begin(),
+ E = block->succ_end(); I != E; ++I) {
+ enqueue(*I);
}
- return Uninitialized; // Value is never consumed.
}
-bool TransferFuncs::VisitCallExpr(CallExpr* C) {
- VisitChildren(C);
- return Initialized;
+const CFGBlock *DataflowWorklist::dequeue() {
+ if (worklist.empty())
+ return 0;
+ const CFGBlock *b = worklist.back();
+ worklist.pop_back();
+ enqueuedBlocks[b->getBlockID()] = false;
+ return b;
}
-bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
- switch (U->getOpcode()) {
- case UO_AddrOf: {
- VarDecl* VD = FindBlockVarDecl(U->getSubExpr());
- if (VD && VD->isLocalVarDecl())
- return V(VD,AD) = Initialized;
- break;
- }
+//------------------------------------------------------------------------====//
+// Transfer function for uninitialized values analysis.
+//====------------------------------------------------------------------------//
- default:
- break;
+namespace {
+class FindVarResult {
+ const VarDecl *vd;
+ const DeclRefExpr *dr;
+public:
+ FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
+
+ const DeclRefExpr *getDeclRefExpr() const { return dr; }
+ const VarDecl *getDecl() const { return vd; }
+};
+
+class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
+ CFGBlockValues &vals;
+ const CFG &cfg;
+ AnalysisContext &ac;
+ UninitVariablesHandler *handler;
+ const DeclRefExpr *currentDR;
+ const Expr *currentVoidCast;
+ const bool flagBlockUses;
+public:
+ TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
+ AnalysisContext &ac,
+ UninitVariablesHandler *handler,
+ bool flagBlockUses)
+ : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0),
+ currentVoidCast(0), flagBlockUses(flagBlockUses) {}
+
+ const CFG &getCFG() { return cfg; }
+ void reportUninit(const DeclRefExpr *ex, const VarDecl *vd,
+ bool isAlwaysUninit);
+
+ void VisitBlockExpr(BlockExpr *be);
+ void VisitDeclStmt(DeclStmt *ds);
+ void VisitDeclRefExpr(DeclRefExpr *dr);
+ void VisitUnaryOperator(UnaryOperator *uo);
+ void VisitBinaryOperator(BinaryOperator *bo);
+ void VisitCastExpr(CastExpr *ce);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E);
+ void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
+
+ bool isTrackedVar(const VarDecl *vd) {
+ return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
}
-
- return Visit(U->getSubExpr());
+
+ FindVarResult findBlockVarDecl(Expr *ex);
+};
}
-bool
-TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
- // This represents a use of the 'collection'
- bool x = Visit(S->getCollection());
+void TransferFunctions::reportUninit(const DeclRefExpr *ex,
+ const VarDecl *vd, bool isAlwaysUnit) {
+ if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit);
+}
- if (x == Uninitialized)
- return Uninitialized;
+FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) {
+ if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
+ if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
+ if (isTrackedVar(vd))
+ return FindVarResult(vd, dr);
+ return FindVarResult(0, 0);
+}
+void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
+ ObjCForCollectionStmt *fs) {
+
+ Visit(fs->getCollection());
+
// This represents an initialization of the 'element' value.
- Stmt* Element = S->getElement();
- VarDecl* VD = 0;
-
- if (DeclStmt* DS = dyn_cast<DeclStmt>(Element))
- VD = cast<VarDecl>(DS->getSingleDecl());
+ Stmt *element = fs->getElement();
+ const VarDecl* vd = 0;
+
+ if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) {
+ vd = cast<VarDecl>(ds->getSingleDecl());
+ if (!isTrackedVar(vd))
+ vd = 0;
+ }
else {
- Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens();
-
// Initialize the value of the reference variable.
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(ElemExpr))
- VD = cast<VarDecl>(DR->getDecl());
- else
- return Visit(ElemExpr);
+ const FindVarResult &res = findBlockVarDecl(cast<Expr>(element));
+ vd = res.getDecl();
+ if (!vd) {
+ Visit(element);
+ return;
+ }
}
-
- V(VD,AD) = Initialized;
- return Initialized;
+
+ if (vd)
+ vals[vd] = Initialized;
}
-
-bool TransferFuncs::
-VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
- Visit(C->getCond());
-
- bool rhsResult = Visit(C->getFalseExpr());
- // Handle the GNU extension for missing LHS.
- if (isa<ConditionalOperator>(C))
- return Visit(C->getTrueExpr()) & rhsResult; // Yes: we want &, not &&.
- else
- return rhsResult;
+void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
+ if (!flagBlockUses || !handler)
+ return;
+ const BlockDecl *bd = be->getBlockDecl();
+ for (BlockDecl::capture_const_iterator i = bd->capture_begin(),
+ e = bd->capture_end() ; i != e; ++i) {
+ const VarDecl *vd = i->getVariable();
+ if (!vd->hasLocalStorage())
+ continue;
+ if (!isTrackedVar(vd))
+ continue;
+ if (i->isByRef()) {
+ vals[vd] = Initialized;
+ continue;
+ }
+ Value v = vals[vd];
+ if (isUninitialized(v))
+ handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v));
+ }
}
-bool TransferFuncs::VisitStmt(Stmt* S) {
- bool x = Initialized;
-
- // We don't stop at the first subexpression that is Uninitialized because
- // evaluating some subexpressions may result in propogating "Uninitialized"
- // or "Initialized" to variables referenced in the other subexpressions.
- for (Stmt::child_range I = S->children(); I; ++I)
- if (*I && Visit(*I) == Uninitialized) x = Uninitialized;
-
- return x;
+void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
+ for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
+ DI != DE; ++DI) {
+ if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
+ if (isTrackedVar(vd)) {
+ if (Expr *init = vd->getInit()) {
+ Visit(init);
+
+ // If the initializer consists solely of a reference to itself, we
+ // explicitly mark the variable as uninitialized. This allows code
+ // like the following:
+ //
+ // int x = x;
+ //
+ // to deliberately leave a variable uninitialized. Different analysis
+ // clients can detect this pattern and adjust their reporting
+ // appropriately, but we need to continue to analyze subsequent uses
+ // of the variable.
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(init->IgnoreParenImpCasts());
+ vals[vd] = (DRE && DRE->getDecl() == vd) ? Uninitialized
+ : Initialized;
+ }
+ } else if (Stmt *init = vd->getInit()) {
+ Visit(init);
+ }
+ }
+ }
}
-bool TransferFuncs::Visit(Stmt *S) {
- if (AD.isTracked(static_cast<Expr*>(S))) return V(static_cast<Expr*>(S),AD);
- else return static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(S);
+void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
+ // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ // If a DeclRefExpr is not involved in a load, we are essentially computing
+ // its address, either for assignment to a reference or via the '&' operator.
+ // In such cases, treat the variable as being initialized, since this
+ // analysis isn't powerful enough to do alias tracking.
+ if (dr != currentDR)
+ if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
+ if (isTrackedVar(vd))
+ vals[vd] = Initialized;
}
-bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
- bool x = static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E);
- if (AD.isTracked(E)) V(E,AD) = x;
- return x;
+void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
+ if (bo->isAssignmentOp()) {
+ const FindVarResult &res = findBlockVarDecl(bo->getLHS());
+ if (const VarDecl* vd = res.getDecl()) {
+ // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
+ res.getDeclRefExpr());
+ Visit(bo->getRHS());
+ Visit(bo->getLHS());
+
+ ValueVector::reference val = vals[vd];
+ if (isUninitialized(val)) {
+ if (bo->getOpcode() != BO_Assign)
+ reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
+ val = Initialized;
+ }
+ return;
+ }
+ }
+ Visit(bo->getRHS());
+ Visit(bo->getLHS());
}
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Merge operator.
-//
-// In our transfer functions we take the approach that any
-// combination of uninitialized values, e.g.
-// Uninitialized + ___ = Uninitialized.
-//
-// Merges take the same approach, preferring soundness. At a confluence point,
-// if any predecessor has a variable marked uninitialized, the value is
-// uninitialized at the confluence point.
-//===----------------------------------------------------------------------===//
-
-namespace {
- typedef StmtDeclBitVector_Types::Union Merge;
- typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
+void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
+ switch (uo->getOpcode()) {
+ case clang::UO_PostDec:
+ case clang::UO_PostInc:
+ case clang::UO_PreDec:
+ case clang::UO_PreInc: {
+ const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
+ if (const VarDecl *vd = res.getDecl()) {
+ // We assume that DeclRefExprs wrapped in a unary operator ++/--
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
+ res.getDeclRefExpr());
+ Visit(uo->getSubExpr());
+
+ ValueVector::reference val = vals[vd];
+ if (isUninitialized(val)) {
+ reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
+ // Don't cascade warnings.
+ val = Initialized;
+ }
+ return;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ Visit(uo->getSubExpr());
}
-//===----------------------------------------------------------------------===//
-// Uninitialized values checker. Scan an AST and flag variable uses
-//===----------------------------------------------------------------------===//
-
-UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
-
-namespace {
-class UninitializedValuesChecker
- : public UninitializedValues::ObserverTy {
+void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
+ if (ce->getCastKind() == CK_LValueToRValue) {
+ const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
+ if (const VarDecl *vd = res.getDecl()) {
+ // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
+ // cannot be block-level expressions. Therefore, we determine if
+ // a DeclRefExpr is involved in a "load" by comparing it to the current
+ // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
+ // Here we update 'currentDR' to be the one associated with this
+ // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we
+ // will know that we are not computing its lvalue for other purposes
+ // than to perform a load.
+ SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
+ res.getDeclRefExpr());
+ Visit(ce->getSubExpr());
+ if (currentVoidCast != ce) {
+ Value val = vals[vd];
+ if (isUninitialized(val)) {
+ reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
+ // Don't cascade warnings.
+ vals[vd] = Initialized;
+ }
+ }
+ return;
+ }
+ }
+ else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) {
+ if (cse->getType()->isVoidType()) {
+ // e.g. (void) x;
+ SaveAndRestore<const Expr *>
+ lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens());
+ Visit(cse->getSubExpr());
+ return;
+ }
+ }
+ Visit(ce->getSubExpr());
+}
- ASTContext &Ctx;
- Diagnostic &Diags;
- llvm::SmallPtrSet<VarDecl*,10> AlreadyWarned;
+void TransferFunctions::VisitUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *se) {
+ if (se->getKind() == UETT_SizeOf) {
+ if (se->getType()->isConstantSizeType())
+ return;
+ // Handle VLAs.
+ Visit(se->getArgumentExpr());
+ }
+}
-public:
- UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
- : Ctx(ctx), Diags(diags) {}
+void TransferFunctions::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+ // typeid(expression) is potentially evaluated when the argument is
+ // a glvalue of polymorphic type. (C++ 5.2.8p2-3)
+ if (!E->isTypeOperand() && E->Classify(ac.getASTContext()).isGLValue()) {
+ QualType SubExprTy = E->getExprOperand()->getType();
+ if (const RecordType *Record = SubExprTy->getAs<RecordType>())
+ if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic())
+ Visit(E->getExprOperand());
+ }
+}
- virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
- UninitializedValues::AnalysisDataTy& AD,
- DeclRefExpr* DR, VarDecl* VD) {
+//------------------------------------------------------------------------====//
+// High-level "driver" logic for uninitialized values analysis.
+//====------------------------------------------------------------------------//
+
+static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
+ AnalysisContext &ac, CFGBlockValues &vals,
+ llvm::BitVector &wasAnalyzed,
+ UninitVariablesHandler *handler = 0,
+ bool flagBlockUses = false) {
+
+ wasAnalyzed[block->getBlockID()] = true;
+
+ if (const BinaryOperator *b = getLogicalOperatorInChain(block)) {
+ CFGBlock::const_pred_iterator itr = block->pred_begin();
+ BVPair vA = vals.getValueVectors(*itr, false);
+ ++itr;
+ BVPair vB = vals.getValueVectors(*itr, false);
+
+ BVPair valsAB;
+
+ if (b->getOpcode() == BO_LAnd) {
+ // Merge the 'F' bits from the first and second.
+ vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true);
+ vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false);
+ valsAB.first = vA.first;
+ valsAB.second = &vals.getScratch();
+ }
+ else {
+ // Merge the 'T' bits from the first and second.
+ assert(b->getOpcode() == BO_LOr);
+ vals.mergeIntoScratch(*vA.first, true);
+ vals.mergeIntoScratch(*vB.first, false);
+ valsAB.first = &vals.getScratch();
+ valsAB.second = vA.second ? vA.second : vA.first;
+ }
+ return vals.updateValueVectors(block, valsAB);
+ }
- assert ( AD.isTracked(VD) && "Unknown VarDecl.");
+ // Default behavior: merge in values of predecessor blocks.
+ vals.resetScratch();
+ bool isFirst = true;
+ for (CFGBlock::const_pred_iterator I = block->pred_begin(),
+ E = block->pred_end(); I != E; ++I) {
+ vals.mergeIntoScratch(vals.getValueVector(*I, block), isFirst);
+ isFirst = false;
+ }
+ // Apply the transfer function.
+ TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses);
+ for (CFGBlock::const_iterator I = block->begin(), E = block->end();
+ I != E; ++I) {
+ if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
+ tf.BlockStmt_Visit(cs->getStmt());
+ }
+ }
+ return vals.updateValueVectorWithScratch(block);
+}
- if (V(VD,AD) == Uninitialized)
- if (AlreadyWarned.insert(VD))
- Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
- diag::warn_uninit_val);
+void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
+ const CFG &cfg,
+ AnalysisContext &ac,
+ UninitVariablesHandler &handler) {
+ CFGBlockValues vals(cfg);
+ vals.computeSetOfDeclarations(dc);
+ if (vals.hasNoDeclarations())
+ return;
+
+ // Mark all variables uninitialized at the entry.
+ const CFGBlock &entry = cfg.getEntry();
+ for (CFGBlock::const_succ_iterator i = entry.succ_begin(),
+ e = entry.succ_end(); i != e; ++i) {
+ if (const CFGBlock *succ = *i) {
+ ValueVector &vec = vals.getValueVector(&entry, succ);
+ const unsigned n = vals.getNumEntries();
+ for (unsigned j = 0; j < n ; ++j) {
+ vec[j] = Uninitialized;
+ }
+ }
}
-};
-} // end anonymous namespace
-namespace clang {
-void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags,
- bool FullUninitTaint) {
+ // Proceed with the workist.
+ DataflowWorklist worklist(cfg);
+ llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
+ worklist.enqueueSuccessors(&cfg.getEntry());
+ llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
+
+ while (const CFGBlock *block = worklist.dequeue()) {
+ // Did the block change?
+ bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);
+ if (changed || !previouslyVisited[block->getBlockID()])
+ worklist.enqueueSuccessors(block);
+ previouslyVisited[block->getBlockID()] = true;
+ }
+
+ // Run through the blocks one more time, and report uninitialized variabes.
+ for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
+ if (wasAnalyzed[(*BI)->getBlockID()])
+ runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler,
+ /* flagBlockUses */ true);
+ }
+}
- // Compute the uninitialized values information.
- UninitializedValues U(cfg);
- U.getAnalysisData().FullUninitTaint = FullUninitTaint;
- Solver S(U);
- S.runOnCFG(cfg);
+UninitVariablesHandler::~UninitVariablesHandler() {}
- // Scan for DeclRefExprs that use uninitialized values.
- UninitializedValuesChecker Observer(Ctx,Diags);
- U.getAnalysisData().Observer = &Observer;
- S.runOnAllBlocks(cfg);
-}
-} // end namespace clang
diff --git a/lib/Analysis/UninitializedValuesV2.cpp b/lib/Analysis/UninitializedValuesV2.cpp
deleted file mode 100644
index 75eccbf7a3c8..000000000000
--- a/lib/Analysis/UninitializedValuesV2.cpp
+++ /dev/null
@@ -1,610 +0,0 @@
-//==- UninitializedValuesV2.cpp - Find Uninitialized 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 implements uninitialized values analysis for source-level CFGs.
-//
-//===----------------------------------------------------------------------===//
-
-#include <utility>
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-#include "clang/AST/Decl.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Analysis/Analyses/UninitializedValuesV2.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
-
-using namespace clang;
-
-static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
- return vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
- vd->getType()->isScalarType() &&
- vd->getDeclContext() == dc;
-}
-
-//------------------------------------------------------------------------====//
-// DeclToBit: a mapping from Decls we track to bitvector indices.
-//====------------------------------------------------------------------------//
-
-namespace {
-class DeclToBit {
- llvm::DenseMap<const VarDecl *, unsigned> map;
-public:
- DeclToBit() {}
-
- /// Compute the actual mapping from declarations to bits.
- void computeMap(const DeclContext &dc);
-
- /// Return the number of declarations in the map.
- unsigned size() const { return map.size(); }
-
- /// Returns the bit vector index for a given declaration.
- llvm::Optional<unsigned> getBitVectorIndex(const VarDecl *d);
-};
-}
-
-void DeclToBit::computeMap(const DeclContext &dc) {
- unsigned count = 0;
- DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
- E(dc.decls_end());
- for ( ; I != E; ++I) {
- const VarDecl *vd = *I;
- if (isTrackedVar(vd, &dc))
- map[vd] = count++;
- }
-}
-
-llvm::Optional<unsigned> DeclToBit::getBitVectorIndex(const VarDecl *d) {
- llvm::DenseMap<const VarDecl *, unsigned>::iterator I = map.find(d);
- if (I == map.end())
- return llvm::Optional<unsigned>();
- return I->second;
-}
-
-//------------------------------------------------------------------------====//
-// CFGBlockValues: dataflow values for CFG blocks.
-//====------------------------------------------------------------------------//
-
-typedef std::pair<llvm::BitVector *, llvm::BitVector *> BVPair;
-
-namespace {
-class CFGBlockValues {
- const CFG &cfg;
- BVPair *vals;
- llvm::BitVector scratch;
- DeclToBit declToBit;
-
- llvm::BitVector &lazyCreate(llvm::BitVector *&bv);
-public:
- CFGBlockValues(const CFG &cfg);
- ~CFGBlockValues();
-
- void computeSetOfDeclarations(const DeclContext &dc);
- llvm::BitVector &getBitVector(const CFGBlock *block,
- const CFGBlock *dstBlock);
-
- BVPair &getBitVectors(const CFGBlock *block, bool shouldLazyCreate);
-
- void mergeIntoScratch(llvm::BitVector const &source, bool isFirst);
- bool updateBitVectorWithScratch(const CFGBlock *block);
- bool updateBitVectors(const CFGBlock *block, const BVPair &newVals);
-
- bool hasNoDeclarations() const {
- return declToBit.size() == 0;
- }
-
- void resetScratch();
- llvm::BitVector &getScratch() { return scratch; }
-
- llvm::BitVector::reference operator[](const VarDecl *vd);
-};
-}
-
-CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
- unsigned n = cfg.getNumBlockIDs();
- if (!n)
- return;
- vals = new std::pair<llvm::BitVector*, llvm::BitVector*>[n];
- memset(vals, 0, sizeof(*vals) * n);
-}
-
-CFGBlockValues::~CFGBlockValues() {
- unsigned n = cfg.getNumBlockIDs();
- if (n == 0)
- return;
- for (unsigned i = 0; i < n; ++i) {
- delete vals[i].first;
- delete vals[i].second;
- }
- delete [] vals;
-}
-
-void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
- declToBit.computeMap(dc);
- scratch.resize(declToBit.size());
-}
-
-llvm::BitVector &CFGBlockValues::lazyCreate(llvm::BitVector *&bv) {
- if (!bv)
- bv = new llvm::BitVector(declToBit.size());
- return *bv;
-}
-
-/// This function pattern matches for a '&&' or '||' that appears at
-/// the beginning of a CFGBlock that also (1) has a terminator and
-/// (2) has no other elements. If such an expression is found, it is returned.
-static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
- if (block->empty())
- return 0;
-
- CFGStmt cstmt = block->front().getAs<CFGStmt>();
- BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt.getStmt());
-
- if (!b || !b->isLogicalOp())
- return 0;
-
- if (block->pred_size() == 2 &&
- ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
- block->size() == 1))
- return b;
-
- return 0;
-}
-
-llvm::BitVector &CFGBlockValues::getBitVector(const CFGBlock *block,
- const CFGBlock *dstBlock) {
- unsigned idx = block->getBlockID();
- if (dstBlock && getLogicalOperatorInChain(block)) {
- if (*block->succ_begin() == dstBlock)
- return lazyCreate(vals[idx].first);
- assert(*(block->succ_begin()+1) == dstBlock);
- return lazyCreate(vals[idx].second);
- }
-
- assert(vals[idx].second == 0);
- return lazyCreate(vals[idx].first);
-}
-
-BVPair &CFGBlockValues::getBitVectors(const clang::CFGBlock *block,
- bool shouldLazyCreate) {
- unsigned idx = block->getBlockID();
- lazyCreate(vals[idx].first);
- if (shouldLazyCreate)
- lazyCreate(vals[idx].second);
- return vals[idx];
-}
-
-void CFGBlockValues::mergeIntoScratch(llvm::BitVector const &source,
- bool isFirst) {
- if (isFirst)
- scratch = source;
- else
- scratch |= source;
-}
-#if 0
-static void printVector(const CFGBlock *block, llvm::BitVector &bv,
- unsigned num) {
-
- llvm::errs() << block->getBlockID() << " :";
- for (unsigned i = 0; i < bv.size(); ++i) {
- llvm::errs() << ' ' << bv[i];
- }
- llvm::errs() << " : " << num << '\n';
-}
-#endif
-
-bool CFGBlockValues::updateBitVectorWithScratch(const CFGBlock *block) {
- llvm::BitVector &dst = getBitVector(block, 0);
- bool changed = (dst != scratch);
- if (changed)
- dst = scratch;
-#if 0
- printVector(block, scratch, 0);
-#endif
- return changed;
-}
-
-bool CFGBlockValues::updateBitVectors(const CFGBlock *block,
- const BVPair &newVals) {
- BVPair &vals = getBitVectors(block, true);
- bool changed = *newVals.first != *vals.first ||
- *newVals.second != *vals.second;
- *vals.first = *newVals.first;
- *vals.second = *newVals.second;
-#if 0
- printVector(block, *vals.first, 1);
- printVector(block, *vals.second, 2);
-#endif
- return changed;
-}
-
-void CFGBlockValues::resetScratch() {
- scratch.reset();
-}
-
-llvm::BitVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
- const llvm::Optional<unsigned> &idx = declToBit.getBitVectorIndex(vd);
- assert(idx.hasValue());
- return scratch[idx.getValue()];
-}
-
-//------------------------------------------------------------------------====//
-// Worklist: worklist for dataflow analysis.
-//====------------------------------------------------------------------------//
-
-namespace {
-class DataflowWorklist {
- llvm::SmallVector<const CFGBlock *, 20> worklist;
- llvm::BitVector enqueuedBlocks;
-public:
- DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
-
- void enqueue(const CFGBlock *block);
- void enqueueSuccessors(const CFGBlock *block);
- const CFGBlock *dequeue();
-
-};
-}
-
-void DataflowWorklist::enqueue(const CFGBlock *block) {
- if (!block)
- return;
- unsigned idx = block->getBlockID();
- if (enqueuedBlocks[idx])
- return;
- worklist.push_back(block);
- enqueuedBlocks[idx] = true;
-}
-
-void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
- for (CFGBlock::const_succ_iterator I = block->succ_begin(),
- E = block->succ_end(); I != E; ++I) {
- enqueue(*I);
- }
-}
-
-const CFGBlock *DataflowWorklist::dequeue() {
- if (worklist.empty())
- return 0;
- const CFGBlock *b = worklist.back();
- worklist.pop_back();
- enqueuedBlocks[b->getBlockID()] = false;
- return b;
-}
-
-//------------------------------------------------------------------------====//
-// Transfer function for uninitialized values analysis.
-//====------------------------------------------------------------------------//
-
-static const bool Initialized = false;
-static const bool Uninitialized = true;
-
-namespace {
-class FindVarResult {
- const VarDecl *vd;
- const DeclRefExpr *dr;
-public:
- FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
-
- const DeclRefExpr *getDeclRefExpr() const { return dr; }
- const VarDecl *getDecl() const { return vd; }
-};
-
-class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
- CFGBlockValues &vals;
- const CFG &cfg;
- AnalysisContext &ac;
- UninitVariablesHandler *handler;
- const DeclRefExpr *currentDR;
- const Expr *currentVoidCast;
- const bool flagBlockUses;
-public:
- TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
- AnalysisContext &ac,
- UninitVariablesHandler *handler,
- bool flagBlockUses)
- : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0),
- currentVoidCast(0), flagBlockUses(flagBlockUses) {}
-
- const CFG &getCFG() { return cfg; }
- void reportUninit(const DeclRefExpr *ex, const VarDecl *vd);
-
- void VisitBlockExpr(BlockExpr *be);
- void VisitDeclStmt(DeclStmt *ds);
- void VisitDeclRefExpr(DeclRefExpr *dr);
- void VisitUnaryOperator(UnaryOperator *uo);
- void VisitBinaryOperator(BinaryOperator *bo);
- void VisitCastExpr(CastExpr *ce);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se);
- void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
-
- bool isTrackedVar(const VarDecl *vd) {
- return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
- }
-
- FindVarResult findBlockVarDecl(Expr *ex);
-};
-}
-
-void TransferFunctions::reportUninit(const DeclRefExpr *ex,
- const VarDecl *vd) {
- if (handler) handler->handleUseOfUninitVariable(ex, vd);
-}
-
-FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) {
- if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
- if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
- if (isTrackedVar(vd))
- return FindVarResult(vd, dr);
- return FindVarResult(0, 0);
-}
-
-void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
- ObjCForCollectionStmt *fs) {
-
- Visit(fs->getCollection());
-
- // This represents an initialization of the 'element' value.
- Stmt *element = fs->getElement();
- const VarDecl* vd = 0;
-
- if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) {
- vd = cast<VarDecl>(ds->getSingleDecl());
- if (!isTrackedVar(vd))
- vd = 0;
- }
- else {
- // Initialize the value of the reference variable.
- const FindVarResult &res = findBlockVarDecl(cast<Expr>(element));
- vd = res.getDecl();
- if (!vd) {
- Visit(element);
- return;
- }
- }
-
- if (vd)
- vals[vd] = Initialized;
-}
-
-void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
- if (!flagBlockUses || !handler)
- return;
- AnalysisContext::referenced_decls_iterator i, e;
- llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl());
- for ( ; i != e; ++i) {
- const VarDecl *vd = *i;
- if (vd->getAttr<BlocksAttr>() || !vd->hasLocalStorage() ||
- !isTrackedVar(vd))
- continue;
- if (vals[vd] == Uninitialized)
- handler->handleUseOfUninitVariable(be, vd);
- }
-}
-
-void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
- for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
- DI != DE; ++DI) {
- if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
- if (isTrackedVar(vd)) {
- vals[vd] = Uninitialized;
- if (Stmt *init = vd->getInit()) {
- Visit(init);
- vals[vd] = Initialized;
- }
- }
- else if (Stmt *init = vd->getInit()) {
- Visit(init);
- }
- }
- }
-}
-
-void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
- // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- // If a DeclRefExpr is not involved in a load, we are essentially computing
- // its address, either for assignment to a reference or via the '&' operator.
- // In such cases, treat the variable as being initialized, since this
- // analysis isn't powerful enough to do alias tracking.
- if (dr != currentDR)
- if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
- if (isTrackedVar(vd))
- vals[vd] = Initialized;
-}
-
-void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
- if (bo->isAssignmentOp()) {
- const FindVarResult &res = findBlockVarDecl(bo->getLHS());
- if (const VarDecl* vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(bo->getRHS());
- Visit(bo->getLHS());
-
- llvm::BitVector::reference bit = vals[vd];
- if (bit == Uninitialized) {
- if (bo->getOpcode() != BO_Assign)
- reportUninit(res.getDeclRefExpr(), vd);
- bit = Initialized;
- }
- return;
- }
- }
- Visit(bo->getRHS());
- Visit(bo->getLHS());
-}
-
-void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
- switch (uo->getOpcode()) {
- case clang::UO_PostDec:
- case clang::UO_PostInc:
- case clang::UO_PreDec:
- case clang::UO_PreInc: {
- const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
- if (const VarDecl *vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in a unary operator ++/--
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(uo->getSubExpr());
-
- llvm::BitVector::reference bit = vals[vd];
- if (bit == Uninitialized) {
- reportUninit(res.getDeclRefExpr(), vd);
- bit = Initialized;
- }
- return;
- }
- break;
- }
- default:
- break;
- }
- Visit(uo->getSubExpr());
-}
-
-void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
- if (ce->getCastKind() == CK_LValueToRValue) {
- const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
- if (const VarDecl *vd = res.getDecl()) {
- // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
- // cannot be block-level expressions. Therefore, we determine if
- // a DeclRefExpr is involved in a "load" by comparing it to the current
- // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
- // Here we update 'currentDR' to be the one associated with this
- // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we
- // will know that we are not computing its lvalue for other purposes
- // than to perform a load.
- SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
- res.getDeclRefExpr());
- Visit(ce->getSubExpr());
- if (currentVoidCast != ce && vals[vd] == Uninitialized) {
- reportUninit(res.getDeclRefExpr(), vd);
- // Don't cascade warnings.
- vals[vd] = Initialized;
- }
- return;
- }
- }
- else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) {
- if (cse->getType()->isVoidType()) {
- // e.g. (void) x;
- SaveAndRestore<const Expr *>
- lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens());
- Visit(cse->getSubExpr());
- return;
- }
- }
- Visit(ce->getSubExpr());
-}
-
-void TransferFunctions::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se) {
- if (se->isSizeOf()) {
- if (se->getType()->isConstantSizeType())
- return;
- // Handle VLAs.
- Visit(se->getArgumentExpr());
- }
-}
-
-//------------------------------------------------------------------------====//
-// High-level "driver" logic for uninitialized values analysis.
-//====------------------------------------------------------------------------//
-
-static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
- AnalysisContext &ac, CFGBlockValues &vals,
- UninitVariablesHandler *handler = 0,
- bool flagBlockUses = false) {
-
- if (const BinaryOperator *b = getLogicalOperatorInChain(block)) {
- CFGBlock::const_pred_iterator itr = block->pred_begin();
- BVPair vA = vals.getBitVectors(*itr, false);
- ++itr;
- BVPair vB = vals.getBitVectors(*itr, false);
-
- BVPair valsAB;
-
- if (b->getOpcode() == BO_LAnd) {
- // Merge the 'F' bits from the first and second.
- vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true);
- vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false);
- valsAB.first = vA.first;
- valsAB.second = &vals.getScratch();
- }
- else {
- // Merge the 'T' bits from the first and second.
- assert(b->getOpcode() == BO_LOr);
- vals.mergeIntoScratch(*vA.first, true);
- vals.mergeIntoScratch(*vB.first, false);
- valsAB.first = &vals.getScratch();
- valsAB.second = vA.second ? vA.second : vA.first;
- }
- return vals.updateBitVectors(block, valsAB);
- }
-
- // Default behavior: merge in values of predecessor blocks.
- vals.resetScratch();
- bool isFirst = true;
- for (CFGBlock::const_pred_iterator I = block->pred_begin(),
- E = block->pred_end(); I != E; ++I) {
- vals.mergeIntoScratch(vals.getBitVector(*I, block), isFirst);
- isFirst = false;
- }
- // Apply the transfer function.
- TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses);
- for (CFGBlock::const_iterator I = block->begin(), E = block->end();
- I != E; ++I) {
- if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
- tf.BlockStmt_Visit(cs->getStmt());
- }
- }
- return vals.updateBitVectorWithScratch(block);
-}
-
-void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
- const CFG &cfg,
- AnalysisContext &ac,
- UninitVariablesHandler &handler) {
- CFGBlockValues vals(cfg);
- vals.computeSetOfDeclarations(dc);
- if (vals.hasNoDeclarations())
- return;
- DataflowWorklist worklist(cfg);
- llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
-
- worklist.enqueueSuccessors(&cfg.getEntry());
-
- while (const CFGBlock *block = worklist.dequeue()) {
- // Did the block change?
- bool changed = runOnBlock(block, cfg, ac, vals);
- if (changed || !previouslyVisited[block->getBlockID()])
- worklist.enqueueSuccessors(block);
- previouslyVisited[block->getBlockID()] = true;
- }
-
- // Run through the blocks one more time, and report uninitialized variabes.
- for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
- runOnBlock(*BI, cfg, ac, vals, &handler, /* flagBlockUses */ true);
- }
-}
-
-UninitVariablesHandler::~UninitVariablesHandler() {}
-
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 91e7deb078ad..c1e7cf6bf971 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangBasic
Targets.cpp
TokenKinds.cpp
Version.cpp
+ VersionTuple.cpp
)
# Determine Subversion revision.
@@ -39,5 +40,6 @@ add_dependencies(clangBasic
ClangDiagnosticGroups
ClangDiagnosticLex
ClangDiagnosticParse
- ClangDiagnosticSema)
+ ClangDiagnosticSema
+ ClangDiagnosticIndexName)
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 31e33315cce2..e8cd21885d22 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -16,6 +16,8 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+
using namespace clang;
static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
@@ -49,11 +51,6 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
- // Create a DiagState and DiagStatePoint representing diagnostic changes
- // through command-line.
- DiagStates.push_back(DiagState());
- PushDiagStatePoint(&DiagStates.back(), SourceLocation());
-
Reset();
}
@@ -100,6 +97,16 @@ void Diagnostic::Reset() {
// displayed.
LastDiagLevel = (DiagnosticIDs::Level)-1;
DelayedDiagID = 0;
+
+ // Clear state related to #pragma diagnostic.
+ DiagStates.clear();
+ DiagStatePoints.clear();
+ DiagStateOnPushStack.clear();
+
+ // Create a DiagState and DiagStatePoint representing diagnostic changes
+ // through command-line.
+ DiagStates.push_back(DiagState());
+ PushDiagStatePoint(&DiagStates.back(), SourceLocation());
}
void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
@@ -168,7 +175,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
// after the previous one.
if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
- // A diagnostic pragma occured, create a new DiagState initialized with
+ // A diagnostic pragma occurred, create a new DiagState initialized with
// the current one and a new DiagStatePoint to record at which location
// the new state became active.
DiagStates.push_back(*GetCurDiagState());
@@ -683,5 +690,7 @@ PartialDiagnostic::StorageAllocator::StorageAllocator() {
}
PartialDiagnostic::StorageAllocator::~StorageAllocator() {
- assert(NumFreeListEntries == NumCached && "A partial is on the lamb");
+ // Don't assert if we are in a CrashRecovery context, as this
+ // invariant may be invalidated during a crash.
+ assert((NumFreeListEntries == NumCached || llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lamb");
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 553e4c929454..b4dd575a9684 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -46,19 +46,41 @@ struct StaticDiagInfoRec {
unsigned AccessControl : 1;
unsigned Category : 5;
+ const char *Name;
+
const char *Description;
const char *OptionGroup;
+ const char *BriefExplanation;
+ const char *FullExplanation;
+
bool operator<(const StaticDiagInfoRec &RHS) const {
return DiagID < RHS.DiagID;
}
};
+struct StaticDiagNameIndexRec {
+ const char *Name;
+ unsigned short DiagID;
+
+ bool operator<(const StaticDiagNameIndexRec &RHS) const {
+ assert(Name && RHS.Name && "Null Diagnostic Name");
+ return strcmp(Name, RHS.Name) == -1;
+ }
+
+ bool operator==(const StaticDiagNameIndexRec &RHS) const {
+ assert(Name && RHS.Name && "Null Diagnostic Name");
+ return strcmp(Name, RHS.Name) == 0;
+ }
+};
+
}
static const StaticDiagInfoRec StaticDiagInfo[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP },
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, \
+ ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -67,20 +89,32 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
- { 0, 0, 0, 0, 0, 0, 0, 0}
-};
#undef DIAG
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static const unsigned StaticDiagInfoSize =
+ sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
+
+/// To be sorted before first use (since it's splitted among multiple files)
+static StaticDiagNameIndexRec StaticDiagNameIndex[] = {
+#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM },
+#include "clang/Basic/DiagnosticIndexName.inc"
+#undef DIAG_NAME_INDEX
+ { 0, 0 }
+};
+
+static const unsigned StaticDiagNameIndexSize =
+ sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
/// or null if the ID is invalid.
static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
- unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
-
// If assertions are enabled, verify that the StaticDiagInfo array is sorted.
#ifndef NDEBUG
static bool IsFirst = true;
if (IsFirst) {
- for (unsigned i = 1; i != NumDiagEntries; ++i) {
+ for (unsigned i = 1; i != StaticDiagInfoSize; ++i) {
assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID &&
"Diag ID conflict, the enums at the start of clang::diag (in "
"DiagnosticIDs.h) probably need to be increased");
@@ -93,11 +127,11 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
#endif
// Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 };
+ StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const StaticDiagInfoRec *Found =
- std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find);
- if (Found == StaticDiagInfo + NumDiagEntries ||
+ std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
+ if (Found == StaticDiagInfo + StaticDiagInfoSize ||
Found->DiagID != DiagID)
return 0;
@@ -119,7 +153,7 @@ const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
return 0;
}
-/// getWarningOptionForDiag - Return the category number that a specified
+/// getCategoryNumberForDiag - Return the category number that a specified
/// DiagID belongs to, or 0 if no category.
unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
@@ -167,7 +201,48 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
return SFINAE_Report;
}
-/// getDiagClass - Return the class field of the diagnostic.
+/// getName - Given a diagnostic ID, return its name
+const char *DiagnosticIDs::getName(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->Name;
+ return 0;
+}
+
+/// getIdFromName - Given a diagnostic name, return its ID, or 0
+unsigned DiagnosticIDs::getIdFromName(char const *Name) {
+ StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
+ StaticDiagNameIndex + StaticDiagNameIndexSize;
+
+ if (Name == 0) { return diag::DIAG_UPPER_LIMIT; }
+
+ StaticDiagNameIndexRec Find = { Name, 0 };
+
+ const StaticDiagNameIndexRec *Found =
+ std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
+ if (Found == StaticDiagNameIndexEnd ||
+ strcmp(Found->Name, Name) != 0)
+ return diag::DIAG_UPPER_LIMIT;
+
+ return Found->DiagID;
+}
+
+/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
+/// of the issue
+const char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->BriefExplanation;
+ return 0;
+}
+
+/// getFullExplanation - Given a diagnostic ID, return a full explanation
+/// of the issue
+const char *DiagnosticIDs::getFullExplanation(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Info->FullExplanation;
+ return 0;
+}
+
+/// getBuiltinDiagClass - Return the class field of the diagnostic.
///
static unsigned getBuiltinDiagClass(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
@@ -329,6 +404,8 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
if (mapping)
*mapping = (diag::Mapping) (MappingInfo & 7);
+ bool ShouldEmitInSystemHeader = false;
+
switch (MappingInfo & 7) {
default: assert(0 && "Unknown mapping!");
case diag::MAP_IGNORE:
@@ -351,6 +428,9 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
case diag::MAP_FATAL:
Result = DiagnosticIDs::Fatal;
break;
+ case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER:
+ ShouldEmitInSystemHeader = true;
+ // continue as MAP_WARNING.
case diag::MAP_WARNING:
// If warnings are globally mapped to ignore or error, do it.
if (Diag.IgnoreAllWarnings)
@@ -395,6 +475,20 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID))
return DiagnosticIDs::Ignored;
+ // If we are in a system header, we ignore it.
+ // We also want to ignore extensions and warnings in -Werror and
+ // -pedantic-errors modes, which *map* warnings/extensions to errors.
+ if (Result >= DiagnosticIDs::Warning &&
+ DiagClass != CLASS_ERROR &&
+ // Custom diagnostics always are emitted in system headers.
+ DiagID < diag::DIAG_UPPER_LIMIT &&
+ !ShouldEmitInSystemHeader &&
+ Diag.SuppressSystemWarnings &&
+ Loc.isValid() &&
+ Diag.getSourceManager().isInSystemHeader(
+ Diag.getSourceManager().getInstantiationLoc(Loc)))
+ return DiagnosticIDs::Ignored;
+
return Result;
}
@@ -480,16 +574,9 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
DiagnosticIDs::Level DiagLevel;
unsigned DiagID = Info.getID();
- // ShouldEmitInSystemHeader - True if this diagnostic should be produced even
- // in a system header.
- bool ShouldEmitInSystemHeader;
-
if (DiagID >= diag::DIAG_UPPER_LIMIT) {
// Handle custom diagnostics, which cannot be mapped.
DiagLevel = CustomDiagInfo->getLevel(DiagID);
-
- // Custom diagnostics always are emitted in system headers.
- ShouldEmitInSystemHeader = true;
} else {
// Get the class of the diagnostic. If this is a NOTE, map it onto whatever
// the diagnostic level was for the previous diagnostic so that it is
@@ -497,14 +584,7 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
unsigned DiagClass = getBuiltinDiagClass(DiagID);
if (DiagClass == CLASS_NOTE) {
DiagLevel = DiagnosticIDs::Note;
- ShouldEmitInSystemHeader = false; // extra consideration is needed
} else {
- // If this is not an error and we are in a system header, we ignore it.
- // Check the original Diag ID here, because we also want to ignore
- // extensions and warnings in -Werror and -pedantic-errors modes, which
- // *map* warnings/extensions to errors.
- ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR;
-
DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
Diag);
}
@@ -540,18 +620,6 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const {
Diag.LastDiagLevel == DiagnosticIDs::Ignored))
return false;
- // If this diagnostic is in a system header and is not a clang error, suppress
- // it.
- if (Diag.SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
- Info.getLocation().isValid() &&
- Diag.getSourceManager().isInSystemHeader(
- Diag.getSourceManager().getInstantiationLoc(Info.getLocation())) &&
- (DiagLevel != DiagnosticIDs::Note ||
- Diag.LastDiagLevel == DiagnosticIDs::Ignored)) {
- Diag.LastDiagLevel = DiagnosticIDs::Ignored;
- return false;
- }
-
if (DiagLevel >= DiagnosticIDs::Error) {
if (Diag.Client->IncludeInDiagnosticCounts()) {
Diag.ErrorOccurred = true;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 342413d7da52..4e5a129082f4 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -313,7 +313,7 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
/// getFile - Lookup, cache, and verify the specified file (real or
/// virtual). This returns NULL if the file doesn't exist.
///
-const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
+const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) {
++NumFileLookups;
// See if there is already an entry in the map.
@@ -354,6 +354,11 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
return 0;
}
+ if (FileDescriptor != -1 && !openFile) {
+ close(FileDescriptor);
+ FileDescriptor = -1;
+ }
+
// It exists. See if we have already opened a file with the same inode.
// This occurs when one dir is symlinked to another, for example.
FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf);
@@ -450,13 +455,15 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
return UFE;
}
-void FileManager::FixupRelativePath(llvm::sys::Path &path,
- const FileSystemOptions &FSOpts) {
- if (FSOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(path.str()))
+void FileManager::FixupRelativePath(llvm::SmallVectorImpl<char> &path) const {
+ llvm::StringRef pathRef(path.data(), path.size());
+
+ if (FileSystemOpts.WorkingDir.empty()
+ || llvm::sys::path::is_absolute(pathRef))
return;
- llvm::SmallString<128> NewPath(FSOpts.WorkingDir);
- llvm::sys::path::append(NewPath, path.str());
+ llvm::SmallString<128> NewPath(FileSystemOpts.WorkingDir);
+ llvm::sys::path::append(NewPath, pathRef);
path = NewPath;
}
@@ -464,30 +471,32 @@ llvm::MemoryBuffer *FileManager::
getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
llvm::OwningPtr<llvm::MemoryBuffer> Result;
llvm::error_code ec;
- if (FileSystemOpts.WorkingDir.empty()) {
- const char *Filename = Entry->getName();
- // If the file is already open, use the open file descriptor.
- if (Entry->FD != -1) {
- ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result,
- Entry->getSize());
- if (ErrorStr)
- *ErrorStr = ec.message();
-
- close(Entry->FD);
- Entry->FD = -1;
- return Result.take();
- }
- // Otherwise, open the file.
+ const char *Filename = Entry->getName();
+ // If the file is already open, use the open file descriptor.
+ if (Entry->FD != -1) {
+ ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result,
+ Entry->getSize());
+ if (ErrorStr)
+ *ErrorStr = ec.message();
+
+ close(Entry->FD);
+ Entry->FD = -1;
+ return Result.take();
+ }
+
+ // Otherwise, open the file.
+
+ if (FileSystemOpts.WorkingDir.empty()) {
ec = llvm::MemoryBuffer::getFile(Filename, Result, Entry->getSize());
if (ec && ErrorStr)
*ErrorStr = ec.message();
return Result.take();
}
-
- llvm::sys::Path FilePath(Entry->getName());
- FixupRelativePath(FilePath, FileSystemOpts);
- ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result, Entry->getSize());
+
+ llvm::SmallString<128> FilePath(Entry->getName());
+ FixupRelativePath(FilePath);
+ ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, Entry->getSize());
if (ec && ErrorStr)
*ErrorStr = ec.message();
return Result.take();
@@ -504,8 +513,8 @@ getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) {
return Result.take();
}
- llvm::sys::Path FilePath(Filename);
- FixupRelativePath(FilePath, FileSystemOpts);
+ llvm::SmallString<128> FilePath(Filename);
+ FixupRelativePath(FilePath);
ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result);
if (ec && ErrorStr)
*ErrorStr = ec.message();
@@ -525,13 +534,21 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
StatCache.get());
- llvm::sys::Path FilePath(Path);
- FixupRelativePath(FilePath, FileSystemOpts);
+ llvm::SmallString<128> FilePath(Path);
+ FixupRelativePath(FilePath);
return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
StatCache.get());
}
+bool FileManager::getNoncachedStatValue(llvm::StringRef Path,
+ struct stat &StatBuf) {
+ llvm::SmallString<128> FilePath(Path);
+ FixupRelativePath(FilePath);
+
+ return ::stat(FilePath.c_str(), &StatBuf) != 0;
+}
+
void FileManager::GetUniqueIDMapping(
llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
UIDToFiles.clear();
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index ef11d658ed9e..cb1f55b75773 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -81,17 +81,18 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
// Constants for TokenKinds.def
namespace {
enum {
- KEYALL = 1,
- KEYC99 = 2,
- KEYCXX = 4,
- KEYCXX0X = 8,
- KEYGNU = 16,
- KEYMS = 32,
- BOOLSUPPORT = 64,
- KEYALTIVEC = 128,
- KEYNOCXX = 256,
- KEYBORLAND = 512,
- KEYOPENCL = 1024
+ KEYC99 = 0x1,
+ KEYCXX = 0x2,
+ KEYCXX0X = 0x4,
+ KEYGNU = 0x8,
+ KEYMS = 0x10,
+ BOOLSUPPORT = 0x20,
+ KEYALTIVEC = 0x40,
+ KEYNOCXX = 0x80,
+ KEYBORLAND = 0x100,
+ KEYOPENCL = 0x200,
+ KEYC1X = 0x400,
+ KEYALL = 0x7ff
};
}
@@ -107,7 +108,7 @@ static void AddKeyword(llvm::StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
const LangOptions &LangOpts, IdentifierTable &Table) {
unsigned AddResult = 0;
- if (Flags & KEYALL) AddResult = 2;
+ if (Flags == KEYALL) AddResult = 2;
else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
@@ -118,6 +119,7 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
+ else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
@@ -162,7 +164,12 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
#define OBJC2_AT_KEYWORD(NAME) \
if (LangOpts.ObjC2) \
AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this);
+#define TESTING_KEYWORD(NAME, FLAGS)
#include "clang/Basic/TokenKinds.def"
+
+ if (LangOpts.ParseUnknownAnytype)
+ AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL,
+ LangOpts, *this);
}
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
@@ -364,6 +371,56 @@ std::string Selector::getAsString() const {
return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName();
}
+/// Interpreting the given string using the normal CamelCase
+/// conventions, determine whether the given string starts with the
+/// given "word", which is assumed to end in a lowercase letter.
+static bool startsWithWord(llvm::StringRef name, llvm::StringRef word) {
+ if (name.size() < word.size()) return false;
+ return ((name.size() == word.size() ||
+ !islower(name[word.size()]))
+ && name.startswith(word));
+}
+
+ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
+ IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
+ if (!first) return OMF_None;
+
+ llvm::StringRef name = first->getName();
+ if (sel.isUnarySelector()) {
+ if (name == "autorelease") return OMF_autorelease;
+ if (name == "dealloc") return OMF_dealloc;
+ if (name == "release") return OMF_release;
+ if (name == "retain") return OMF_retain;
+ if (name == "retainCount") return OMF_retainCount;
+ }
+
+ // The other method families may begin with a prefix of underscores.
+ while (!name.empty() && name.front() == '_')
+ name = name.substr(1);
+
+ if (name.empty()) return OMF_None;
+ switch (name.front()) {
+ case 'a':
+ if (startsWithWord(name, "alloc")) return OMF_alloc;
+ break;
+ case 'c':
+ if (startsWithWord(name, "copy")) return OMF_copy;
+ break;
+ case 'i':
+ if (startsWithWord(name, "init")) return OMF_init;
+ break;
+ case 'm':
+ if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
+ break;
+ case 'n':
+ if (startsWithWord(name, "new")) return OMF_new;
+ break;
+ default:
+ break;
+ }
+
+ return OMF_None;
+}
namespace {
struct SelectorTableImpl {
@@ -376,6 +433,10 @@ static SelectorTableImpl &getSelectorTableImpl(void *P) {
return *static_cast<SelectorTableImpl*>(P);
}
+size_t SelectorTable::getTotalMemory() const {
+ SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
+ return SelTabImpl.Allocator.getTotalMemory();
+}
Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
if (nKeys < 2)
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index e2783ba6fda2..c3e03933e5e5 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -46,13 +46,26 @@ unsigned ContentCache::getSizeBytesMapped() const {
return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0;
}
+/// Returns the kind of memory used to back the memory buffer for
+/// this content cache. This is used for performance analysis.
+llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const {
+ assert(Buffer.getPointer());
+
+ // Should be unreachable, but keep for sanity.
+ if (!Buffer.getPointer())
+ return llvm::MemoryBuffer::MemoryBuffer_Malloc;
+
+ const llvm::MemoryBuffer *buf = Buffer.getPointer();
+ return buf->getBufferKind();
+}
+
/// getSize - Returns the size of the content encapsulated by this ContentCache.
/// This can be the size of the source file or the size of an arbitrary
/// scratch buffer. If the ContentCache encapsulates a source file, that
/// file is not lazily brought in from disk to satisfy this query.
unsigned ContentCache::getSize() const {
return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize()
- : (unsigned) Entry->getSize();
+ : (unsigned) ContentsEntry->getSize();
}
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
@@ -70,8 +83,8 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
SourceLocation Loc,
bool *Invalid) const {
// Lazily create the Buffer for ContentCaches that wrap files. If we already
- // computed it, jsut return what we have.
- if (Buffer.getPointer() || Entry == 0) {
+ // computed it, just return what we have.
+ if (Buffer.getPointer() || ContentsEntry == 0) {
if (Invalid)
*Invalid = isBufferInvalid();
@@ -79,7 +92,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
}
std::string ErrorStr;
- Buffer.setPointer(SM.getFileManager().getBufferForFile(Entry, &ErrorStr));
+ Buffer.setPointer(SM.getFileManager().getBufferForFile(ContentsEntry, &ErrorStr));
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
@@ -93,18 +106,18 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// possible.
if (!Buffer.getPointer()) {
const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n");
- Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(),
+ Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(),
"<invalid>"));
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
- for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
+ for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
if (Diag.isDiagnosticInFlight())
Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
- Entry->getName(), ErrorStr);
+ ContentsEntry->getName(), ErrorStr);
else
Diag.Report(Loc, diag::err_cannot_open_file)
- << Entry->getName() << ErrorStr;
+ << ContentsEntry->getName() << ErrorStr;
Buffer.setInt(Buffer.getInt() | InvalidFlag);
@@ -114,25 +127,24 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
// Check that the file's size is the same as in the file entry (which may
// have come from a stat cache).
- if (getRawBuffer()->getBufferSize() != (size_t)Entry->getSize()) {
+ if (getRawBuffer()->getBufferSize() != (size_t)ContentsEntry->getSize()) {
if (Diag.isDiagnosticInFlight())
Diag.SetDelayedDiagnostic(diag::err_file_modified,
- Entry->getName());
+ ContentsEntry->getName());
else
Diag.Report(Loc, diag::err_file_modified)
- << Entry->getName();
+ << ContentsEntry->getName();
Buffer.setInt(Buffer.getInt() | InvalidFlag);
if (Invalid) *Invalid = true;
return Buffer.getPointer();
}
-
+
// If the buffer is valid, check to see if it has a UTF Byte Order Mark
- // (BOM). We only support UTF-8 without a BOM right now. See
+ // (BOM). We only support UTF-8 with and without a BOM right now. See
// http://en.wikipedia.org/wiki/Byte_order_mark for more information.
llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
- const char *BOM = llvm::StringSwitch<const char *>(BufStr)
- .StartsWith("\xEF\xBB\xBF", "UTF-8")
+ const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr)
.StartsWith("\xFE\xFF", "UTF-16 (BE)")
.StartsWith("\xFF\xFE", "UTF-16 (LE)")
.StartsWith("\x00\x00\xFE\xFF", "UTF-32 (BE)")
@@ -145,9 +157,9 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
.StartsWith("\x84\x31\x95\x33", "GB-18030")
.Default(0);
- if (BOM) {
+ if (InvalidBOM) {
Diag.Report(Loc, diag::err_unsupported_bom)
- << BOM << Entry->getName();
+ << InvalidBOM << ContentsEntry->getName();
Buffer.setInt(Buffer.getInt() | InvalidFlag);
}
@@ -279,7 +291,12 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
int FilenameID) {
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+ if (!Entry.isFile() || Invalid)
+ return;
+
+ const SrcMgr::FileInfo &FileInfo = Entry.getFile();
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
@@ -303,7 +320,13 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
}
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile();
+
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+ if (!Entry.isFile() || Invalid)
+ return;
+
+ const SrcMgr::FileInfo &FileInfo = Entry.getFile();
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
@@ -340,9 +363,9 @@ LineTableInfo &SourceManager::getLineTable() {
//===----------------------------------------------------------------------===//
SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr)
- : Diag(Diag), FileMgr(FileMgr),
+ : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
- NumBinaryProbes(0) {
+ NumBinaryProbes(0), FakeBufferForRecovery(0) {
clearIDTables();
Diag.setSourceManager(this);
}
@@ -362,6 +385,8 @@ SourceManager::~SourceManager() {
I->second->~ContentCache();
ContentCacheAlloc.Deallocate(I->second);
}
+
+ delete FakeBufferForRecovery;
}
void SourceManager::clearIDTables() {
@@ -395,7 +420,18 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) {
unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
EntryAlign = std::max(8U, EntryAlign);
Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
- new (Entry) ContentCache(FileEnt);
+
+ // If the file contents are overridden with contents from another file,
+ // pass that file to ContentCache.
+ llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
+ overI = OverriddenFiles.find(FileEnt);
+ if (overI == OverriddenFiles.end())
+ new (Entry) ContentCache(FileEnt);
+ else
+ new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt
+ : overI->second,
+ overI->second);
+
return Entry;
}
@@ -445,6 +481,15 @@ void SourceManager::ClearPreallocatedSLocEntries() {
ExternalSLocEntries = 0;
}
+/// \brief As part of recovering from missing or changed content, produce a
+/// fake, non-empty buffer.
+const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
+ if (!FakeBufferForRecovery)
+ FakeBufferForRecovery
+ = llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
+
+ return FakeBufferForRecovery;
+}
//===----------------------------------------------------------------------===//
// Methods to create new FileID's and instantiations.
@@ -531,10 +576,21 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile,
const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
}
+void SourceManager::overrideFileContents(const FileEntry *SourceFile,
+ const FileEntry *NewFile) {
+ assert(SourceFile->getSize() == NewFile->getSize() &&
+ "Different sizes, use the FileManager to create a virtual file with "
+ "the correct size");
+ assert(FileInfos.count(SourceFile) == 0 &&
+ "This function should be called at the initialization stage, before "
+ "any parsing occurs.");
+ OverriddenFiles[SourceFile] = NewFile;
+}
+
llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
bool MyInvalid = false;
- const SLocEntry &SLoc = getSLocEntry(FID.ID);
- if (!SLoc.isFile()) {
+ const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid);
+ if (!SLoc.isFile() || MyInvalid) {
if (Invalid)
*Invalid = true;
return "<<<<<INVALID SOURCE LOCATION>>>>>";
@@ -562,7 +618,8 @@ llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
/// SLocEntryTable which contains the specified location.
///
FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
- assert(SLocOffset && "Invalid FileID");
+ if (!SLocOffset)
+ return FileID::get(0);
// After the first and second level caches, I see two common sorts of
// behavior: 1) a lot of searched FileID's are "near" the cached file location
@@ -590,8 +647,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
unsigned NumProbes = 0;
while (1) {
--I;
- if (ExternalSLocEntries)
- getSLocEntry(FileID::get(I - SLocEntryTable.begin()));
+ if (ExternalSLocEntries) {
+ bool Invalid = false;
+ getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid);
+ if (Invalid)
+ return FileID::get(0);
+ }
+
if (I->getOffset() <= SLocOffset) {
#if 0
printf("lin %d -> %d [%s] %d %d\n", SLocOffset,
@@ -621,9 +683,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
unsigned LessIndex = 0;
NumProbes = 0;
while (1) {
+ bool Invalid = false;
unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
- unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset();
-
+ unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid)
+ .getOffset();
+ if (Invalid)
+ return FileID::get(0);
+
++NumProbes;
// If the offset of the midpoint is too large, chop the high side of the
@@ -773,9 +839,16 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
// Note that calling 'getBuffer()' may lazily page in a source file.
bool CharDataInvalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid);
+ if (CharDataInvalid || !Entry.isFile()) {
+ if (Invalid)
+ *Invalid = true;
+
+ return "<<<<INVALID BUFFER>>>>";
+ }
const llvm::MemoryBuffer *Buffer
- = getSLocEntry(LocInfo.first).getFile().getContentCache()
- ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
+ = Entry.getFile().getContentCache()
+ ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
@@ -891,10 +964,18 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
ContentCache *Content;
if (LastLineNoFileIDQuery == FID)
Content = LastLineNoContentCache;
- else
- Content = const_cast<ContentCache*>(getSLocEntry(FID)
- .getFile().getContentCache());
-
+ else {
+ bool MyInvalid = false;
+ const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid);
+ if (MyInvalid || !Entry.isFile()) {
+ if (Invalid)
+ *Invalid = true;
+ return 1;
+ }
+
+ Content = const_cast<ContentCache*>(Entry.getFile().getContentCache());
+ }
+
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
@@ -1021,7 +1102,12 @@ SrcMgr::CharacteristicKind
SourceManager::getFileCharacteristic(SourceLocation Loc) const {
assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!");
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+ bool Invalid = false;
+ const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid);
+ if (Invalid || !SEntry.isFile())
+ return C_User;
+
+ const SrcMgr::FileInfo &FI = SEntry.getFile();
// If there are no #line directives in this file, just return the whole-file
// state.
@@ -1064,18 +1150,23 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// Presumed locations are always for instantiation points.
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile();
+ bool Invalid = false;
+ const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return PresumedLoc();
+
+ const SrcMgr::FileInfo &FI = Entry.getFile();
const SrcMgr::ContentCache *C = FI.getContentCache();
// To get the source name, first consult the FileEntry (if one exists)
// before the MemBuffer as this will avoid unnecessarily paging in the
// MemBuffer.
const char *Filename;
- if (C->Entry)
- Filename = C->Entry->getName();
+ if (C->OrigEntry)
+ Filename = C->OrigEntry->getName();
else
Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
- bool Invalid = false;
+
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
if (Invalid)
return PresumedLoc();
@@ -1152,18 +1243,22 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
llvm::Optional<ino_t> SourceFileInode;
llvm::Optional<llvm::StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
- const SLocEntry &MainSLoc = getSLocEntry(MainFileID);
+ bool Invalid = false;
+ const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
if (MainSLoc.isFile()) {
const ContentCache *MainContentCache
= MainSLoc.getFile().getContentCache();
if (!MainContentCache) {
// Can't do anything
- } else if (MainContentCache->Entry == SourceFile) {
+ } else if (MainContentCache->OrigEntry == SourceFile) {
FirstFID = MainFileID;
} else {
// Fall back: check whether we have the same base name and inode
// as the main file.
- const FileEntry *MainFile = MainContentCache->Entry;
+ const FileEntry *MainFile = MainContentCache->OrigEntry;
SourceFileName = llvm::sys::path::filename(SourceFile->getName());
if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
SourceFileInode = getActualFileInode(SourceFile);
@@ -1185,10 +1280,14 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
// The location we're looking for isn't in the main file; look
// through all of the source locations.
for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
- const SLocEntry &SLoc = getSLocEntry(I);
+ bool Invalid = false;
+ const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
if (SLoc.isFile() &&
SLoc.getFile().getContentCache() &&
- SLoc.getFile().getContentCache()->Entry == SourceFile) {
+ SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
FirstFID = FileID::get(I);
break;
}
@@ -1203,12 +1302,16 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
(SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
(SourceFileInode ||
(SourceFileInode = getActualFileInode(SourceFile)))) {
+ bool Invalid = false;
for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {
- const SLocEntry &SLoc = getSLocEntry(I);
+ const SLocEntry &SLoc = getSLocEntry(I, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
if (SLoc.isFile()) {
const ContentCache *FileContentCache
= SLoc.getFile().getContentCache();
- const FileEntry *Entry =FileContentCache? FileContentCache->Entry : 0;
+ const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0;
if (Entry &&
*SourceFileName == llvm::sys::path::filename(Entry->getName())) {
if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
@@ -1367,7 +1470,7 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/;
while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/;
- // If exactly one location is a memory buffer, assume it preceeds the other.
+ // If exactly one location is a memory buffer, assume it precedes the other.
// Strip off macro instantation locations, going up to the top-level File
// SLocEntry.
@@ -1403,3 +1506,24 @@ void SourceManager::PrintStats() const {
}
ExternalSLocEntrySource::~ExternalSLocEntrySource() { }
+
+/// Return the amount of memory used by memory buffers, breaking down
+/// by heap-backed versus mmap'ed memory.
+SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const {
+ size_t malloc_bytes = 0;
+ size_t mmap_bytes = 0;
+
+ for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i)
+ if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped())
+ switch (MemBufferInfos[i]->getMemoryBufferKind()) {
+ case llvm::MemoryBuffer::MemoryBuffer_MMap:
+ mmap_bytes += sized_mapped;
+ break;
+ case llvm::MemoryBuffer::MemoryBuffer_Malloc:
+ malloc_bytes += sized_mapped;
+ break;
+ }
+
+ return MemoryBufferSizes(malloc_bytes, mmap_bytes);
+}
+
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index a9eeb8b4cc4e..dcf0cb4237a9 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
@@ -19,6 +20,8 @@
#include <cstdlib>
using namespace clang;
+static const LangAS::Map DefaultAddrSpaceMap = { 0 };
+
// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
@@ -64,6 +67,13 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// Default to using the Itanium ABI.
CXXABI = CXXABI_Itanium;
+
+ // Default to an empty address space map.
+ AddrSpaceMap = &DefaultAddrSpaceMap;
+
+ // Default to an unknown platform name.
+ PlatformName = "unknown";
+ PlatformMinVersion = VersionTuple();
}
// Out of line virtual dtor for TargetInfo.
@@ -422,7 +432,7 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
case ',': // multiple alternative constraint. Ignore comma.
break;
case '?': // Disparage slightly code.
- case '!': // Disparage severly.
+ case '!': // Disparage severely.
break; // Pass them.
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 55321f2498ef..97109caf1237 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -76,7 +76,9 @@ public:
static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
- const llvm::Triple &Triple) {
+ const llvm::Triple &Triple,
+ llvm::StringRef &PlatformName,
+ VersionTuple &PlatformMinVersion) {
Builder.defineMacro("__APPLE_CC__", "5621");
Builder.defineMacro("__APPLE__");
Builder.defineMacro("__MACH__");
@@ -99,19 +101,40 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
- // Get the OS version number from the triple.
+ // Get the platform type and version number from the triple.
unsigned Maj, Min, Rev;
// If no version was given, default to to 10.4.0, for simplifying tests.
- if (Triple.getOSName() == "darwin") {
+ if (Triple.getOSName() == "darwin" || Triple.getOSName() == "osx") {
+ PlatformName = "macosx";
Min = Rev = 0;
Maj = 8;
- } else
- Triple.getDarwinNumber(Maj, Min, Rev);
+ } else {
+ // Otherwise, honor all three triple forms ("-darwinNNN[-iphoneos]",
+ // "-osxNNN", and "-iosNNN").
+
+ if (Triple.getOS() == llvm::Triple::Darwin) {
+ // For historical reasons that make little sense, the version passed here
+ // is the "darwin" version, which drops the 10 and offsets by 4.
+ Triple.getOSVersion(Maj, Min, Rev);
+
+ if (Triple.getEnvironmentName() == "iphoneos") {
+ PlatformName = "ios";
+ } else {
+ PlatformName = "macosx";
+ Rev = Min;
+ Min = Maj - 4;
+ Maj = 10;
+ }
+ } else {
+ Triple.getOSVersion(Maj, Min, Rev);
+ PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
+ }
+ }
// Set the appropriate OS version define.
- if (Triple.getEnvironmentName() == "iphoneos") {
- assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!");
+ if (PlatformName == "ios") {
+ assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
char Str[6];
Str[0] = '0' + Maj;
Str[1] = '0' + (Min / 10);
@@ -121,22 +144,22 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Str[5] = '\0';
Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str);
} else {
- // For historical reasons that make little sense, the version passed here is
- // the "darwin" version, which drops the 10 and offsets by 4.
- Rev = Min;
- Min = Maj - 4;
- Maj = 10;
-
+ // Note that the Driver allows versions which aren't representable in the
+ // define (because we only get a single digit for the minor and micro
+ // revision numbers). So, we limit them to the maximum representable
+ // version.
assert(Triple.getEnvironmentName().empty() && "Invalid environment!");
- assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!");
+ assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
char Str[5];
Str[0] = '0' + (Maj / 10);
Str[1] = '0' + (Maj % 10);
- Str[2] = '0' + Min;
- Str[3] = '0' + Rev;
+ Str[2] = '0' + std::min(Min, 9U);
+ Str[3] = '0' + std::min(Rev, 9U);
Str[4] = '\0';
Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
}
+
+ PlatformMinVersion = VersionTuple(Maj, Min, Rev);
}
namespace {
@@ -145,7 +168,8 @@ class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts, Triple);
+ getDarwinDefines(Builder, Opts, Triple, this->PlatformName,
+ this->PlatformMinVersion);
}
public:
@@ -159,8 +183,9 @@ public:
// Let MCSectionMachO validate this.
llvm::StringRef Segment, Section;
unsigned TAA, StubSize;
+ bool HasTAA;
return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section,
- TAA, StubSize);
+ TAA, HasTAA, StubSize);
}
virtual const char *getStaticInitSectionSpecifier() const {
@@ -823,6 +848,87 @@ public:
} // end anonymous namespace.
namespace {
+ class PTXTargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ static const Builtin::Info BuiltinInfo[];
+ public:
+ PTXTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ TLSSupported = false;
+ LongWidth = LongAlign = 64;
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__PTX__");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = BuiltinInfo;
+ NumRecords = clang::PTX::LastTSBuiltin-Builtin::FirstTSBuiltin;
+ }
+
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ // No aliases.
+ Aliases = 0;
+ NumAliases = 0;
+ }
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ // FIXME: implement
+ return true;
+ }
+ virtual const char *getClobbers() const {
+ // FIXME: Is this really right?
+ return "";
+ }
+ virtual const char *getVAListDeclaration() const {
+ // FIXME: implement
+ return "typedef char* __builtin_va_list;";
+ }
+ };
+
+ const Builtin::Info PTXTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES, false },
+#include "clang/Basic/BuiltinsPTX.def"
+ };
+
+ const char * const PTXTargetInfo::GCCRegNames[] = {
+ "r0"
+ };
+
+ void PTXTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+ }
+
+
+ class PTX32TargetInfo : public PTXTargetInfo {
+ public:
+ PTX32TargetInfo(const std::string& triple) : PTXTargetInfo(triple) {
+ PointerWidth = PointerAlign = 32;
+ SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedInt;
+ DescriptionString
+ = "e-p:32:32-i64:64:64-f64:64:64-n1:8:16:32:64";
+ }
+ };
+
+ class PTX64TargetInfo : public PTXTargetInfo {
+ public:
+ PTX64TargetInfo(const std::string& triple) : PTXTargetInfo(triple) {
+ PointerWidth = PointerAlign = 64;
+ SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedLongLong;
+ DescriptionString
+ = "e-p:64:64-i64:64:64-f64:64:64-n1:8:16:32:64";
+ }
+ };
+}
+
+namespace {
// MBlaze abstract base class
class MBlazeTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
@@ -1074,8 +1180,11 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
else if (CPU == "corei7") {
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
- }
- else if (CPU == "k6" || CPU == "winchip-c6")
+ } else if (CPU == "sandybridge") {
+ setFeatureEnabled(Features, "sse4", true);
+ setFeatureEnabled(Features, "aes", true);
+// setFeatureEnabled(Features, "avx", true);
+ } else if (CPU == "k6" || CPU == "winchip-c6")
setFeatureEnabled(Features, "mmx", true);
else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" ||
CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") {
@@ -1133,7 +1242,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["avx"] = true;
} else {
if (Name == "mmx")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["3dnow"] = Features["3dnowa"] =
+ Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
else if (Name == "sse")
Features["sse"] = Features["sse2"] = Features["sse3"] =
@@ -1146,12 +1256,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["sse42"] = false;
else if (Name == "ssse3")
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
- else if (Name == "sse4")
+ else if (Name == "sse4" || Name == "sse4.1")
Features["sse41"] = Features["sse42"] = false;
else if (Name == "sse4.2")
Features["sse42"] = false;
- else if (Name == "sse4.1")
- Features["sse41"] = Features["sse42"] = false;
else if (Name == "3dnow")
Features["3dnow"] = Features["3dnowa"] = false;
else if (Name == "3dnowa")
@@ -1451,7 +1559,7 @@ class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
VisualStudioWindowsX86_32TargetInfo(const std::string& triple)
: WindowsX86_32TargetInfo(triple) {
- LongDoubleWidth = 64;
+ LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1481,7 +1589,15 @@ public:
Builder.defineMacro("_X86_");
Builder.defineMacro("__MSVCRT__");
Builder.defineMacro("__MINGW32__");
- Builder.defineMacro("__declspec", "__declspec");
+
+ // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
+ // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
+ if (Opts.Microsoft)
+ // Provide "as-is" __declspec.
+ Builder.defineMacro("__declspec", "__declspec");
+ else
+ // Provide alias of __attribute__ like mingw32-gcc.
+ Builder.defineMacro("__declspec(a)", "__attribute__((a))");
}
};
} // end anonymous namespace
@@ -1606,6 +1722,8 @@ class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
VisualStudioWindowsX86_64TargetInfo(const std::string& triple)
: WindowsX86_64TargetInfo(triple) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -1629,8 +1747,17 @@ public:
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
DefineStd(Builder, "WIN64", Opts);
Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW32__");
Builder.defineMacro("__MINGW64__");
- Builder.defineMacro("__declspec", "__declspec");
+
+ // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
+ // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
+ if (Opts.Microsoft)
+ // Provide "as-is" __declspec.
+ Builder.defineMacro("__declspec", "__declspec");
+ else
+ // Provide alias of __attribute__ like mingw32-gcc.
+ Builder.defineMacro("__declspec(a)", "__attribute__((a))");
}
};
} // end anonymous namespace
@@ -1700,13 +1827,15 @@ public:
// FIXME: Should we just treat this as a feature?
IsThumb = getTriple().getArchName().startswith("thumb");
if (IsThumb) {
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:32-n32");
+ "v64:64:64-v128:64:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:64-n32");
+ "v64:64:64-v128:64:128-a0:0:64-n32");
}
// ARM targets default to using the ARM C++ ABI.
@@ -1729,13 +1858,15 @@ public:
UseBitFieldTypeAlignment = false;
if (IsThumb) {
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:32-n32");
+ "v64:32:64-v128:32:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:64-n32");
+ "i64:32:64-f32:32:32-f64:32:64-"
+ "v64:32:64-v128:32:128-a0:0:32-n32");
}
// FIXME: Override "preferred align" for double and long long.
@@ -1822,6 +1953,7 @@ public:
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
.Cases("cortex-a8", "cortex-a9", "7A")
.Case("cortex-m3", "7M")
+ .Case("cortex-m0", "6M")
.Default(0);
}
virtual bool setCPU(const std::string &Name) {
@@ -1984,7 +2116,7 @@ class DarwinARMTargetInfo :
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts, Triple);
+ getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
}
public:
@@ -2563,11 +2695,12 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
+ if (Triple.isOSDarwin())
+ return new DarwinARMTargetInfo(T);
+
switch (os) {
case llvm::Triple::Linux:
return new LinuxTargetInfo<ARMTargetInfo>(T);
- case llvm::Triple::Darwin:
- return new DarwinARMTargetInfo(T);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<ARMTargetInfo>(T);
default:
@@ -2595,14 +2728,14 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MipselTargetInfo(T);
case llvm::Triple::ppc:
- if (os == llvm::Triple::Darwin)
+ if (Triple.isOSDarwin())
return new DarwinPPC32TargetInfo(T);
else if (os == llvm::Triple::FreeBSD)
return new FreeBSDTargetInfo<PPC32TargetInfo>(T);
return new PPC32TargetInfo(T);
case llvm::Triple::ppc64:
- if (os == llvm::Triple::Darwin)
+ if (Triple.isOSDarwin())
return new DarwinPPC64TargetInfo(T);
else if (os == llvm::Triple::Lv2)
return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
@@ -2610,6 +2743,11 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new FreeBSDTargetInfo<PPC64TargetInfo>(T);
return new PPC64TargetInfo(T);
+ case llvm::Triple::ptx32:
+ return new PTX32TargetInfo(T);
+ case llvm::Triple::ptx64:
+ return new PTX64TargetInfo(T);
+
case llvm::Triple::mblaze:
return new MBlazeTargetInfo(T);
@@ -2631,11 +2769,12 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new TCETargetInfo(T);
case llvm::Triple::x86:
+ if (Triple.isOSDarwin())
+ return new DarwinI386TargetInfo(T);
+
switch (os) {
case llvm::Triple::AuroraUX:
return new AuroraUXTargetInfo<X86_32TargetInfo>(T);
- case llvm::Triple::Darwin:
- return new DarwinI386TargetInfo(T);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_32TargetInfo>(T);
case llvm::Triple::DragonFly:
@@ -2663,11 +2802,12 @@ static TargetInfo *AllocateTarget(const std::string &T) {
}
case llvm::Triple::x86_64:
+ if (Triple.isOSDarwin() || Triple.getEnvironment() == llvm::Triple::MachO)
+ return new DarwinX86_64TargetInfo(T);
+
switch (os) {
case llvm::Triple::AuroraUX:
return new AuroraUXTargetInfo<X86_64TargetInfo>(T);
- case llvm::Triple::Darwin:
- return new DarwinX86_64TargetInfo(T);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_64TargetInfo>(T);
case llvm::Triple::DragonFly:
@@ -2683,10 +2823,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::MinGW32:
return new MinGWX86_64TargetInfo(T);
case llvm::Triple::Win32: // This is what Triple.h supports now.
- if (Triple.getEnvironment() == llvm::Triple::MachO)
- return new DarwinX86_64TargetInfo(T);
- else
- return new VisualStudioWindowsX86_64TargetInfo(T);
+ return new VisualStudioWindowsX86_64TargetInfo(T);
default:
return new X86_64TargetInfo(T);
}
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 6573eb96e3f3..8f713524629c 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -17,11 +17,12 @@
#include <cstring>
#include <cstdlib>
-using namespace std;
-
namespace clang {
std::string getClangRepositoryPath() {
+#if defined(CLANG_REPOSITORY_STRING)
+ return CLANG_REPOSITORY_STRING;
+#else
#ifdef SVN_REPOSITORY
llvm::StringRef URL(SVN_REPOSITORY);
#else
@@ -45,6 +46,7 @@ std::string getClangRepositoryPath() {
URL = URL.substr(Start + 4);
return URL;
+#endif
}
std::string getClangRevision() {
@@ -87,4 +89,17 @@ std::string getClangFullVersion() {
return OS.str();
}
+std::string getClangFullCPPVersion() {
+ // The version string we report in __VERSION__ is just a compacted version of
+ // the one we report on the command line.
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
+#ifdef CLANG_VENDOR
+ OS << CLANG_VENDOR;
+#endif
+ OS << "Clang " CLANG_VERSION_STRING " ("
+ << getClangFullRepositoryVersion() << ')';
+ return OS.str();
+}
+
} // end namespace clang
diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp
new file mode 100644
index 000000000000..d5cf126ff487
--- /dev/null
+++ b/lib/Basic/VersionTuple.cpp
@@ -0,0 +1,36 @@
+//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the VersionTuple class, which represents a version in
+// the form major[.minor[.subminor]].
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/VersionTuple.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+std::string VersionTuple::getAsString() const {
+ std::string Result;
+ {
+ llvm::raw_string_ostream Out(Result);
+ Out << *this;
+ }
+ return Result;
+}
+
+llvm::raw_ostream& clang::operator<<(llvm::raw_ostream &Out,
+ const VersionTuple &V) {
+ Out << V.getMajor();
+ if (llvm::Optional<unsigned> Minor = V.getMinor())
+ Out << '.' << *Minor;
+ if (llvm::Optional<unsigned> Subminor = V.getSubminor())
+ Out << '.' << *Subminor;
+ return Out;
+}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index b4574344bc5f..0943e2b1c785 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -13,3 +13,4 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Index)
add_subdirectory(StaticAnalyzer)
+add_subdirectory(Tooling)
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 9897b1b1a028..1264473dabce 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -30,6 +30,7 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Transforms/Instrumentation.h"
using namespace clang;
using namespace llvm;
@@ -108,9 +109,9 @@ void EmitAssemblyHelper::CreatePasses() {
OptLevel = 0;
Inlining = CodeGenOpts.NoInlining;
}
-
+
FunctionPassManager *FPM = getPerFunctionPasses();
-
+
TargetLibraryInfo *TLI =
new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
if (!CodeGenOpts.SimplifyLibCalls)
@@ -133,8 +134,10 @@ void EmitAssemblyHelper::CreatePasses() {
//
// FIXME: Derive these constants in a principled fashion.
unsigned Threshold = 225;
- if (CodeGenOpts.OptimizeSize)
+ if (CodeGenOpts.OptimizeSize == 1) //-Os
Threshold = 75;
+ else if (CodeGenOpts.OptimizeSize == 2) //-Oz
+ Threshold = 25;
else if (OptLevel > 2)
Threshold = 275;
InliningPass = createFunctionInliningPass(Threshold);
@@ -146,12 +149,19 @@ void EmitAssemblyHelper::CreatePasses() {
}
PassManager *MPM = getPerModulePasses();
-
+
TLI = new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
if (!CodeGenOpts.SimplifyLibCalls)
TLI->disableAllFunctions();
MPM->add(TLI);
+ if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
+ MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
+ CodeGenOpts.EmitGcovArcs));
+ if (!CodeGenOpts.DebugInfo)
+ MPM->add(createStripSymbolsPass(true));
+ }
+
// For now we always create per module passes.
llvm::createStandardModulePasses(MPM, OptLevel,
CodeGenOpts.OptimizeSize,
@@ -190,7 +200,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
}
// Set float ABI type.
- if (CodeGenOpts.FloatABI == "soft")
+ if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp")
llvm::FloatABIType = llvm::FloatABI::Soft;
else if (CodeGenOpts.FloatABI == "hard")
llvm::FloatABIType = llvm::FloatABI::Hard;
@@ -248,6 +258,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
}
if (llvm::TimePassesIsEnabled)
BackendArgs.push_back("-time-passes");
+ for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i)
+ BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str());
BackendArgs.push_back(0);
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
const_cast<char **>(&BackendArgs[0]));
@@ -266,6 +278,10 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
if (CodeGenOpts.RelaxAll)
TM->setMCRelaxAll(true);
+ if (CodeGenOpts.SaveTempLabels)
+ TM->setMCSaveTempLabels(true);
+ if (CodeGenOpts.NoDwarf2CFIAsm)
+ TM->setMCUseCFI(false);
// Create the code generator passes.
PassManager *PM = getCodeGenPasses();
@@ -319,6 +335,9 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
return;
}
+ // Before executing passes, print the final values of the LLVM options.
+ cl::PrintOptionValues();
+
// Run passes. For now we do all passes at once, but eventually we
// would like to have the option of streaming code generation.
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 9587de223aa7..99a69a4f4a93 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -27,13 +27,16 @@ using namespace CodeGen;
CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N)
: Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), StructureType(0), Block(blockExpr) {
+ HasCXXObject(false), UsesStret(false), StructureType(0), Block(blockExpr) {
// Skip asm prefix, if any.
if (Name && Name[0] == '\01')
++Name;
}
+// Anchor the vtable to this translation unit.
+CodeGenModule::ByrefHelpers::~ByrefHelpers() {}
+
/// Build the given block as a global block.
static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
const CGBlockInfo &blockInfo,
@@ -104,23 +107,6 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType());
}
-static BlockFlags computeBlockFlag(CodeGenModule &CGM,
- const BlockExpr *BE,
- BlockFlags flags) {
- const FunctionType *ftype = BE->getFunctionType();
-
- // This is a bit overboard.
- CallArgList args;
- const CGFunctionInfo &fnInfo =
- CGM.getTypes().getFunctionInfo(ftype->getResultType(), args,
- ftype->getExtInfo());
-
- if (CGM.ReturnTypeUsesSRet(fnInfo))
- flags |= BLOCK_USE_STRET;
-
- return flags;
-}
-
/*
Purely notional variadic template describing the layout of a block.
@@ -536,7 +522,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
BlockFlags flags = BLOCK_HAS_SIGNATURE;
if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ;
- flags = computeBlockFlag(CGM, blockInfo.getBlockExpr(), flags);
+ if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
// Initialize the block literal.
Builder.CreateStore(isa, Builder.CreateStructGEP(blockAddr, 0, "block.isa"));
@@ -630,7 +616,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
declRef, VK_RValue);
- EmitAnyExprToMem(&l2r, blockField, /*volatile*/ false, /*init*/ true);
+ EmitExprAsInit(&l2r, variable, blockField,
+ getContext().getDeclAlign(variable),
+ /*captured by init*/ false);
}
// Push a destructor if necessary. The semantics for when this
@@ -734,7 +722,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
// Add the block literal.
QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy);
CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(BlockLiteral), VoidPtrTy));
+ Args.add(RValue::get(BlockLiteral), VoidPtrTy);
QualType FnType = BPT->getPointeeType();
@@ -745,7 +733,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
// Load the function.
llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
- const FunctionType *FuncTy = FnType->getAs<FunctionType>();
+ const FunctionType *FuncTy = FnType->castAs<FunctionType>();
QualType ResultType = FuncTy->getResultType();
const CGFunctionInfo &FnInfo =
@@ -834,8 +822,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
fields[0] = CGM.getNSConcreteGlobalBlock();
// __flags
- BlockFlags flags = computeBlockFlag(CGM, blockInfo.getBlockExpr(),
- BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE);
+ BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
+ if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
+
fields[1] = llvm::ConstantInt::get(CGM.IntTy, flags.getBitMask());
// Reserved
@@ -873,7 +862,10 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const DeclMapTy &ldm) {
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
- DebugInfo = CGM.getDebugInfo();
+ // Check if we should generate debug info for this block function.
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
BlockInfo = &blockInfo;
// Arrange for local static and local extern declarations to appear
@@ -897,12 +889,12 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
ImplicitParamDecl selfDecl(const_cast<BlockDecl*>(blockDecl),
SourceLocation(), II, selfTy);
- args.push_back(std::make_pair(&selfDecl, selfTy));
+ args.push_back(&selfDecl);
// Now add the rest of the parameters.
for (BlockDecl::param_const_iterator i = blockDecl->param_begin(),
e = blockDecl->param_end(); i != e; ++i)
- args.push_back(std::make_pair(*i, (*i)->getType()));
+ args.push_back(*i);
// Create the function declaration.
const FunctionProtoType *fnType =
@@ -910,6 +902,9 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const CGFunctionInfo &fnInfo =
CGM.getTypes().getFunctionInfo(fnType->getResultType(), args,
fnType->getExtInfo());
+ if (CGM.ReturnTypeUsesSRet(fnInfo))
+ blockInfo.UsesStret = true;
+
const llvm::FunctionType *fnLLVMType =
CGM.getTypes().GetFunctionType(fnInfo, fnType->isVariadic());
@@ -921,8 +916,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo);
// Begin generating the function.
- StartFunction(blockDecl, fnType->getResultType(), fn, args,
- blockInfo.getBlockExpr()->getBody()->getLocEnd());
+ StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args,
+ blockInfo.getBlockExpr()->getBody()->getLocStart());
CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl
// Okay. Undo some of what StartFunction did.
@@ -1049,13 +1044,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- // FIXME: This leaks
- ImplicitParamDecl *dstDecl =
- ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy);
- args.push_back(std::make_pair(dstDecl, dstDecl->getType()));
- ImplicitParamDecl *srcDecl =
- ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy);
- args.push_back(std::make_pair(srcDecl, srcDecl->getType()));
+ ImplicitParamDecl dstDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ args.push_back(&dstDecl);
+ ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
@@ -1073,20 +1065,21 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
SC_None,
false,
true);
- StartFunction(FD, C.VoidTy, Fn, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- llvm::Value *src = GetAddrOfLocalVar(srcDecl);
+ llvm::Value *src = GetAddrOfLocalVar(&srcDecl);
src = Builder.CreateLoad(src);
src = Builder.CreateBitCast(src, structPtrTy, "block.source");
- llvm::Value *dst = GetAddrOfLocalVar(dstDecl);
+ llvm::Value *dst = GetAddrOfLocalVar(&dstDecl);
dst = Builder.CreateLoad(dst);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
@@ -1143,10 +1136,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- // FIXME: This leaks
- ImplicitParamDecl *srcDecl =
- ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy);
- args.push_back(std::make_pair(srcDecl, srcDecl->getType()));
+ ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
@@ -1163,15 +1154,16 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
= &CGM.getContext().Idents.get("__destroy_helper_block_");
FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
SC_None,
false, true);
- StartFunction(FD, C.VoidTy, Fn, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- llvm::Value *src = GetAddrOfLocalVar(srcDecl);
+ llvm::Value *src = GetAddrOfLocalVar(&srcDecl);
src = Builder.CreateLoad(src);
src = Builder.CreateBitCast(src, structPtrTy, "block");
@@ -1229,99 +1221,158 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
}
-llvm::Constant *CodeGenFunction::
-GeneratebyrefCopyHelperFunction(const llvm::Type *T, BlockFieldFlags flags,
- const VarDecl *variable) {
- QualType R = getContext().VoidTy;
-
- FunctionArgList Args;
- // FIXME: This leaks
- ImplicitParamDecl *Dst =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
- Args.push_back(std::make_pair(Dst, Dst->getType()));
-
- // FIXME: This leaks
- ImplicitParamDecl *Src =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
- Args.push_back(std::make_pair(Src, Src->getType()));
+namespace {
+
+/// Emits the copy/dispose helper functions for a __block object of id type.
+class ObjectByrefHelpers : public CodeGenModule::ByrefHelpers {
+ BlockFieldFlags Flags;
+
+public:
+ ObjectByrefHelpers(CharUnits alignment, BlockFieldFlags flags)
+ : ByrefHelpers(alignment), Flags(flags) {}
+
+ void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+ llvm::Value *srcField) {
+ destField = CGF.Builder.CreateBitCast(destField, CGF.VoidPtrTy);
+
+ srcField = CGF.Builder.CreateBitCast(srcField, CGF.VoidPtrPtrTy);
+ llvm::Value *srcValue = CGF.Builder.CreateLoad(srcField);
+
+ unsigned flags = (Flags | BLOCK_BYREF_CALLER).getBitMask();
+
+ llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags);
+ llvm::Value *fn = CGF.CGM.getBlockObjectAssign();
+ CGF.Builder.CreateCall3(fn, destField, srcValue, flagsVal);
+ }
+
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0));
+ llvm::Value *value = CGF.Builder.CreateLoad(field);
+
+ CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER);
+ }
+
+ void profileImpl(llvm::FoldingSetNodeID &id) const {
+ id.AddInteger(Flags.getBitMask());
+ }
+};
+
+/// Emits the copy/dispose helpers for a __block variable with a
+/// nontrivial copy constructor or destructor.
+class CXXByrefHelpers : public CodeGenModule::ByrefHelpers {
+ QualType VarType;
+ const Expr *CopyExpr;
+
+public:
+ CXXByrefHelpers(CharUnits alignment, QualType type,
+ const Expr *copyExpr)
+ : ByrefHelpers(alignment), VarType(type), CopyExpr(copyExpr) {}
+
+ bool needsCopy() const { return CopyExpr != 0; }
+ void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+ llvm::Value *srcField) {
+ if (!CopyExpr) return;
+ CGF.EmitSynthesizedCXXCopyCtor(destField, srcField, CopyExpr);
+ }
+
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin();
+ CGF.PushDestructorCleanup(VarType, field);
+ CGF.PopCleanupBlocks(cleanupDepth);
+ }
+
+ void profileImpl(llvm::FoldingSetNodeID &id) const {
+ id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
+ }
+};
+} // end anonymous namespace
+
+static llvm::Constant *
+generateByrefCopyHelper(CodeGenFunction &CGF,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &byrefInfo) {
+ ASTContext &Context = CGF.getContext();
+
+ QualType R = Context.VoidTy;
+
+ FunctionArgList args;
+ ImplicitParamDecl dst(0, SourceLocation(), 0, Context.VoidPtrTy);
+ args.push_back(&dst);
+
+ ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
+ args.push_back(&src);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
+ CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
- CodeGenTypes &Types = CGM.getTypes();
+ CodeGenTypes &Types = CGF.CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__Block_byref_object_copy_", &CGM.getModule());
+ "__Block_byref_object_copy_", &CGF.CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__Block_byref_object_copy_");
+ = &Context.Idents.get("__Block_byref_object_copy_");
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
+ FunctionDecl *FD = FunctionDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
SC_None,
false, true);
- StartFunction(FD, R, Fn, Args, SourceLocation());
-
- // dst->x
- llvm::Value *V = GetAddrOfLocalVar(Dst);
- V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
- V = Builder.CreateLoad(V);
- V = Builder.CreateStructGEP(V, 6, "x");
- llvm::Value *DstObj = V;
-
- // src->x
- V = GetAddrOfLocalVar(Src);
- V = Builder.CreateLoad(V);
- V = Builder.CreateBitCast(V, T);
- V = Builder.CreateStructGEP(V, 6, "x");
-
- if (Expr *copyExpr = getContext().getBlockVarCopyInits(variable)) {
- llvm::Value *SrcObj = V;
- EmitSynthesizedCXXCopyCtor(DstObj, SrcObj, copyExpr);
- } else {
- DstObj = Builder.CreateBitCast(DstObj, VoidPtrTy);
- V = Builder.CreateBitCast(V, VoidPtrPtrTy);
- llvm::Value *SrcObj = Builder.CreateLoad(V);
- flags |= BLOCK_BYREF_CALLER;
- llvm::Value *N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask());
- llvm::Value *F = CGM.getBlockObjectAssign();
- Builder.CreateCall3(F, DstObj, SrcObj, N);
- }
-
- FinishFunction();
+ CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
- return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
+ if (byrefInfo.needsCopy()) {
+ const llvm::Type *byrefPtrType = byrefType.getPointerTo(0);
+
+ // dst->x
+ llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst);
+ destField = CGF.Builder.CreateLoad(destField);
+ destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
+ destField = CGF.Builder.CreateStructGEP(destField, 6, "x");
+
+ // src->x
+ llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src);
+ srcField = CGF.Builder.CreateLoad(srcField);
+ srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
+ srcField = CGF.Builder.CreateStructGEP(srcField, 6, "x");
+
+ byrefInfo.emitCopy(CGF, destField, srcField);
+ }
+
+ CGF.FinishFunction();
+
+ return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
}
-llvm::Constant *
-CodeGenFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
- BlockFieldFlags flags,
- const VarDecl *variable) {
- QualType R = getContext().VoidTy;
+/// Build the copy helper for a __block variable.
+static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &info) {
+ CodeGenFunction CGF(CGM);
+ return generateByrefCopyHelper(CGF, byrefType, info);
+}
- FunctionArgList Args;
- // FIXME: This leaks
- ImplicitParamDecl *Src =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
+/// Generate code for a __block variable's dispose helper.
+static llvm::Constant *
+generateByrefDisposeHelper(CodeGenFunction &CGF,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &byrefInfo) {
+ ASTContext &Context = CGF.getContext();
+ QualType R = Context.VoidTy;
- Args.push_back(std::make_pair(Src, Src->getType()));
+ FunctionArgList args;
+ ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
+ args.push_back(&src);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
+ CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
- CodeGenTypes &Types = CGM.getTypes();
+ CodeGenTypes &Types = CGF.CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
// FIXME: We'd like to put these into a mergable by content, with
@@ -1329,81 +1380,255 @@ CodeGenFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__Block_byref_object_dispose_",
- &CGM.getModule());
+ &CGF.CGM.getModule());
IdentifierInfo *II
- = &CGM.getContext().Idents.get("__Block_byref_object_dispose_");
+ = &Context.Idents.get("__Block_byref_object_dispose_");
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
+ FunctionDecl *FD = FunctionDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
SC_None,
false, true);
- StartFunction(FD, R, Fn, Args, SourceLocation());
+ CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
+
+ if (byrefInfo.needsDispose()) {
+ llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
+ V = CGF.Builder.CreateLoad(V);
+ V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0));
+ V = CGF.Builder.CreateStructGEP(V, 6, "x");
- llvm::Value *V = GetAddrOfLocalVar(Src);
- V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0));
- V = Builder.CreateLoad(V);
- V = Builder.CreateStructGEP(V, 6, "x");
+ byrefInfo.emitDispose(CGF, V);
+ }
- // If it's not any kind of special object, it must have a destructor
- // or something.
- if (!flags.isSpecialPointer()) {
- EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
- PushDestructorCleanup(variable->getType(), V);
- PopCleanupBlocks(CleanupDepth);
+ CGF.FinishFunction();
- // Otherwise, call _Block_object_dispose.
- } else {
- V = Builder.CreateBitCast(V, llvm::PointerType::get(Int8PtrTy, 0));
- V = Builder.CreateLoad(V);
+ return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy);
+}
- flags |= BLOCK_BYREF_CALLER;
- BuildBlockRelease(V, flags);
+/// Build the dispose helper for a __block variable.
+static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
+ const llvm::StructType &byrefType,
+ CodeGenModule::ByrefHelpers &info) {
+ CodeGenFunction CGF(CGM);
+ return generateByrefDisposeHelper(CGF, byrefType, info);
+}
+
+///
+template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
+ const llvm::StructType &byrefTy,
+ T &byrefInfo) {
+ // Increase the field's alignment to be at least pointer alignment,
+ // since the layout of the byref struct will guarantee at least that.
+ byrefInfo.Alignment = std::max(byrefInfo.Alignment,
+ CharUnits::fromQuantity(CGM.PointerAlignInBytes));
+
+ llvm::FoldingSetNodeID id;
+ byrefInfo.Profile(id);
+
+ void *insertPos;
+ CodeGenModule::ByrefHelpers *node
+ = CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos);
+ if (node) return static_cast<T*>(node);
+
+ byrefInfo.CopyHelper = buildByrefCopyHelper(CGM, byrefTy, byrefInfo);
+ byrefInfo.DisposeHelper = buildByrefDisposeHelper(CGM, byrefTy, byrefInfo);
+
+ T *copy = new (CGM.getContext()) T(byrefInfo);
+ CGM.ByrefHelpersCache.InsertNode(copy, insertPos);
+ return copy;
+}
+
+CodeGenModule::ByrefHelpers *
+CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType,
+ const AutoVarEmission &emission) {
+ const VarDecl &var = *emission.Variable;
+ QualType type = var.getType();
+
+ if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
+ const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
+ if (!copyExpr && record->hasTrivialDestructor()) return 0;
+
+ CXXByrefHelpers byrefInfo(emission.Alignment, type, copyExpr);
+ return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
- FinishFunction();
+ BlockFieldFlags flags;
+ if (type->isBlockPointerType()) {
+ flags |= BLOCK_FIELD_IS_BLOCK;
+ } else if (CGM.getContext().isObjCNSObjectType(type) ||
+ type->isObjCObjectPointerType()) {
+ flags |= BLOCK_FIELD_IS_OBJECT;
+ } else {
+ return 0;
+ }
- return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy);
+ if (type.isObjCGCWeak())
+ flags |= BLOCK_FIELD_IS_WEAK;
+
+ ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
+ return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
-llvm::Constant *CodeGenModule::BuildbyrefCopyHelper(const llvm::Type *T,
- BlockFieldFlags flags,
- unsigned align,
- const VarDecl *var) {
- // All alignments below pointer alignment are bumped up, as we
- // always have at least that much alignment to begin with.
- if (align < PointerAlignInBytes) align = PointerAlignInBytes;
+unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
+ assert(ByRefValueInfo.count(VD) && "Did not find value!");
- // As an optimization, we only generate a single function of each kind we
- // might need. We need a different one for each alignment and for each
- // setting of flags. We mix Align and flag to get the kind.
- uint64_t Kind = (uint64_t)align*BLOCK_BYREF_CURRENT_MAX + flags.getBitMask();
- llvm::Constant *&Entry = AssignCache[Kind];
- if (!Entry)
- Entry = CodeGenFunction(*this).
- GeneratebyrefCopyHelperFunction(T, flags, var);
- return Entry;
+ return ByRefValueInfo.find(VD)->second.second;
+}
+
+llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr,
+ const VarDecl *V) {
+ llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding");
+ Loc = Builder.CreateLoad(Loc);
+ Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V),
+ V->getNameAsString());
+ return Loc;
}
-llvm::Constant *CodeGenModule::BuildbyrefDestroyHelper(const llvm::Type *T,
- BlockFieldFlags flags,
- unsigned align,
- const VarDecl *var) {
- // All alignments below pointer alignment are bumped up, as we
- // always have at least that much alignment to begin with.
- if (align < PointerAlignInBytes) align = PointerAlignInBytes;
+/// BuildByRefType - This routine changes a __block variable declared as T x
+/// into:
+///
+/// struct {
+/// void *__isa;
+/// void *__forwarding;
+/// int32_t __flags;
+/// int32_t __size;
+/// void *__copy_helper; // only if needed
+/// void *__destroy_helper; // only if needed
+/// char padding[X]; // only if needed
+/// T x;
+/// } x
+///
+const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
+ std::pair<const llvm::Type *, unsigned> &Info = ByRefValueInfo[D];
+ if (Info.first)
+ return Info.first;
+
+ QualType Ty = D->getType();
+
+ std::vector<const llvm::Type *> Types;
+
+ llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext());
+
+ // void *__isa;
+ Types.push_back(Int8PtrTy);
+
+ // void *__forwarding;
+ Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
+
+ // int32_t __flags;
+ Types.push_back(Int32Ty);
+
+ // int32_t __size;
+ Types.push_back(Int32Ty);
+
+ bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ /// void *__copy_helper;
+ Types.push_back(Int8PtrTy);
+
+ /// void *__destroy_helper;
+ Types.push_back(Int8PtrTy);
+ }
+
+ bool Packed = false;
+ CharUnits Align = getContext().getDeclAlign(D);
+ if (Align > getContext().toCharUnitsFromBits(Target.getPointerAlign(0))) {
+ // We have to insert padding.
+
+ // The struct above has 2 32-bit integers.
+ unsigned CurrentOffsetInBytes = 4 * 2;
+
+ // And either 2 or 4 pointers.
+ CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
+ CGM.getTargetData().getTypeAllocSize(Int8PtrTy);
+
+ // Align the offset.
+ unsigned AlignedOffsetInBytes =
+ llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align.getQuantity());
+
+ unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
+ if (NumPaddingBytes > 0) {
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
+ // FIXME: We need a sema error for alignment larger than the minimum of
+ // the maximal stack alignmint and the alignment of malloc on the system.
+ if (NumPaddingBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumPaddingBytes);
+
+ Types.push_back(Ty);
+
+ // We want a packed struct.
+ Packed = true;
+ }
+ }
+
+ // T x;
+ Types.push_back(ConvertTypeForMem(Ty));
+
+ const llvm::Type *T = llvm::StructType::get(getLLVMContext(), Types, Packed);
+
+ cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T);
+ CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(),
+ ByRefTypeHolder.get());
- // As an optimization, we only generate a single function of each kind we
- // might need. We need a different one for each alignment and for each
- // setting of flags. We mix Align and flag to get the kind.
- uint64_t Kind = (uint64_t)align*BLOCK_BYREF_CURRENT_MAX + flags.getBitMask();
- llvm::Constant *&Entry = DestroyCache[Kind];
- if (!Entry)
- Entry = CodeGenFunction(*this).
- GeneratebyrefDestroyHelperFunction(T, flags, var);
- return Entry;
+ Info.first = ByRefTypeHolder.get();
+
+ Info.second = Types.size() - 1;
+
+ return Info.first;
+}
+
+/// Initialize the structural components of a __block variable, i.e.
+/// everything but the actual object.
+void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
+ // Find the address of the local.
+ llvm::Value *addr = emission.Address;
+
+ // That's an alloca of the byref structure type.
+ const llvm::StructType *byrefType = cast<llvm::StructType>(
+ cast<llvm::PointerType>(addr->getType())->getElementType());
+
+ // Build the byref helpers if necessary. This is null if we don't need any.
+ CodeGenModule::ByrefHelpers *helpers =
+ buildByrefHelpers(*byrefType, emission);
+
+ const VarDecl &D = *emission.Variable;
+ QualType type = D.getType();
+
+ llvm::Value *V;
+
+ // Initialize the 'isa', which is just 0 or 1.
+ int isa = 0;
+ if (type.isObjCGCWeak())
+ isa = 1;
+ V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa");
+ Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa"));
+
+ // Store the address of the variable into its own forwarding pointer.
+ Builder.CreateStore(addr,
+ Builder.CreateStructGEP(addr, 1, "byref.forwarding"));
+
+ // Blocks ABI:
+ // c) the flags field is set to either 0 if no helper functions are
+ // needed or BLOCK_HAS_COPY_DISPOSE if they are,
+ BlockFlags flags;
+ if (helpers) flags |= BLOCK_HAS_COPY_DISPOSE;
+ Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
+ Builder.CreateStructGEP(addr, 2, "byref.flags"));
+
+ CharUnits byrefSize = CGM.GetTargetTypeStoreSize(byrefType);
+ V = llvm::ConstantInt::get(IntTy, byrefSize.getQuantity());
+ Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size"));
+
+ if (helpers) {
+ llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4);
+ Builder.CreateStore(helpers->CopyHelper, copy_helper);
+
+ llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5);
+ Builder.CreateStore(helpers->DisposeHelper, destroy_helper);
+ }
}
void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) {
@@ -1413,3 +1638,26 @@ void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) {
N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask());
Builder.CreateCall2(F, V, N);
}
+
+namespace {
+ struct CallBlockRelease : EHScopeStack::Cleanup {
+ llvm::Value *Addr;
+ CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {}
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF);
+ }
+ };
+}
+
+/// Enter a cleanup to destroy a __block variable. Note that this
+/// cleanup should be a no-op if the variable hasn't left the stack
+/// yet; if a cleanup is required for the variable itself, that needs
+/// to be done externally.
+void CodeGenFunction::enterByrefCleanup(const AutoVarEmission &emission) {
+ // We don't enter this cleanup if we're in pure-GC mode.
+ if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ return;
+
+ EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address);
+}
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 0bc8bcaa14f9..9bd18e5fde74 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -173,6 +173,10 @@ public:
/// need to be run even in GC mode.
bool HasCXXObject : 1;
+ /// UsesStret : True if the block uses an stret return. Mutable
+ /// because it gets set later in the block-creation process.
+ mutable bool UsesStret : 1;
+
const llvm::StructType *StructureType;
const BlockExpr *Block;
CharUnits BlockSize;
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 5eeb605f18ee..7a0c8da50248 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -176,7 +176,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E) {
// See if we can constant fold this builtin. If so, don't emit it at all.
Expr::EvalResult Result;
- if (E->Evaluate(Result, CGM.getContext())) {
+ if (E->Evaluate(Result, CGM.getContext()) &&
+ !Result.hasSideEffects()) {
if (Result.Val.isInt())
return RValue::get(llvm::ConstantInt::get(getLLVMContext(),
Result.Val.getInt()));
@@ -312,9 +313,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__builtin_expect: {
// FIXME: pass expect through to LLVM
+ Value *ArgValue = EmitScalarExpr(E->getArg(0));
if (E->getArg(1)->HasSideEffects(getContext()))
(void)EmitScalarExpr(E->getArg(1));
- return RValue::get(EmitScalarExpr(E->getArg(0)));
+ return RValue::get(ArgValue);
}
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64: {
@@ -473,7 +475,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
BasicBlock *End = createBasicBlock("fpclassify_end", this->CurFn);
Builder.SetInsertPoint(End);
PHINode *Result =
- Builder.CreatePHI(ConvertType(E->getArg(0)->getType()),
+ Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 4,
"fpclassify_result");
// if (V==0) return FP_ZERO
@@ -543,6 +545,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Address);
}
+ case Builtin::BI__builtin___memcpy_chk: {
+ // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
+ if (!E->getArg(2)->isEvaluatable(CGM.getContext()) ||
+ !E->getArg(3)->isEvaluatable(CGM.getContext()))
+ break;
+ llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext());
+ llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext());
+ if (Size.ugt(DstSize))
+ break;
+ Value *Dest = EmitScalarExpr(E->getArg(0));
+ Value *Src = EmitScalarExpr(E->getArg(1));
+ Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
+ Builder.CreateMemCpy(Dest, Src, SizeVal, 1, false);
+ return RValue::get(Dest);
+ }
+
case Builtin::BI__builtin_objc_memmove_collectable: {
Value *Address = EmitScalarExpr(E->getArg(0));
Value *SrcAddr = EmitScalarExpr(E->getArg(1));
@@ -551,7 +569,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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.
+ if (!E->getArg(2)->isEvaluatable(CGM.getContext()) ||
+ !E->getArg(3)->isEvaluatable(CGM.getContext()))
+ break;
+ llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext());
+ llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext());
+ if (Size.ugt(DstSize))
+ break;
+ Value *Dest = EmitScalarExpr(E->getArg(0));
+ Value *Src = EmitScalarExpr(E->getArg(1));
+ Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
+ Builder.CreateMemMove(Dest, Src, SizeVal, 1, false);
+ return RValue::get(Dest);
+ }
+
case Builtin::BImemmove:
case Builtin::BI__builtin_memmove: {
Value *Address = EmitScalarExpr(E->getArg(0));
@@ -569,6 +603,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false);
return RValue::get(Address);
}
+ case Builtin::BI__builtin___memset_chk: {
+ // fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2.
+ if (!E->getArg(2)->isEvaluatable(CGM.getContext()) ||
+ !E->getArg(3)->isEvaluatable(CGM.getContext()))
+ break;
+ llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext());
+ llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext());
+ if (Size.ugt(DstSize))
+ break;
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
+ Builder.getInt8Ty());
+ Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
+ Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false);
+
+ return RValue::get(Address);
+ }
case Builtin::BI__builtin_dwarf_cfa: {
// The offset in bytes from the first argument to the CFA.
//
@@ -721,6 +772,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_release:
+ case Builtin::BI__sync_swap:
assert(0 && "Shouldn't make it through sema");
case Builtin::BI__sync_fetch_and_add_1:
case Builtin::BI__sync_fetch_and_add_2:
@@ -860,6 +912,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
+ case Builtin::BI__sync_swap_1:
+ case Builtin::BI__sync_swap_2:
+ case Builtin::BI__sync_swap_4:
+ case Builtin::BI__sync_swap_8:
+ case Builtin::BI__sync_swap_16:
+ return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E);
+
case Builtin::BI__sync_lock_test_and_set_1:
case Builtin::BI__sync_lock_test_and_set_2:
case Builtin::BI__sync_lock_test_and_set_4:
@@ -948,8 +1007,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return EmitCall(E->getCallee()->getType(),
CGM.getBuiltinLibFunction(FD, BuiltinID),
- ReturnValueSlot(),
- E->arg_begin(), E->arg_end());
+ ReturnValueSlot(), E->arg_begin(), E->arg_end(), FD);
// See if we have a target specific intrinsic.
const char *Name = getContext().BuiltinInfo.GetName(BuiltinID);
@@ -1116,13 +1174,16 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
if (BuiltinID == ARM::BI__clear_cache) {
const FunctionDecl *FD = E->getDirectCallee();
- Value *a = EmitScalarExpr(E->getArg(0));
- Value *b = EmitScalarExpr(E->getArg(1));
+ // Oddly people write this call without args on occasion and gcc accepts
+ // it - it's also marked as varargs in the description file.
+ llvm::SmallVector<Value*, 2> Ops;
+ for (unsigned i = 0; i < E->getNumArgs(); i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
const llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
llvm::StringRef Name = FD->getName();
- return Builder.CreateCall2(CGM.CreateRuntimeFunction(FTy, Name),
- a, b);
+ return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
+ Ops.begin(), Ops.end());
}
llvm::SmallVector<Value*, 4> Ops;
@@ -1462,9 +1523,9 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmulp, &Ty, 1),
Ops, "vmul");
case ARM::BI__builtin_neon_vmull_v:
- assert(poly && "vmull builtin only supported for polynomial types");
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmullp, &Ty, 1),
- Ops, "vmull");
+ Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
+ Int = poly ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
+ return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmull");
case ARM::BI__builtin_neon_vpadal_v:
case ARM::BI__builtin_neon_vpadalq_v: {
Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals;
@@ -2082,6 +2143,149 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
+ case X86::BI__builtin_ia32_loaddqu: {
+ const llvm::Type *VecTy = ConvertType(E->getType());
+ const llvm::Type *IntTy = llvm::IntegerType::get(getLLVMContext(), 128);
+
+ Value *BC = Builder.CreateBitCast(Ops[0],
+ llvm::PointerType::getUnqual(IntTy),
+ "cast");
+ LoadInst *LI = Builder.CreateLoad(BC);
+ LI->setAlignment(1); // Unaligned load.
+ return Builder.CreateBitCast(LI, VecTy, "loadu.cast");
+ }
+ // 3DNow!
+ case X86::BI__builtin_ia32_pavgusb:
+ case X86::BI__builtin_ia32_pf2id:
+ case X86::BI__builtin_ia32_pfacc:
+ case X86::BI__builtin_ia32_pfadd:
+ case X86::BI__builtin_ia32_pfcmpeq:
+ case X86::BI__builtin_ia32_pfcmpge:
+ case X86::BI__builtin_ia32_pfcmpgt:
+ case X86::BI__builtin_ia32_pfmax:
+ case X86::BI__builtin_ia32_pfmin:
+ case X86::BI__builtin_ia32_pfmul:
+ case X86::BI__builtin_ia32_pfrcp:
+ case X86::BI__builtin_ia32_pfrcpit1:
+ case X86::BI__builtin_ia32_pfrcpit2:
+ case X86::BI__builtin_ia32_pfrsqrt:
+ case X86::BI__builtin_ia32_pfrsqit1:
+ case X86::BI__builtin_ia32_pfrsqrtit1:
+ case X86::BI__builtin_ia32_pfsub:
+ case X86::BI__builtin_ia32_pfsubr:
+ case X86::BI__builtin_ia32_pi2fd:
+ case X86::BI__builtin_ia32_pmulhrw:
+ case X86::BI__builtin_ia32_pf2iw:
+ case X86::BI__builtin_ia32_pfnacc:
+ case X86::BI__builtin_ia32_pfpnacc:
+ case X86::BI__builtin_ia32_pi2fw:
+ case X86::BI__builtin_ia32_pswapdsf:
+ case X86::BI__builtin_ia32_pswapdsi: {
+ const char *name = 0;
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+ switch(BuiltinID) {
+ case X86::BI__builtin_ia32_pavgusb:
+ name = "pavgusb";
+ ID = Intrinsic::x86_3dnow_pavgusb;
+ break;
+ case X86::BI__builtin_ia32_pf2id:
+ name = "pf2id";
+ ID = Intrinsic::x86_3dnow_pf2id;
+ break;
+ case X86::BI__builtin_ia32_pfacc:
+ name = "pfacc";
+ ID = Intrinsic::x86_3dnow_pfacc;
+ break;
+ case X86::BI__builtin_ia32_pfadd:
+ name = "pfadd";
+ ID = Intrinsic::x86_3dnow_pfadd;
+ break;
+ case X86::BI__builtin_ia32_pfcmpeq:
+ name = "pfcmpeq";
+ ID = Intrinsic::x86_3dnow_pfcmpeq;
+ break;
+ case X86::BI__builtin_ia32_pfcmpge:
+ name = "pfcmpge";
+ ID = Intrinsic::x86_3dnow_pfcmpge;
+ break;
+ case X86::BI__builtin_ia32_pfcmpgt:
+ name = "pfcmpgt";
+ ID = Intrinsic::x86_3dnow_pfcmpgt;
+ break;
+ case X86::BI__builtin_ia32_pfmax:
+ name = "pfmax";
+ ID = Intrinsic::x86_3dnow_pfmax;
+ break;
+ case X86::BI__builtin_ia32_pfmin:
+ name = "pfmin";
+ ID = Intrinsic::x86_3dnow_pfmin;
+ break;
+ case X86::BI__builtin_ia32_pfmul:
+ name = "pfmul";
+ ID = Intrinsic::x86_3dnow_pfmul;
+ break;
+ case X86::BI__builtin_ia32_pfrcp:
+ name = "pfrcp";
+ ID = Intrinsic::x86_3dnow_pfrcp;
+ break;
+ case X86::BI__builtin_ia32_pfrcpit1:
+ name = "pfrcpit1";
+ ID = Intrinsic::x86_3dnow_pfrcpit1;
+ break;
+ case X86::BI__builtin_ia32_pfrcpit2:
+ name = "pfrcpit2";
+ ID = Intrinsic::x86_3dnow_pfrcpit2;
+ break;
+ case X86::BI__builtin_ia32_pfrsqrt:
+ name = "pfrsqrt";
+ ID = Intrinsic::x86_3dnow_pfrsqrt;
+ break;
+ case X86::BI__builtin_ia32_pfrsqit1:
+ case X86::BI__builtin_ia32_pfrsqrtit1:
+ name = "pfrsqit1";
+ ID = Intrinsic::x86_3dnow_pfrsqit1;
+ break;
+ case X86::BI__builtin_ia32_pfsub:
+ name = "pfsub";
+ ID = Intrinsic::x86_3dnow_pfsub;
+ break;
+ case X86::BI__builtin_ia32_pfsubr:
+ name = "pfsubr";
+ ID = Intrinsic::x86_3dnow_pfsubr;
+ break;
+ case X86::BI__builtin_ia32_pi2fd:
+ name = "pi2fd";
+ ID = Intrinsic::x86_3dnow_pi2fd;
+ break;
+ case X86::BI__builtin_ia32_pmulhrw:
+ name = "pmulhrw";
+ ID = Intrinsic::x86_3dnow_pmulhrw;
+ break;
+ case X86::BI__builtin_ia32_pf2iw:
+ name = "pf2iw";
+ ID = Intrinsic::x86_3dnowa_pf2iw;
+ break;
+ case X86::BI__builtin_ia32_pfnacc:
+ name = "pfnacc";
+ ID = Intrinsic::x86_3dnowa_pfnacc;
+ break;
+ case X86::BI__builtin_ia32_pfpnacc:
+ name = "pfpnacc";
+ ID = Intrinsic::x86_3dnowa_pfpnacc;
+ break;
+ case X86::BI__builtin_ia32_pi2fw:
+ name = "pi2fw";
+ ID = Intrinsic::x86_3dnowa_pi2fw;
+ break;
+ case X86::BI__builtin_ia32_pswapdsf:
+ case X86::BI__builtin_ia32_pswapdsi:
+ name = "pswapd";
+ ID = Intrinsic::x86_3dnowa_pswapd;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name);
+ }
}
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 7ffc6e732554..184147cb728d 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -194,39 +194,44 @@ void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
EmitGlobal(GlobalDecl(D, Ctor_Base));
}
-void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
- CXXCtorType Type) {
+void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
+ CXXCtorType ctorType) {
// The complete constructor is equivalent to the base constructor
// for classes with no virtual bases. Try to emit it as an alias.
- if (Type == Ctor_Complete &&
- !D->getParent()->getNumVBases() &&
- !TryEmitDefinitionAsAlias(GlobalDecl(D, Ctor_Complete),
- GlobalDecl(D, Ctor_Base)))
+ if (ctorType == Ctor_Complete &&
+ !ctor->getParent()->getNumVBases() &&
+ !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
+ GlobalDecl(ctor, Ctor_Base)))
return;
- llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXConstructor(D, Type));
- setFunctionLinkage(D, Fn);
+ const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(ctor, ctorType);
- CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
+ llvm::Function *fn =
+ cast<llvm::Function>(GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo));
+ setFunctionLinkage(ctor, fn);
- SetFunctionDefinitionAttributes(D, Fn);
- SetLLVMFunctionAttributesForDefinition(D, Fn);
+ CodeGenFunction(*this).GenerateCode(GlobalDecl(ctor, ctorType), fn, fnInfo);
+
+ SetFunctionDefinitionAttributes(ctor, fn);
+ SetLLVMFunctionAttributesForDefinition(ctor, fn);
}
llvm::GlobalValue *
-CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
- CXXCtorType Type) {
- GlobalDecl GD(D, Type);
+CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
+ CXXCtorType ctorType,
+ const CGFunctionInfo *fnInfo) {
+ GlobalDecl GD(ctor, ctorType);
- llvm::StringRef Name = getMangledName(GD);
- if (llvm::GlobalValue *V = GetGlobalValue(Name))
- return V;
-
- const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
- const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type),
- FPT->isVariadic());
- return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FTy, GD,
+ llvm::StringRef name = getMangledName(GD);
+ if (llvm::GlobalValue *existing = GetGlobalValue(name))
+ return existing;
+
+ if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(ctor, ctorType);
+
+ const FunctionProtoType *proto = ctor->getType()->castAs<FunctionProtoType>();
+ const llvm::FunctionType *fnType =
+ getTypes().GetFunctionType(*fnInfo, proto->isVariadic());
+ return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
}
@@ -246,45 +251,51 @@ void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
EmitGlobal(GlobalDecl(D, Dtor_Base));
}
-void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
- CXXDtorType Type) {
+void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
+ CXXDtorType dtorType) {
// The complete destructor is equivalent to the base destructor for
// classes with no virtual bases, so try to emit it as an alias.
- if (Type == Dtor_Complete &&
- !D->getParent()->getNumVBases() &&
- !TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Complete),
- GlobalDecl(D, Dtor_Base)))
+ if (dtorType == Dtor_Complete &&
+ !dtor->getParent()->getNumVBases() &&
+ !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete),
+ GlobalDecl(dtor, Dtor_Base)))
return;
// The base destructor is equivalent to the base destructor of its
// base class if there is exactly one non-virtual base class with a
// non-trivial destructor, there are no fields with a non-trivial
// destructor, and the body of the destructor is trivial.
- if (Type == Dtor_Base && !TryEmitBaseDestructorAsAlias(D))
+ if (dtorType == Dtor_Base && !TryEmitBaseDestructorAsAlias(dtor))
return;
- llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type));
- setFunctionLinkage(D, Fn);
+ const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(dtor, dtorType);
- CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
+ llvm::Function *fn =
+ cast<llvm::Function>(GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo));
+ setFunctionLinkage(dtor, fn);
- SetFunctionDefinitionAttributes(D, Fn);
- SetLLVMFunctionAttributesForDefinition(D, Fn);
+ CodeGenFunction(*this).GenerateCode(GlobalDecl(dtor, dtorType), fn, fnInfo);
+
+ SetFunctionDefinitionAttributes(dtor, fn);
+ SetLLVMFunctionAttributesForDefinition(dtor, fn);
}
llvm::GlobalValue *
-CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
- CXXDtorType Type) {
- GlobalDecl GD(D, Type);
+CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
+ CXXDtorType dtorType,
+ const CGFunctionInfo *fnInfo) {
+ GlobalDecl GD(dtor, dtorType);
+
+ llvm::StringRef name = getMangledName(GD);
+ if (llvm::GlobalValue *existing = GetGlobalValue(name))
+ return existing;
- llvm::StringRef Name = getMangledName(GD);
- if (llvm::GlobalValue *V = GetGlobalValue(Name))
- return V;
+ if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(dtor, dtorType);
- const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false);
+ const llvm::FunctionType *fnType =
+ getTypes().GetFunctionType(*fnInfo, false);
- return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FTy, GD,
+ return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
}
@@ -334,7 +345,7 @@ CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
MD = MD->getCanonicalDecl();
uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD);
uint64_t AddressPoint =
- CGM.getVTables().getAddressPoint(BaseSubobject(RD, 0), RD);
+ CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD);
VTableIndex += AddressPoint;
llvm::Value *VFuncPtr =
Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
@@ -369,7 +380,7 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
uint64_t VTableIndex =
CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type));
uint64_t AddressPoint =
- CGM.getVTables().getAddressPoint(BaseSubobject(RD, 0), RD);
+ CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD);
VTableIndex += AddressPoint;
llvm::Value *VFuncPtr =
Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 8373b660b2f4..92f1c63a3829 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -115,7 +115,7 @@ bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
return true;
}
-void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params) {
+void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &params) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
// FIXME: I'm not entirely sure I like using a fake decl just for code
@@ -124,7 +124,7 @@ void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params) {
= ImplicitParamDecl::Create(CGM.getContext(), 0, MD->getLocation(),
&CGM.getContext().Idents.get("this"),
MD->getThisType(CGM.getContext()));
- Params.push_back(std::make_pair(ThisDecl, ThisDecl->getType()));
+ params.push_back(ThisDecl);
getThisDecl(CGF) = ThisDecl;
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index ae84b6196dfa..a765f0f3439a 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -36,6 +36,8 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_X86StdCall: return llvm::CallingConv::X86_StdCall;
case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
+ case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
+ case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
// TODO: add support for CC_X86Pascal to llvm
}
}
@@ -104,6 +106,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
if (D->hasAttr<PascalAttr>())
return CC_X86Pascal;
+ if (PcsAttr *PCS = D->getAttr<PcsAttr>())
+ return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP);
+
return CC_C;
}
@@ -188,6 +193,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
ArgTys,
FunctionType::ExtInfo(
/*NoReturn*/ false,
+ /*HasRegParm*/ false,
/*RegParm*/ 0,
getCallingConventionForDecl(MD)));
}
@@ -212,7 +218,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
llvm::SmallVector<CanQualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
- ArgTys.push_back(Context.getCanonicalParamType(i->second));
+ ArgTys.push_back(Context.getCanonicalParamType(i->Ty));
return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
}
@@ -223,10 +229,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
llvm::SmallVector<CanQualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
- ArgTys.push_back(Context.getCanonicalParamType(i->second));
+ ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
}
+const CGFunctionInfo &CodeGenTypes::getNullaryFunctionInfo() {
+ llvm::SmallVector<CanQualType, 1> args;
+ return getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo());
+}
+
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys,
const FunctionType::ExtInfo &Info,
@@ -250,7 +261,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
return *FI;
// Construct the function info.
- FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getRegParm(), ResTy,
+ FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getHasRegParm(), Info.getRegParm(), ResTy,
ArgTys.data(), ArgTys.size());
FunctionInfos.InsertNode(FI, InsertPos);
@@ -279,13 +290,13 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
}
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
- bool _NoReturn, unsigned _RegParm,
+ bool _NoReturn, bool _HasRegParm, unsigned _RegParm,
CanQualType ResTy,
const CanQualType *ArgTys,
unsigned NumArgTys)
: CallingConvention(_CallingConvention),
EffectiveCallingConvention(_CallingConvention),
- NoReturn(_NoReturn), RegParm(_RegParm)
+ NoReturn(_NoReturn), HasRegParm(_HasRegParm), RegParm(_RegParm)
{
NumArgs = NumArgTys;
@@ -622,7 +633,8 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
assert(!RetAI.getIndirectAlign() && "Align unused on indirect return.");
ResultType = llvm::Type::getVoidTy(getLLVMContext());
const llvm::Type *STy = ConvertType(RetTy, IsRecursive);
- ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace()));
+ unsigned AS = Context.getTargetAddressSpace(RetTy);
+ ArgTys.push_back(llvm::PointerType::get(STy, AS));
break;
}
@@ -704,7 +716,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs |= llvm::Attribute::NoUnwind;
else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
- if (FPT && FPT->hasEmptyExceptionSpec())
+ if (FPT && FPT->isNothrow(getContext()))
FuncAttrs |= llvm::Attribute::NoUnwind;
}
@@ -756,8 +768,10 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs));
// FIXME: RegParm should be reduced in case of global register variable.
- signed RegParm = FI.getRegParm();
- if (!RegParm)
+ signed RegParm;
+ if (FI.getHasRegParm())
+ RegParm = FI.getRegParm();
+ else
RegParm = CodeGenOpts.NumRegisterParameters;
unsigned PointerWidth = getContext().Target.getPointerWidth(0);
@@ -826,6 +840,26 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs));
}
+/// An argument came in as a promoted argument; demote it back to its
+/// declared type.
+static llvm::Value *emitArgumentDemotion(CodeGenFunction &CGF,
+ const VarDecl *var,
+ llvm::Value *value) {
+ const llvm::Type *varType = CGF.ConvertType(var->getType());
+
+ // This can happen with promotions that actually don't change the
+ // underlying type, like the enum promotions.
+ if (value->getType() == varType) return value;
+
+ assert((varType->isIntegerTy() || varType->isFloatingPointTy())
+ && "unexpected promotion type");
+
+ if (isa<llvm::IntegerType>(varType))
+ return CGF.Builder.CreateTrunc(value, varType, "arg.unpromote");
+
+ return CGF.Builder.CreateFPCast(value, varType, "arg.unpromote");
+}
+
void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Function *Fn,
const FunctionArgList &Args) {
@@ -856,13 +890,17 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
assert(FI.arg_size() == Args.size() &&
"Mismatch between function signature & arguments.");
+ unsigned ArgNo = 1;
CGFunctionInfo::const_arg_iterator info_it = FI.arg_begin();
- for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
- i != e; ++i, ++info_it) {
- const VarDecl *Arg = i->first;
+ for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ i != e; ++i, ++info_it, ++ArgNo) {
+ const VarDecl *Arg = *i;
QualType Ty = info_it->type;
const ABIArgInfo &ArgI = info_it->info;
+ bool isPromoted =
+ isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted();
+
switch (ArgI.getKind()) {
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
@@ -880,8 +918,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// copy.
const llvm::Type *I8PtrTy = Builder.getInt8PtrTy();
CharUnits Size = getContext().getTypeSizeInChars(Ty);
- Builder.CreateMemCpy(Builder.CreateBitCast(AlignedTemp, I8PtrTy),
- Builder.CreateBitCast(V, I8PtrTy),
+ llvm::Value *Dst = Builder.CreateBitCast(AlignedTemp, I8PtrTy);
+ llvm::Value *Src = Builder.CreateBitCast(V, I8PtrTy);
+ Builder.CreateMemCpy(Dst,
+ Src,
llvm::ConstantInt::get(IntPtrTy,
Size.getQuantity()),
ArgI.getIndirectAlign(),
@@ -892,13 +932,11 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Load scalar value from indirect argument.
CharUnits Alignment = getContext().getTypeAlignInChars(Ty);
V = EmitLoadOfScalar(V, false, Alignment.getQuantity(), Ty);
- if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
- // This must be a promotion, for something like
- // "void a(x) short x; {..."
- V = EmitScalarConversion(V, Ty, Arg->getType());
- }
+
+ if (isPromoted)
+ V = emitArgumentDemotion(*this, Arg, V);
}
- EmitParmDecl(*Arg, V);
+ EmitParmDecl(*Arg, V, ArgNo);
break;
}
@@ -914,12 +952,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (Arg->getType().isRestrictQualified())
AI->addAttr(llvm::Attribute::NoAlias);
- if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
- // This must be a promotion, for something like
- // "void a(x) short x; {..."
- V = EmitScalarConversion(V, Ty, Arg->getType());
- }
- EmitParmDecl(*Arg, V);
+ if (isPromoted)
+ V = emitArgumentDemotion(*this, Arg, V);
+
+ EmitParmDecl(*Arg, V, ArgNo);
break;
}
@@ -968,13 +1004,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Match to what EmitParmDecl is expecting for this type.
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty);
- if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
- // This must be a promotion, for something like
- // "void a(x) short x; {..."
- V = EmitScalarConversion(V, Ty, Arg->getType());
- }
+ if (isPromoted)
+ V = emitArgumentDemotion(*this, Arg, V);
}
- EmitParmDecl(*Arg, V);
+ EmitParmDecl(*Arg, V, ArgNo);
continue; // Skip ++AI increment, already done.
}
@@ -985,7 +1018,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr");
llvm::Function::arg_iterator End =
ExpandTypeFromArgs(Ty, MakeAddrLValue(Temp, Ty), AI);
- EmitParmDecl(*Arg, Temp);
+ EmitParmDecl(*Arg, Temp, ArgNo);
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
@@ -997,9 +1030,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
if (hasAggregateLLVMType(Ty))
- EmitParmDecl(*Arg, CreateMemTemp(Ty));
+ EmitParmDecl(*Arg, CreateMemTemp(Ty), ArgNo);
else
- EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())));
+ EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())),
+ ArgNo);
// Skip increment, no matching LLVM parameter.
continue;
@@ -1091,42 +1125,48 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
Ret->setDebugLoc(RetDbgLoc);
}
-RValue CodeGenFunction::EmitDelegateCallArg(const VarDecl *Param) {
+void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
+ const VarDecl *param) {
// StartFunction converted the ABI-lowered parameter(s) into a
// local alloca. We need to turn that into an r-value suitable
// for EmitCall.
- llvm::Value *Local = GetAddrOfLocalVar(Param);
+ llvm::Value *local = GetAddrOfLocalVar(param);
- QualType ArgType = Param->getType();
+ QualType type = param->getType();
// For the most part, we just need to load the alloca, except:
// 1) aggregate r-values are actually pointers to temporaries, and
// 2) references to aggregates are pointers directly to the aggregate.
// I don't know why references to non-aggregates are different here.
- if (const ReferenceType *RefType = ArgType->getAs<ReferenceType>()) {
- if (hasAggregateLLVMType(RefType->getPointeeType()))
- return RValue::getAggregate(Local);
+ if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
+ if (hasAggregateLLVMType(ref->getPointeeType()))
+ return args.add(RValue::getAggregate(local), type);
// Locals which are references to scalars are represented
// with allocas holding the pointer.
- return RValue::get(Builder.CreateLoad(Local));
+ return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
- if (ArgType->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(Local, /*volatile*/ false));
+ if (type->isAnyComplexType()) {
+ ComplexPairTy complex = LoadComplexFromAddr(local, /*volatile*/ false);
+ return args.add(RValue::getComplex(complex), type);
+ }
- if (hasAggregateLLVMType(ArgType))
- return RValue::getAggregate(Local);
+ if (hasAggregateLLVMType(type))
+ return args.add(RValue::getAggregate(local), type);
- unsigned Alignment = getContext().getDeclAlign(Param).getQuantity();
- return RValue::get(EmitLoadOfScalar(Local, false, Alignment, ArgType));
+ unsigned alignment = getContext().getDeclAlign(param).getQuantity();
+ llvm::Value *value = EmitLoadOfScalar(local, false, alignment, type);
+ return args.add(RValue::get(value), type);
}
-RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
- if (ArgType->isReferenceType())
- return EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
+void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
+ QualType type) {
+ if (type->isReferenceType())
+ return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
+ type);
- return EmitAnyExprToTemp(E);
+ args.add(EmitAnyExprToTemp(E), type);
}
/// Emits a call or invoke instruction to the given function, depending
@@ -1177,18 +1217,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end();
I != E; ++I, ++info_it) {
const ABIArgInfo &ArgInfo = info_it->info;
- RValue RV = I->first;
+ RValue RV = I->RV;
unsigned Alignment =
- getContext().getTypeAlignInChars(I->second).getQuantity();
+ getContext().getTypeAlignInChars(I->Ty).getQuantity();
switch (ArgInfo.getKind()) {
case ABIArgInfo::Indirect: {
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
- Args.push_back(CreateMemTemp(I->second));
+ Args.push_back(CreateMemTemp(I->Ty));
if (RV.isScalar())
EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false,
- Alignment, I->second);
+ Alignment, I->Ty);
else
StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
} else {
@@ -1215,11 +1255,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: Avoid the conversion through memory if possible.
llvm::Value *SrcPtr;
if (RV.isScalar()) {
- SrcPtr = CreateMemTemp(I->second, "coerce");
- EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, Alignment,
- I->second);
+ SrcPtr = CreateMemTemp(I->Ty, "coerce");
+ EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, Alignment, I->Ty);
} else if (RV.isComplex()) {
- SrcPtr = CreateMemTemp(I->second, "coerce");
+ SrcPtr = CreateMemTemp(I->Ty, "coerce");
StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
} else
SrcPtr = RV.getAggregateAddr();
@@ -1257,7 +1296,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
case ABIArgInfo::Expand:
- ExpandTypeToArgs(I->second, RV, Args);
+ ExpandTypeToArgs(I->Ty, RV, Args);
break;
}
}
@@ -1275,7 +1314,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (CE->getOpcode() == llvm::Instruction::BitCast &&
ActualFT->getReturnType() == CurFT->getReturnType() &&
ActualFT->getNumParams() == CurFT->getNumParams() &&
- ActualFT->getNumParams() == Args.size()) {
+ ActualFT->getNumParams() == Args.size() &&
+ (CurFT->isVarArg() || !ActualFT->isVarArg())) {
bool ArgsMatch = true;
for (unsigned i = 0, e = ActualFT->getNumParams(); i != e; ++i)
if (ActualFT->getParamType(i) != CurFT->getParamType(i)) {
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 41e707a204ca..3f600c04e59d 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -44,15 +44,29 @@ namespace clang {
namespace CodeGen {
typedef llvm::SmallVector<llvm::AttributeWithIndex, 8> AttributeListType;
+ struct CallArg {
+ RValue RV;
+ QualType Ty;
+ CallArg(RValue rv, QualType ty)
+ : RV(rv), Ty(ty)
+ { }
+ };
+
/// CallArgList - Type for representing both the value and type of
/// arguments in a call.
- typedef llvm::SmallVector<std::pair<RValue, QualType>, 16> CallArgList;
+ class CallArgList :
+ public llvm::SmallVector<CallArg, 16> {
+ public:
+ void add(RValue rvalue, QualType type) {
+ push_back(CallArg(rvalue, type));
+ }
+ };
/// FunctionArgList - Type for representing both the decl and type
/// of parameters to a function. The decl must be either a
/// ParmVarDecl or ImplicitParamDecl.
- typedef llvm::SmallVector<std::pair<const VarDecl*, QualType>,
- 16> FunctionArgList;
+ class FunctionArgList : public llvm::SmallVector<const VarDecl*, 16> {
+ };
/// CGFunctionInfo - Class to encapsulate the information about a
/// function definition.
@@ -77,6 +91,7 @@ namespace CodeGen {
ArgInfo *Args;
/// How many arguments to pass inreg.
+ bool HasRegParm;
unsigned RegParm;
public:
@@ -84,7 +99,7 @@ namespace CodeGen {
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention, bool NoReturn,
- unsigned RegParm, CanQualType ResTy,
+ bool HasRegParm, unsigned RegParm, CanQualType ResTy,
const CanQualType *ArgTys, unsigned NumArgTys);
~CGFunctionInfo() { delete[] Args; }
@@ -110,6 +125,7 @@ namespace CodeGen {
EffectiveCallingConvention = Value;
}
+ bool getHasRegParm() const { return HasRegParm; }
unsigned getRegParm() const { return RegParm; }
CanQualType getReturnType() const { return Args[0].type; }
@@ -120,6 +136,7 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
ID.AddBoolean(NoReturn);
+ ID.AddBoolean(HasRegParm);
ID.AddInteger(RegParm);
getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
@@ -133,6 +150,7 @@ namespace CodeGen {
Iterator end) {
ID.AddInteger(Info.getCC());
ID.AddBoolean(Info.getNoReturn());
+ ID.AddBoolean(Info.getHasRegParm());
ID.AddInteger(Info.getRegParm());
ResTy.Profile(ID);
for (; begin != end; ++begin) {
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index cd28bbe44db5..ca8b6576c7ad 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -22,12 +22,12 @@
using namespace clang;
using namespace CodeGen;
-static uint64_t
+static CharUnits
ComputeNonVirtualBaseClassOffset(ASTContext &Context,
const CXXRecordDecl *DerivedClass,
CastExpr::path_const_iterator Start,
CastExpr::path_const_iterator End) {
- uint64_t Offset = 0;
+ CharUnits Offset = CharUnits::Zero();
const CXXRecordDecl *RD = DerivedClass;
@@ -42,13 +42,12 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context,
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
// Add the offset.
- Offset += Layout.getBaseClassOffsetInBits(BaseDecl);
+ Offset += Layout.getBaseClassOffset(BaseDecl);
RD = BaseDecl;
}
- // FIXME: We should not use / 8 here.
- return Offset / 8;
+ return Offset;
}
llvm::Constant *
@@ -57,16 +56,16 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
CastExpr::path_const_iterator PathEnd) {
assert(PathBegin != PathEnd && "Base path should not be empty!");
- uint64_t Offset =
+ CharUnits Offset =
ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl,
PathBegin, PathEnd);
- if (!Offset)
+ if (Offset.isZero())
return 0;
const llvm::Type *PtrDiffTy =
Types.ConvertType(getContext().getPointerDiffType());
- return llvm::ConstantInt::get(PtrDiffTy, Offset);
+ return llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity());
}
/// Gets the address of a direct base class within a complete object.
@@ -85,20 +84,20 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
== ConvertType(Derived));
// Compute the offset of the virtual base.
- uint64_t Offset;
+ CharUnits Offset;
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
if (BaseIsVirtual)
- Offset = Layout.getVBaseClassOffsetInBits(Base);
+ Offset = Layout.getVBaseClassOffset(Base);
else
- Offset = Layout.getBaseClassOffsetInBits(Base);
+ Offset = Layout.getBaseClassOffset(Base);
// Shift and cast down to the base type.
// TODO: for complete types, this should be possible with a GEP.
llvm::Value *V = This;
- if (Offset) {
+ if (Offset.isPositive()) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
V = Builder.CreateBitCast(V, Int8PtrTy);
- V = Builder.CreateConstInBoundsGEP1_64(V, Offset / 8);
+ V = Builder.CreateConstInBoundsGEP1_64(V, Offset.getQuantity());
}
V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo());
@@ -107,13 +106,14 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
static llvm::Value *
ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
- uint64_t NonVirtual, llvm::Value *Virtual) {
+ CharUnits NonVirtual, llvm::Value *Virtual) {
const llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
llvm::Value *NonVirtualOffset = 0;
- if (NonVirtual)
- NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, NonVirtual);
+ if (!NonVirtual.isZero())
+ NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy,
+ NonVirtual.getQuantity());
llvm::Value *BaseOffset;
if (Virtual) {
@@ -150,7 +150,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
++Start;
}
- uint64_t NonVirtualOffset =
+ CharUnits NonVirtualOffset =
ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived,
Start, PathEnd);
@@ -158,7 +158,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
const llvm::Type *BasePtrTy =
ConvertType((PathEnd[-1])->getType())->getPointerTo();
- if (!NonVirtualOffset && !VBase) {
+ if (NonVirtualOffset.isZero() && !VBase) {
// Just cast back.
return Builder.CreateBitCast(Value, BasePtrTy);
}
@@ -172,9 +172,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
CastNotNull = createBasicBlock("cast.notnull");
CastEnd = createBasicBlock("cast.end");
- llvm::Value *IsNull =
- Builder.CreateICmpEQ(Value,
- llvm::Constant::getNullValue(Value->getType()));
+ llvm::Value *IsNull = Builder.CreateIsNull(Value);
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
EmitBlock(CastNotNull);
}
@@ -187,14 +185,15 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
- uint64_t VBaseOffset = Layout.getVBaseClassOffsetInBits(VBase);
- NonVirtualOffset += VBaseOffset / 8;
+ CharUnits VBaseOffset = Layout.getVBaseClassOffset(VBase);
+ NonVirtualOffset += VBaseOffset;
} else
VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
}
// Apply the offsets.
- Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset,
+ Value = ApplyNonVirtualAndVirtualOffset(*this, Value,
+ NonVirtualOffset,
VirtualOffset);
// Cast back.
@@ -206,8 +205,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
Builder.CreateBr(CastEnd);
EmitBlock(CastEnd);
- llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
- PHI->reserveOperandSpace(2);
+ llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2);
PHI->addIncoming(Value, CastNotNull);
PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
CastNull);
@@ -246,9 +244,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
CastNotNull = createBasicBlock("cast.notnull");
CastEnd = createBasicBlock("cast.end");
- llvm::Value *IsNull =
- Builder.CreateICmpEQ(Value,
- llvm::Constant::getNullValue(Value->getType()));
+ llvm::Value *IsNull = Builder.CreateIsNull(Value);
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
EmitBlock(CastNotNull);
}
@@ -267,8 +263,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
Builder.CreateBr(CastEnd);
EmitBlock(CastEnd);
- llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
- PHI->reserveOperandSpace(2);
+ llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2);
PHI->addIncoming(Value, CastNotNull);
PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
CastNull);
@@ -304,9 +299,9 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
} else {
const ASTRecordLayout &Layout =
CGF.getContext().getASTRecordLayout(RD);
- uint64_t BaseOffset = ForVirtualBase ?
- Layout.getVBaseClassOffsetInBits(Base) :
- Layout.getBaseClassOffsetInBits(Base);
+ CharUnits BaseOffset = ForVirtualBase ?
+ Layout.getVBaseClassOffset(Base) :
+ Layout.getBaseClassOffset(Base);
SubVTTIndex =
CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
@@ -407,7 +402,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
- if (CGF.CGM.getLangOptions().areExceptionsEnabled() &&
+ if (CGF.CGM.getLangOptions().Exceptions &&
!BaseClassDecl->hasTrivialDestructor())
CGF.EHStack.pushCleanup<CallBaseDtor>(EHCleanup, BaseClassDecl,
isBaseVirtual);
@@ -589,8 +584,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// we know we're in a copy constructor.
unsigned SrcArgIndex = Args.size() - 1;
llvm::Value *SrcPtr
- = CGF.Builder.CreateLoad(
- CGF.GetAddrOfLocalVar(Args[SrcArgIndex].first));
+ = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0);
// Copy the aggregate.
@@ -606,7 +600,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, FieldType, 0);
- if (!CGF.CGM.getLangOptions().areExceptionsEnabled())
+ if (!CGF.CGM.getLangOptions().Exceptions)
return;
// FIXME: If we have an array of classes w/ non-trivial destructors,
@@ -664,6 +658,10 @@ static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) {
if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic())
return false;
+ // FIXME: Decide if we can do a delegation of a delegating constructor.
+ if (Ctor->isDelegatingConstructor())
+ return false;
+
return true;
}
@@ -716,6 +714,9 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
CXXCtorType CtorType,
FunctionArgList &Args) {
+ if (CD->isDelegatingConstructor())
+ return EmitDelegatingCXXConstructorCall(CD, Args);
+
const CXXRecordDecl *ClassDecl = CD->getParent();
llvm::SmallVector<CXXCtorInitializer *, 8> MemberInitializers;
@@ -727,8 +728,10 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
if (Member->isBaseInitializer())
EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
- else
+ else if (Member->isAnyMemberInitializer())
MemberInitializers.push_back(Member);
+ else
+ llvm_unreachable("Delegating initializer on non-delegating constructor");
}
InitializeVTablePointers(ClassDecl);
@@ -1196,15 +1199,14 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
CallArgList Args;
// Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This),
- D->getThisType(getContext())));
+ Args.add(RValue::get(This), D->getThisType(getContext()));
// Push the src ptr.
QualType QT = *(FPT->arg_type_begin());
const llvm::Type *t = CGM.getTypes().ConvertType(QT);
Src = Builder.CreateBitCast(Src, t);
- Args.push_back(std::make_pair(RValue::get(Src), QT));
+ Args.add(RValue::get(Src), QT);
// Skip over first argument (Src).
++ArgBeg;
@@ -1212,9 +1214,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin()+1,
E = FPT->arg_type_end(); I != E; ++I, ++Arg) {
assert(Arg != ArgEnd && "Running over edge of argument list!");
- QualType ArgType = *I;
- Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
- ArgType));
+ EmitCallArg(Args, *Arg, *I);
}
// Either we've emitted all the call args, or we have a call to a
// variadic function.
@@ -1223,8 +1223,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
// If we still have any arguments, emit them using the type of the argument.
for (; Arg != ArgEnd; ++Arg) {
QualType ArgType = Arg->getType();
- Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
- ArgType));
+ EmitCallArg(Args, *Arg, ArgType);
}
QualType ResultType = FPT->getResultType();
@@ -1243,30 +1242,26 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
assert(I != E && "no parameters to constructor");
// this
- DelegateArgs.push_back(std::make_pair(RValue::get(LoadCXXThis()),
- I->second));
+ DelegateArgs.add(RValue::get(LoadCXXThis()), (*I)->getType());
++I;
// vtt
if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType),
/*ForVirtualBase=*/false)) {
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
- DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP));
+ DelegateArgs.add(RValue::get(VTT), VoidPP);
if (CodeGenVTables::needsVTTParameter(CurGD)) {
assert(I != E && "cannot skip vtt parameter, already done with args");
- assert(I->second == VoidPP && "skipping parameter not of vtt type");
+ assert((*I)->getType() == VoidPP && "skipping parameter not of vtt type");
++I;
}
}
// Explicit arguments.
for (; I != E; ++I) {
- const VarDecl *Param = I->first;
- QualType ArgType = Param->getType(); // because we're passing it to itself
- RValue Arg = EmitDelegateCallArg(Param);
-
- DelegateArgs.push_back(std::make_pair(Arg, ArgType));
+ const VarDecl *param = *I;
+ EmitDelegateCallArg(DelegateArgs, param);
}
EmitCall(CGM.getTypes().getFunctionInfo(Ctor, CtorType),
@@ -1274,6 +1269,19 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
ReturnValueSlot(), DelegateArgs, Ctor);
}
+void
+CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
+ const FunctionArgList &Args) {
+ assert(Ctor->isDelegatingConstructor());
+
+ llvm::Value *ThisPtr = LoadCXXThis();
+
+ AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
+
+ EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
+}
+
+
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
bool ForVirtualBase,
@@ -1317,6 +1325,7 @@ void CodeGenFunction::PushDestructorCleanup(QualType T, llvm::Value *Addr) {
if (ClassDecl->hasTrivialDestructor()) return;
const CXXDestructorDecl *D = ClassDecl->getDestructor();
+ assert(D && D->isUsed() && "destructor not marked as used!");
PushDestructorCleanup(D, Addr);
}
@@ -1325,11 +1334,12 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
llvm::Value *VTablePtr = GetVTablePtr(This, Int8PtrTy);
- int64_t VBaseOffsetOffset =
+ CharUnits VBaseOffsetOffset =
CGM.getVTables().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
llvm::Value *VBaseOffsetPtr =
- Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset, "vbase.offset.ptr");
+ Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(),
+ "vbase.offset.ptr");
const llvm::Type *PtrDiffTy =
ConvertType(getContext().getPointerDiffType());
@@ -1344,7 +1354,7 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
void
CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
const CXXRecordDecl *NearestVBase,
- uint64_t OffsetFromNearestVBase,
+ CharUnits OffsetFromNearestVBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass) {
const CXXRecordDecl *RD = Base.getBase();
@@ -1374,23 +1384,23 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
// Compute where to store the address point.
llvm::Value *VirtualOffset = 0;
- uint64_t NonVirtualOffset = 0;
+ CharUnits NonVirtualOffset = CharUnits::Zero();
if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) {
// We need to use the virtual base offset offset because the virtual base
// might have a different offset in the most derived class.
VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass,
NearestVBase);
- NonVirtualOffset = OffsetFromNearestVBase / 8;
+ NonVirtualOffset = OffsetFromNearestVBase;
} else {
// We can just use the base offset in the complete class.
- NonVirtualOffset = Base.getBaseOffset() / 8;
+ NonVirtualOffset = Base.getBaseOffset();
}
// Apply the offsets.
llvm::Value *VTableField = LoadCXXThis();
- if (NonVirtualOffset || VirtualOffset)
+ if (!NonVirtualOffset.isZero() || VirtualOffset)
VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField,
NonVirtualOffset,
VirtualOffset);
@@ -1405,7 +1415,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
void
CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
const CXXRecordDecl *NearestVBase,
- uint64_t OffsetFromNearestVBase,
+ CharUnits OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
@@ -1430,8 +1440,8 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
if (!BaseDecl->isDynamicClass())
continue;
- uint64_t BaseOffset;
- uint64_t BaseOffsetFromNearestVBase;
+ CharUnits BaseOffset;
+ CharUnits BaseOffsetFromNearestVBase;
bool BaseDeclIsNonVirtualPrimaryBase;
if (I->isVirtual()) {
@@ -1442,16 +1452,15 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
const ASTRecordLayout &Layout =
getContext().getASTRecordLayout(VTableClass);
- BaseOffset = Layout.getVBaseClassOffsetInBits(BaseDecl);
- BaseOffsetFromNearestVBase = 0;
+ BaseOffset = Layout.getVBaseClassOffset(BaseDecl);
+ BaseOffsetFromNearestVBase = CharUnits::Zero();
BaseDeclIsNonVirtualPrimaryBase = false;
} else {
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
- BaseOffset =
- Base.getBaseOffset() + Layout.getBaseClassOffsetInBits(BaseDecl);
+ BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
BaseOffsetFromNearestVBase =
- OffsetFromNearestVBase + Layout.getBaseClassOffsetInBits(BaseDecl);
+ OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl);
BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
}
@@ -1473,8 +1482,9 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
// Initialize the vtable pointers for this class and all of its bases.
VisitedVirtualBasesSetTy VBases;
- InitializeVTablePointers(BaseSubobject(RD, 0), /*NearestVBase=*/0,
- /*OffsetFromNearestVBase=*/0,
+ InitializeVTablePointers(BaseSubobject(RD, CharUnits::Zero()),
+ /*NearestVBase=*/0,
+ /*OffsetFromNearestVBase=*/CharUnits::Zero(),
/*BaseIsNonVirtualPrimaryBase=*/false,
VTable, RD, VBases);
}
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 1d7901a2db4c..41ecd8111790 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -870,6 +870,29 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
}
+/// isObviouslyBranchWithoutCleanups - Return true if a branch to the
+/// specified destination obviously has no cleanups to run. 'false' is always
+/// a conservatively correct answer for this method.
+bool CodeGenFunction::isObviouslyBranchWithoutCleanups(JumpDest Dest) const {
+ assert(Dest.getScopeDepth().encloses(EHStack.stable_begin())
+ && "stale jump destination");
+
+ // Calculate the innermost active normal cleanup.
+ EHScopeStack::stable_iterator TopCleanup =
+ EHStack.getInnermostActiveNormalCleanup();
+
+ // If we're not in an active normal cleanup scope, or if the
+ // destination scope is within the innermost active normal cleanup
+ // scope, we don't need to worry about fixups.
+ if (TopCleanup == EHStack.stable_end() ||
+ TopCleanup.encloses(Dest.getScopeDepth())) // works for invalid
+ return true;
+
+ // Otherwise, we might need some cleanups.
+ return false;
+}
+
+
/// Terminate the current block by emitting a branch which might leave
/// the current cleanup-protected scope. The target scope may not yet
/// be known, in which case this will require a fixup.
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index dfd9f56b12e3..f2e1c024dd05 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -119,6 +119,17 @@ llvm::StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
return llvm::StringRef(StrPtr, OS.tell());
}
+/// getSelectorName - Return selector name. This is used for debugging
+/// info.
+llvm::StringRef CGDebugInfo::getSelectorName(Selector S) {
+ llvm::SmallString<256> SName;
+ llvm::raw_svector_ostream OS(SName);
+ OS << S.getAsString();
+ char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell());
+ memcpy(StrPtr, SName.begin(), OS.tell());
+ return llvm::StringRef(StrPtr, OS.tell());
+}
+
/// getClassName - Get class name including template argument list.
llvm::StringRef
CGDebugInfo::getClassName(RecordDecl *RD) {
@@ -306,8 +317,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
DBuilder.createMemberType("isa", getOrCreateMainFile(),
0,Size, 0, 0, 0, ISATy);
EltTys.push_back(FieldTy);
- llvm::DIArray Elements =
- DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
return DBuilder.createStructType(TheCU, "objc_object",
getOrCreateMainFile(),
@@ -462,8 +472,8 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
- uint64_t Size =
- CGM.getContext().Target.getPointerWidth(PointeeTy.getAddressSpace());
+ unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
+ uint64_t Size = CGM.getContext().Target.getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
return
@@ -488,7 +498,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
- Elements = DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
+ Elements = DBuilder.getOrCreateArray(EltTys);
EltTys.clear();
unsigned Flags = llvm::DIDescriptor::FlagAppleBlock;
@@ -522,7 +532,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- Elements = DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
+ Elements = DBuilder.getOrCreateArray(EltTys);
EltTy = DBuilder.createStructType(Unit, "__block_literal_generic",
Unit, LineNo, FieldOffset, 0,
@@ -564,8 +574,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
EltTys.push_back(getOrCreateType(FTP->getArgType(i), Unit));
}
- llvm::DIArray EltTypeArray =
- DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys);
llvm::DIType DbgTy = DBuilder.createSubroutineType(Unit, EltTypeArray);
return DbgTy;
@@ -609,18 +618,32 @@ void CGDebugInfo::
CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
llvm::SmallVectorImpl<llvm::Value *> &elements) {
unsigned fieldNo = 0;
+ const FieldDecl *LastFD = 0;
+ bool IsMsStruct = record->hasAttr<MsStructAttr>();
+
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
for (RecordDecl::field_iterator I = record->field_begin(),
E = record->field_end();
I != E; ++I, ++fieldNo) {
FieldDecl *field = *I;
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are ignored
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD) ||
+ CGM.getContext().ZeroBitfieldFollowsBitfield((field), LastFD)) {
+ --fieldNo;
+ continue;
+ }
+ LastFD = field;
+ }
llvm::StringRef name = field->getName();
QualType type = field->getType();
// Ignore unnamed fields unless they're anonymous structs/unions.
- if (name.empty() && !type->isRecordType())
+ if (name.empty() && !type->isRecordType()) {
+ LastFD = field;
continue;
+ }
llvm::DIType fieldType
= createFieldType(name, type, field->getBitWidth(),
@@ -655,9 +678,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
if (!Method->isStatic())
{
// "this" pointer is always first argument.
- ASTContext &Context = CGM.getContext();
- QualType ThisPtr =
- Context.getPointerType(Context.getTagDeclType(Method->getParent()));
+ QualType ThisPtr = Method->getThisType(CGM.getContext());
llvm::DIType ThisPtrType =
DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit));
@@ -669,8 +690,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
Elts.push_back(Args.getElement(i));
- llvm::DIArray EltTypeArray =
- DBuilder.getOrCreateArray(Elts.data(), Elts.size());
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
return DBuilder.createSubroutineType(Unit, EltTypeArray);
}
@@ -753,10 +773,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
Virtuality, VIndex, ContainingType,
Flags, CGM.getLangOptions().Optimize);
- // Don't cache ctors or dtors since we have to emit multiple functions for
- // a single ctor or dtor.
- if (!IsCtorOrDtor && Method->isThisDeclarationADefinition())
- SPCache[Method] = llvm::WeakVH(SP);
+ SPCache[Method] = llvm::WeakVH(SP);
return SP;
}
@@ -816,10 +833,13 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
if (BI->isVirtual()) {
// virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
- BaseOffset = 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base);
+ BaseOffset =
+ 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base).getQuantity();
BFlags = llvm::DIDescriptor::FlagVirtual;
} else
BaseOffset = RL.getBaseClassOffsetInBits(Base);
+ // FIXME: Inconsistent units for BaseOffset. It is in bytes when
+ // BI->isVirtual() and bits when not.
AccessSpecifier Access = BI->getAccessSpecifier();
if (Access == clang::AS_private)
@@ -835,6 +855,60 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
}
}
+/// CollectTemplateParams - A helper function to collect template parameters.
+llvm::DIArray CGDebugInfo::
+CollectTemplateParams(const TemplateParameterList *TPList,
+ const TemplateArgumentList &TAList,
+ llvm::DIFile Unit) {
+ llvm::SmallVector<llvm::Value *, 16> TemplateParams;
+ for (unsigned i = 0, e = TAList.size(); i != e; ++i) {
+ const TemplateArgument &TA = TAList[i];
+ const NamedDecl *ND = TPList->getParam(i);
+ if (TA.getKind() == TemplateArgument::Type) {
+ llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit);
+ llvm::DITemplateTypeParameter TTP =
+ DBuilder.createTemplateTypeParameter(TheCU, ND->getName(), TTy);
+ TemplateParams.push_back(TTP);
+ } else if (TA.getKind() == TemplateArgument::Integral) {
+ llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
+ llvm::DITemplateValueParameter TVP =
+ DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy,
+ TA.getAsIntegral()->getZExtValue());
+ TemplateParams.push_back(TVP);
+ }
+ }
+ return DBuilder.getOrCreateArray(TemplateParams);
+}
+
+/// CollectFunctionTemplateParams - A helper function to collect debug
+/// info for function template parameters.
+llvm::DIArray CGDebugInfo::
+CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
+ if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization){
+ const TemplateParameterList *TList =
+ FD->getTemplateSpecializationInfo()->getTemplate()->getTemplateParameters();
+ return
+ CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit);
+ }
+ return llvm::DIArray();
+}
+
+/// CollectCXXTemplateParams - A helper function to collect debug info for
+/// template parameters.
+llvm::DIArray CGDebugInfo::
+CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial,
+ llvm::DIFile Unit) {
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ PU = TSpecial->getSpecializedTemplateOrPartial();
+
+ TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ?
+ PU.get<ClassTemplateDecl *>()->getTemplateParameters() :
+ PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters();
+ const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs();
+ return CollectTemplateParams(TPList, TAList, Unit);
+}
+
/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
if (VTablePtrType.isValid())
@@ -844,7 +918,7 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
/* Function type */
llvm::Value *STy = getOrCreateType(Context.IntTy, Unit);
- llvm::DIArray SElements = DBuilder.getOrCreateArray(&STy, 1);
+ llvm::DIArray SElements = DBuilder.getOrCreateArray(STy);
llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements);
unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0,
@@ -971,30 +1045,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
}
CollectRecordFields(RD, Unit, EltTys);
- llvm::SmallVector<llvm::Value *, 16> TemplateParams;
+ llvm::DIArray TParamsArray;
if (CXXDecl) {
CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl);
CollectCXXFriends(CXXDecl, Unit, EltTys, FwdDecl);
- if (ClassTemplateSpecializationDecl *TSpecial
- = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
- const TemplateArgumentList &TAL = TSpecial->getTemplateArgs();
- for (unsigned i = 0, e = TAL.size(); i != e; ++i) {
- const TemplateArgument &TA = TAL[i];
- if (TA.getKind() == TemplateArgument::Type) {
- llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit);
- llvm::DITemplateTypeParameter TTP =
- DBuilder.createTemplateTypeParameter(TheCU, TTy.getName(), TTy);
- TemplateParams.push_back(TTP);
- } else if (TA.getKind() == TemplateArgument::Integral) {
- llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit);
- // FIXME: Get parameter name, instead of parameter type name.
- llvm::DITemplateValueParameter TVP =
- DBuilder.createTemplateValueParameter(TheCU, TTy.getName(), TTy,
- TA.getAsIntegral()->getZExtValue());
- TemplateParams.push_back(TVP);
- }
- }
- }
+ if (const ClassTemplateSpecializationDecl *TSpecial
+ = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ TParamsArray = CollectCXXTemplateParams(TSpecial, Unit);
}
RegionStack.pop_back();
@@ -1008,18 +1065,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
llvm::StringRef RDName = RD->getName();
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- llvm::DIArray Elements =
- DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
llvm::MDNode *RealDecl = NULL;
- if (RD->isStruct())
- RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, Elements);
- else if (RD->isUnion())
+ if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, Elements);
- else {
- assert(RD->isClass() && "Unknown RecordType!");
+ Size, Align, 0, Elements);
+ else if (CXXDecl) {
RDName = getClassName(RD);
// A class's primary base or the class itself contains the vtable.
llvm::MDNode *ContainingType = NULL;
@@ -1039,13 +1091,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
}
else if (CXXDecl->isDynamicClass())
ContainingType = FwdDecl;
- llvm::DIArray TParamsArray =
- DBuilder.getOrCreateArray(TemplateParams.data(), TemplateParams.size());
+
RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
Size, Align, 0, 0, llvm::DIType(),
Elements, ContainingType,
TParamsArray);
- }
+ } else
+ RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
+ Size, Align, 0, Elements);
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
@@ -1156,14 +1209,26 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
Flags = llvm::DIDescriptor::FlagPrivate;
- FieldTy = DBuilder.createMemberType(FieldName, FieldDefUnit,
- FieldLine, FieldSize, FieldAlign,
- FieldOffset, Flags, FieldTy);
+ llvm::StringRef PropertyName;
+ llvm::StringRef PropertyGetter;
+ llvm::StringRef PropertySetter;
+ unsigned PropertyAttributes = 0;
+ if (ObjCPropertyDecl *PD =
+ ID->FindPropertyVisibleInPrimaryClass(Field->getIdentifier())) {
+ PropertyName = PD->getName();
+ PropertyGetter = getSelectorName(PD->getGetterName());
+ PropertySetter = getSelectorName(PD->getSetterName());
+ PropertyAttributes = PD->getPropertyAttributes();
+ }
+ FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit,
+ FieldLine, FieldSize, FieldAlign,
+ FieldOffset, Flags, FieldTy,
+ PropertyName, PropertyGetter,
+ PropertySetter, PropertyAttributes);
EltTys.push_back(FieldTy);
}
- llvm::DIArray Elements =
- DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
RegionStack.pop_back();
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
@@ -1200,12 +1265,17 @@ llvm::DIType CGDebugInfo::CreateType(const TagType *Ty) {
llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty,
llvm::DIFile Unit) {
llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit);
- uint64_t NumElems = Ty->getNumElements();
- if (NumElems > 0)
+ int64_t NumElems = Ty->getNumElements();
+ int64_t LowerBound = 0;
+ if (NumElems == 0)
+ // If number of elements are not known then this is an unbounded array.
+ // Use Low = 1, Hi = 0 to express such arrays.
+ LowerBound = 1;
+ else
--NumElems;
- llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, NumElems);
- llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(&Subscript, 1);
+ llvm::Value *Subscript = DBuilder.getOrCreateSubrange(LowerBound, NumElems);
+ llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
@@ -1228,6 +1298,9 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
} else if (Ty->isIncompleteArrayType()) {
Size = 0;
Align = CGM.getContext().getTypeAlign(Ty->getElementType());
+ } else if (Ty->isDependentSizedArrayType() || Ty->isIncompleteType()) {
+ Size = 0;
+ Align = 0;
} else {
// Size and align of the whole array, not the element type.
Size = CGM.getContext().getTypeSize(Ty);
@@ -1243,18 +1316,23 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
EltTy = Ty->getElementType();
else {
while ((Ty = dyn_cast<ArrayType>(EltTy))) {
- uint64_t Upper = 0;
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ int64_t UpperBound = 0;
+ int64_t LowerBound = 0;
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) {
if (CAT->getSize().getZExtValue())
- Upper = CAT->getSize().getZExtValue() - 1;
+ UpperBound = CAT->getSize().getZExtValue() - 1;
+ } else
+ // This is an unbounded array. Use Low = 1, Hi = 0 to express such
+ // arrays.
+ LowerBound = 1;
+
// FIXME: Verify this is right for VLAs.
- Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Upper));
+ Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound, UpperBound));
EltTy = Ty->getElementType();
}
}
- llvm::DIArray SubscriptArray =
- DBuilder.getOrCreateArray(Subscripts.data(), Subscripts.size());
+ llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts);
llvm::DIType DbgTy =
DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit),
@@ -1303,9 +1381,7 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
Info.first, Info.second, FieldOffset, 0,
PointerDiffDITy);
- llvm::DIArray Elements =
- DBuilder.getOrCreateArray(&ElementTypes[0],
- llvm::array_lengthof(ElementTypes));
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes);
return DBuilder.createStructType(U, llvm::StringRef("test"),
U, 0, FieldOffset,
@@ -1327,8 +1403,7 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
}
// Return a CompositeType for the enum itself.
- llvm::DIArray EltArray =
- DBuilder.getOrCreateArray(Enumerators.data(), Enumerators.size());
+ llvm::DIArray EltArray = DBuilder.getOrCreateArray(Enumerators);
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
@@ -1366,6 +1441,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
break;
case Type::Attributed:
T = cast<AttributedType>(T)->getEquivalentType();
+ break;
case Type::Elaborated:
T = cast<ElaboratedType>(T)->getNamedType();
break;
@@ -1375,6 +1451,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
case Type::SubstTemplateTypeParm:
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
break;
+ case Type::Auto:
+ T = cast<AutoType>(T)->getDeducedType();
+ break;
}
assert(T != LastT && "Type unwrapping failed to unwrap!");
@@ -1394,7 +1473,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty);
-
+
// Check for existing entry.
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
@@ -1502,6 +1581,37 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
return Ty;
}
+/// getFunctionDeclaration - Return debug info descriptor to describe method
+/// declaration for the given method definition.
+llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) return llvm::DISubprogram();
+
+ // Setup context.
+ getContextDescriptor(cast<Decl>(D->getDeclContext()));
+
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
+ MI = SPCache.find(FD);
+ if (MI != SPCache.end()) {
+ llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second));
+ if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
+ return SP;
+ }
+
+ for (FunctionDecl::redecl_iterator I = FD->redecls_begin(),
+ E = FD->redecls_end(); I != E; ++I) {
+ const FunctionDecl *NextFD = *I;
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
+ MI = SPCache.find(NextFD);
+ if (MI != SPCache.end()) {
+ llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second));
+ if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
+ return SP;
+ }
+ }
+ return llvm::DISubprogram();
+}
+
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
@@ -1514,9 +1624,11 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
FnBeginRegionCount.push_back(RegionStack.size());
const Decl *D = GD.getDecl();
+
unsigned Flags = 0;
llvm::DIFile Unit = getOrCreateFile(CurLoc);
llvm::DIDescriptor FDContext(Unit);
+ llvm::DIArray TParamsArray;
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
@@ -1540,6 +1652,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
+
+ // Collect template parameters.
+ TParamsArray = CollectFunctionTemplateParams(FD, Unit);
} else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
Name = getObjCMethodName(OMD);
Flags |= llvm::DIDescriptor::FlagPrototyped;
@@ -1557,11 +1672,14 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
unsigned LineNo = getLineNumber(CurLoc);
if (D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
+ llvm::DIType SPTy = getOrCreateType(FnType, Unit);
+ llvm::DISubprogram SPDecl = getFunctionDeclaration(D);
llvm::DISubprogram SP =
DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
- LineNo, getOrCreateType(FnType, Unit),
+ LineNo, SPTy,
Fn->hasInternalLinkage(), true/*definition*/,
- Flags, CGM.getLangOptions().Optimize, Fn);
+ Flags, CGM.getLangOptions().Optimize, Fn,
+ TParamsArray, SPDecl);
// Push function on region stack.
llvm::MDNode *SPN = SP;
@@ -1714,15 +1832,17 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
}
CharUnits Align = CGM.getContext().getDeclAlign(VD);
- if (Align > CharUnits::fromQuantity(
- CGM.getContext().Target.getPointerAlign(0) / 8)) {
- unsigned AlignedOffsetInBytes
- = llvm::RoundUpToAlignment(FieldOffset/8, Align.getQuantity());
- unsigned NumPaddingBytes
- = AlignedOffsetInBytes - FieldOffset/8;
+ if (Align > CGM.getContext().toCharUnitsFromBits(
+ CGM.getContext().Target.getPointerAlign(0))) {
+ CharUnits FieldOffsetInBytes
+ = CGM.getContext().toCharUnitsFromBits(FieldOffset);
+ CharUnits AlignedOffsetInBytes
+ = FieldOffsetInBytes.RoundUpToAlignment(Align);
+ CharUnits NumPaddingBytes
+ = AlignedOffsetInBytes - FieldOffsetInBytes;
- if (NumPaddingBytes > 0) {
- llvm::APInt pad(32, NumPaddingBytes);
+ if (NumPaddingBytes.isPositive()) {
+ llvm::APInt pad(32, NumPaddingBytes.getQuantity());
FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
pad, ArrayType::Normal, 0);
EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
@@ -1732,7 +1852,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
FType = Type;
llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = Align.getQuantity()*8;
+ FieldAlign = CGM.getContext().toBits(Align);
*XOffset = FieldOffset;
FieldTy = DBuilder.createMemberType(VD->getName(), Unit,
@@ -1741,8 +1861,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
- llvm::DIArray Elements =
- DBuilder.getOrCreateArray(EltTys.data(), EltTys.size());
+ llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
@@ -1752,7 +1871,8 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
/// EmitDeclare - Emit local variable declaration debug info.
void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
- llvm::Value *Storage, CGBuilderTy &Builder) {
+ llvm::Value *Storage,
+ unsigned ArgNo, CGBuilderTy &Builder) {
assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
@@ -1798,13 +1918,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
- offset =
- CharUnits::fromQuantity(CGM.getContext().Target.getPointerWidth(0)/8);
+ offset = CGM.getContext().toCharUnitsFromBits(
+ CGM.getContext().Target.getPointerWidth(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));
// offset of x field
- offset = CharUnits::fromQuantity(XOffset/8);
+ offset = CGM.getContext().toCharUnitsFromBits(XOffset);
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
// Create the descriptor for the variable.
@@ -1812,7 +1932,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
DBuilder.createComplexVariable(Tag,
llvm::DIDescriptor(RegionStack.back()),
VD->getName(), Unit, Line, Ty,
- addr.data(), addr.size());
+ addr, ArgNo);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1825,7 +1945,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::DIVariable D =
DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
Name, Unit, Line, Ty,
- CGM.getLangOptions().Optimize, Flags);
+ CGM.getLangOptions().Optimize, Flags, ArgNo);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1855,7 +1975,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::DIVariable D =
DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
FieldName, Unit, Line, FieldTy,
- CGM.getLangOptions().Optimize, Flags);
+ CGM.getLangOptions().Optimize, Flags,
+ ArgNo);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1867,17 +1988,22 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
}
}
-/// EmitDeclare - Emit local variable declaration debug info.
-void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
- llvm::Value *Storage, CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo) {
- assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
+ llvm::Value *Storage,
+ CGBuilderTy &Builder) {
+ 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(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+
if (Builder.GetInsertBlock() == 0)
return;
-
+
bool isByRef = VD->hasAttr<BlocksAttr>();
-
+
uint64_t XOffset = 0;
llvm::DIFile Unit = getOrCreateFile(VD->getLocation());
llvm::DIType Ty;
@@ -1904,46 +2030,34 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
- offset = CharUnits::fromQuantity(target.getPointerSize()/8);
+ offset = CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits());
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));
// offset of x field
- offset = CharUnits::fromQuantity(XOffset/8);
+ offset = CGM.getContext().toCharUnitsFromBits(XOffset);
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
}
// Create the descriptor for the variable.
llvm::DIVariable D =
- DBuilder.createComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- VD->getName(), Unit, Line, Ty,
- addr.data(), addr.size());
+ DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
+ llvm::DIDescriptor(RegionStack.back()),
+ VD->getName(), Unit, Line, Ty, addr);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint());
llvm::MDNode *Scope = RegionStack.back();
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
-void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
- llvm::Value *Storage,
- CGBuilderTy &Builder) {
- EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder);
-}
-
-void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
- const VarDecl *variable, llvm::Value *Storage, CGBuilderTy &Builder,
- const CGBlockInfo &blockInfo) {
- EmitDeclare(variable, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder,
- blockInfo);
-}
-
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
/// variable declaration.
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
+ unsigned ArgNo,
CGBuilderTy &Builder) {
- EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, Builder);
+ EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder);
}
namespace {
@@ -1969,8 +2083,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
unsigned column = getColumnNumber(loc);
// Build the debug-info type for the block literal.
- llvm::DIDescriptor enclosingContext =
- getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
+ getContextDescriptor(cast<Decl>(blockDecl->getDeclContext()));
const llvm::StructLayout *blockLayout =
CGM.getTargetData().getStructLayout(block.StructureType);
@@ -2048,18 +2161,31 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
}
const VarDecl *variable = capture->getVariable();
- QualType type = (capture->isByRef() ? C.VoidPtrTy : variable->getType());
llvm::StringRef name = variable->getName();
- fields.push_back(createFieldType(name, type, 0, loc, AS_public,
- offsetInBits, tunit));
+
+ llvm::DIType fieldType;
+ if (capture->isByRef()) {
+ std::pair<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy);
+
+ // FIXME: this creates a second copy of this type!
+ uint64_t xoffset;
+ fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset);
+ fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first);
+ fieldType = DBuilder.createMemberType(name, tunit, line,
+ ptrInfo.first, ptrInfo.second,
+ offsetInBits, 0, fieldType);
+ } else {
+ fieldType = createFieldType(name, variable->getType(), 0,
+ loc, AS_public, offsetInBits, tunit);
+ }
+ fields.push_back(fieldType);
}
llvm::SmallString<36> typeName;
llvm::raw_svector_ostream(typeName)
<< "__block_literal_" << CGM.getUniqueBlockCount();
- llvm::DIArray fieldsArray =
- DBuilder.getOrCreateArray(fields.data(), fields.size());
+ llvm::DIArray fieldsArray = DBuilder.getOrCreateArray(fields);
llvm::DIType type =
DBuilder.createStructType(tunit, typeName.str(), tunit, line,
@@ -2078,7 +2204,8 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
llvm::DIDescriptor(scope),
name, tunit, line, type,
- CGM.getLangOptions().Optimize, flags);
+ CGM.getLangOptions().Optimize, flags,
+ cast<llvm::Argument>(addr)->getArgNo() + 1);
// Insert an llvm.dbg.value into the current block.
llvm::Instruction *declare =
@@ -2185,3 +2312,17 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
NameSpaceCache[NSDecl] = llvm::WeakVH(NS);
return NS;
}
+
+/// UpdateCompletedType - Update type cache because the type is now
+/// translated.
+void CGDebugInfo::UpdateCompletedType(const TagDecl *TD) {
+ QualType Ty = CGM.getContext().getTagDeclType(TD);
+
+ // If the type exist in type cache then remove it from the cache.
+ // There is no need to prepare debug info for the completed type
+ // right now. It will be generated on demand lazily.
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
+ TypeCache.find(Ty.getAsOpaquePtr());
+ if (it != TypeCache.end())
+ TypeCache.erase(it);
+}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index a39078860fa9..27d991bbee42 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -32,6 +32,7 @@ namespace llvm {
namespace clang {
class VarDecl;
class ObjCInterfaceDecl;
+ class ClassTemplateSpecializationDecl;
namespace CodeGen {
class CodeGenModule;
@@ -122,6 +123,16 @@ class CGDebugInfo {
llvm::DIFile F,
llvm::SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy);
+
+ llvm::DIArray
+ CollectTemplateParams(const TemplateParameterList *TPList,
+ const TemplateArgumentList &TAList,
+ llvm::DIFile Unit);
+ llvm::DIArray
+ CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit);
+ llvm::DIArray
+ CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS,
+ llvm::DIFile F);
llvm::DIType createFieldType(llvm::StringRef name, QualType type,
Expr *bitWidth, SourceLocation loc,
@@ -158,6 +169,10 @@ public:
/// has introduced scope change.
void UpdateLineDirectiveRegion(CGBuilderTy &Builder);
+ /// UpdateCompletedType - Update type cache because the type is now
+ /// translated.
+ void UpdateCompletedType(const TagDecl *TD);
+
/// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
/// of a new block.
void EmitRegionStart(CGBuilderTy &Builder);
@@ -181,7 +196,7 @@ public:
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
/// variable declaration.
void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
- CGBuilderTy &Builder);
+ unsigned ArgNo, CGBuilderTy &Builder);
/// EmitDeclareOfBlockLiteralArgVariable - Emit call to
/// llvm.dbg.declare for the block-literal argument to a block
@@ -204,12 +219,7 @@ public:
private:
/// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
- CGBuilderTy &Builder);
-
- /// EmitDeclare - Emit call to llvm.dbg.declare for a variable
- /// declaration from an enclosing block.
- void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
- CGBuilderTy &Builder, const CGBlockInfo &blockInfo);
+ unsigned ArgNo, CGBuilderTy &Builder);
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
@@ -243,6 +253,10 @@ private:
llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
llvm::StringRef Name, uint64_t *Offset);
+ /// getFunctionDeclaration - Return debug info descriptor to describe method
+ /// declaration for the given method definition.
+ llvm::DISubprogram getFunctionDeclaration(const Decl *D);
+
/// getFunctionName - Get function name for the given FunctionDecl. If the
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
@@ -252,6 +266,10 @@ private:
/// This is the display name for the debugging info.
llvm::StringRef getObjCMethodName(const ObjCMethodDecl *FD);
+ /// getSelectorName - Return selector name. This is used for debugging
+ /// info.
+ llvm::StringRef getSelectorName(Selector S);
+
/// getClassName - Get class name including template argument list.
llvm::StringRef getClassName(RecordDecl *RD);
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index f4db01d2570b..c02737581814 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -14,7 +14,6 @@
#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "CGBlocks.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
@@ -70,7 +69,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Friend:
case Decl::FriendTemplate:
case Decl::Block:
- assert(0 && "Declaration not should not be in declstmts!");
+ assert(0 && "Declaration should not be in declstmts!");
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;
case Decl::Enum: // enum X;
@@ -92,8 +91,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
return EmitVarDecl(VD);
}
- case Decl::Typedef: { // typedef int X;
- const TypedefDecl &TD = cast<TypedefDecl>(D);
+ case Decl::Typedef: // typedef int X;
+ case Decl::TypeAlias: { // using X = int; [C++0x]
+ const TypedefNameDecl &TD = cast<TypedefNameDecl>(D);
QualType Ty = TD.getUnderlyingType();
if (Ty->isVariablyModifiedType())
@@ -179,7 +179,8 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
new llvm::GlobalVariable(CGM.getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
CGM.EmitNullConstant(D.getType()), Name, 0,
- D.isThreadSpecified(), Ty.getAddressSpace());
+ D.isThreadSpecified(),
+ CGM.getContext().getTargetAddressSpace(Ty));
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
if (Linkage != llvm::GlobalValue::InternalLinkage)
GV->setVisibility(CurFn->getVisibility());
@@ -222,7 +223,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
OldGV->getLinkage(), Init, "",
/*InsertBefore*/ OldGV,
D.isThreadSpecified(),
- D.getType().getAddressSpace());
+ CGM.getContext().getTargetAddressSpace(D.getType()));
GV->setVisibility(OldGV->getVisibility());
// Steal the name of the old global
@@ -289,7 +290,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// FIXME: It is really dangerous to store this in the map; if anyone
// RAUW's the GV uses of this constant will be invalid.
const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType());
- const llvm::Type *LPtrTy = LTy->getPointerTo(D.getType().getAddressSpace());
+ const llvm::Type *LPtrTy =
+ LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType()));
DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy);
// Emit global variable debug descriptor for static vars.
@@ -300,114 +302,6 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
}
}
-unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
- assert(ByRefValueInfo.count(VD) && "Did not find value!");
-
- return ByRefValueInfo.find(VD)->second.second;
-}
-
-llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr,
- const VarDecl *V) {
- llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding");
- Loc = Builder.CreateLoad(Loc);
- Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V),
- V->getNameAsString());
- return Loc;
-}
-
-/// BuildByRefType - This routine changes a __block variable declared as T x
-/// into:
-///
-/// struct {
-/// void *__isa;
-/// void *__forwarding;
-/// int32_t __flags;
-/// int32_t __size;
-/// void *__copy_helper; // only if needed
-/// void *__destroy_helper; // only if needed
-/// char padding[X]; // only if needed
-/// T x;
-/// } x
-///
-const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
- std::pair<const llvm::Type *, unsigned> &Info = ByRefValueInfo[D];
- if (Info.first)
- return Info.first;
-
- QualType Ty = D->getType();
-
- std::vector<const llvm::Type *> Types;
-
- llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext());
-
- // void *__isa;
- Types.push_back(Int8PtrTy);
-
- // void *__forwarding;
- Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
-
- // int32_t __flags;
- Types.push_back(Int32Ty);
-
- // int32_t __size;
- Types.push_back(Int32Ty);
-
- bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty);
- if (HasCopyAndDispose) {
- /// void *__copy_helper;
- Types.push_back(Int8PtrTy);
-
- /// void *__destroy_helper;
- Types.push_back(Int8PtrTy);
- }
-
- bool Packed = false;
- CharUnits Align = getContext().getDeclAlign(D);
- if (Align > getContext().toCharUnitsFromBits(Target.getPointerAlign(0))) {
- // We have to insert padding.
-
- // The struct above has 2 32-bit integers.
- unsigned CurrentOffsetInBytes = 4 * 2;
-
- // And either 2 or 4 pointers.
- CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
- CGM.getTargetData().getTypeAllocSize(Int8PtrTy);
-
- // Align the offset.
- unsigned AlignedOffsetInBytes =
- llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align.getQuantity());
-
- unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
- if (NumPaddingBytes > 0) {
- const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
- // FIXME: We need a sema error for alignment larger than the minimum of
- // the maximal stack alignmint and the alignment of malloc on the system.
- if (NumPaddingBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumPaddingBytes);
-
- Types.push_back(Ty);
-
- // We want a packed struct.
- Packed = true;
- }
- }
-
- // T x;
- Types.push_back(ConvertTypeForMem(Ty));
-
- const llvm::Type *T = llvm::StructType::get(getLLVMContext(), Types, Packed);
-
- cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T);
- CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(),
- ByRefTypeHolder.get());
-
- Info.first = ByRefTypeHolder.get();
-
- Info.second = Types.size() - 1;
-
- return Info.first;
-}
-
namespace {
struct CallArrayDtor : EHScopeStack::Cleanup {
CallArrayDtor(const CXXDestructorDecl *Dtor,
@@ -498,20 +392,11 @@ namespace {
CGF.Builder.CreateBitCast(Addr, CGF.ConvertType(ArgTy));
CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(Arg),
- CGF.getContext().getPointerType(Var.getType())));
+ Args.add(RValue::get(Arg),
+ CGF.getContext().getPointerType(Var.getType()));
CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args);
}
};
-
- struct CallBlockRelease : EHScopeStack::Cleanup {
- llvm::Value *Addr;
- CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {}
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF);
- }
- };
}
@@ -642,7 +527,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// candidate nor a __block variable, emit it as a global instead.
if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstQualified() &&
!NRVO && !isByRef) {
- EmitStaticVarDecl(D, llvm::GlobalValue::PrivateLinkage);
+ EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
emission.Address = 0; // signal this condition to later callbacks
assert(emission.wasEmittedAsGlobal());
@@ -724,7 +609,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Get the element type.
const llvm::Type *LElemTy = ConvertTypeForMem(Ty);
- const llvm::Type *LElemPtrTy = LElemTy->getPointerTo(Ty.getAddressSpace());
+ const llvm::Type *LElemPtrTy =
+ LElemTy->getPointerTo(CGM.getContext().getTargetAddressSpace(Ty));
llvm::Value *VLASize = EmitVLASize(Ty);
@@ -800,75 +686,14 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
EnsureInsertPoint();
}
- CharUnits alignment = emission.Alignment;
-
- if (emission.IsByRef) {
- llvm::Value *V;
-
- BlockFieldFlags fieldFlags;
- bool fieldNeedsCopyDispose = false;
-
- if (type->isBlockPointerType()) {
- fieldFlags |= BLOCK_FIELD_IS_BLOCK;
- fieldNeedsCopyDispose = true;
- } else if (getContext().isObjCNSObjectType(type) ||
- type->isObjCObjectPointerType()) {
- fieldFlags |= BLOCK_FIELD_IS_OBJECT;
- fieldNeedsCopyDispose = true;
- } else if (getLangOptions().CPlusPlus) {
- if (getContext().getBlockVarCopyInits(&D))
- fieldNeedsCopyDispose = true;
- else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl())
- fieldNeedsCopyDispose = !record->hasTrivialDestructor();
- }
-
- llvm::Value *addr = emission.Address;
-
- // FIXME: Someone double check this.
- if (type.isObjCGCWeak())
- fieldFlags |= BLOCK_FIELD_IS_WEAK;
-
- // Initialize the 'isa', which is just 0 or 1.
- int isa = 0;
- if (fieldFlags & BLOCK_FIELD_IS_WEAK)
- isa = 1;
- V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa");
- Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa"));
-
- // Store the address of the variable into its own forwarding pointer.
- Builder.CreateStore(addr,
- Builder.CreateStructGEP(addr, 1, "byref.forwarding"));
-
- // Blocks ABI:
- // c) the flags field is set to either 0 if no helper functions are
- // needed or BLOCK_HAS_COPY_DISPOSE if they are,
- BlockFlags flags;
- if (fieldNeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
- Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
- Builder.CreateStructGEP(addr, 2, "byref.flags"));
-
- const llvm::Type *V1;
- V1 = cast<llvm::PointerType>(addr->getType())->getElementType();
- V = llvm::ConstantInt::get(IntTy, CGM.GetTargetTypeStoreSize(V1).getQuantity());
- Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size"));
-
- if (fieldNeedsCopyDispose) {
- llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4);
- Builder.CreateStore(CGM.BuildbyrefCopyHelper(addr->getType(), fieldFlags,
- alignment.getQuantity(), &D),
- copy_helper);
-
- llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5);
- Builder.CreateStore(CGM.BuildbyrefDestroyHelper(addr->getType(),
- fieldFlags,
- alignment.getQuantity(),
- &D),
- destroy_helper);
- }
- }
+ // Initialize the structure of a __block variable.
+ if (emission.IsByRef)
+ emitByrefStructureInit(emission);
if (!Init) return;
+ CharUnits alignment = emission.Alignment;
+
// Check whether this is a byref variable that's potentially
// captured and moved by its own initializer. If so, we'll need to
// emit the initializer first, then copy into the variable.
@@ -877,67 +702,91 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::Value *Loc =
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
- bool isVolatile = type.isVolatileQualified();
-
+ if (!emission.IsConstantAggregate)
+ return EmitExprAsInit(Init, &D, Loc, alignment, capturedByInit);
+
// If this is a simple aggregate initialization, we can optimize it
// in various ways.
- if (emission.IsConstantAggregate) {
- assert(!capturedByInit && "constant init contains a capturing block?");
-
- llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), type, this);
- assert(Init != 0 && "Wasn't a simple constant init?");
-
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(IntPtrTy,
- getContext().getTypeSizeInChars(type).getQuantity());
-
- const llvm::Type *BP = Int8PtrTy;
- if (Loc->getType() != BP)
- Loc = Builder.CreateBitCast(Loc, BP, "tmp");
-
- // If the initializer is all or mostly zeros, codegen with memset then do
- // a few stores afterward.
- if (shouldUseMemSetPlusStoresToInitialize(Init,
- CGM.getTargetData().getTypeAllocSize(Init->getType()))) {
- Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
- alignment.getQuantity(), isVolatile);
- if (!Init->isNullValue()) {
- Loc = Builder.CreateBitCast(Loc, Init->getType()->getPointerTo());
- emitStoresForInitAfterMemset(Init, Loc, isVolatile, Builder);
- }
- } else {
- // Otherwise, create a temporary global with the initializer then
- // memcpy from the global to the alloca.
- std::string Name = GetStaticDeclName(*this, D, ".");
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
- llvm::GlobalValue::InternalLinkage,
- Init, Name, 0, false, 0);
- GV->setAlignment(alignment.getQuantity());
-
- llvm::Value *SrcPtr = GV;
- if (SrcPtr->getType() != BP)
- SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+ assert(!capturedByInit && "constant init contains a capturing block?");
+
+ bool isVolatile = type.isVolatileQualified();
- Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(),
- isVolatile);
+ llvm::Constant *constant = CGM.EmitConstantExpr(D.getInit(), type, this);
+ assert(constant != 0 && "Wasn't a simple constant init?");
+
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(IntPtrTy,
+ getContext().getTypeSizeInChars(type).getQuantity());
+
+ const llvm::Type *BP = Int8PtrTy;
+ if (Loc->getType() != BP)
+ Loc = Builder.CreateBitCast(Loc, BP, "tmp");
+
+ // 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()))) {
+ Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
+ alignment.getQuantity(), isVolatile);
+ if (!constant->isNullValue()) {
+ Loc = Builder.CreateBitCast(Loc, constant->getType()->getPointerTo());
+ emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder);
}
- } else if (type->isReferenceType()) {
- RValue RV = EmitReferenceBindingToExpr(Init, &D);
- if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D);
- EmitStoreOfScalar(RV.getScalarVal(), Loc, false, alignment.getQuantity(),
- type);
+ } else {
+ // Otherwise, create a temporary global with the initializer then
+ // memcpy from the global to the alloca.
+ std::string Name = GetStaticDeclName(*this, D, ".");
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ constant, Name, 0, false, 0);
+ GV->setAlignment(alignment.getQuantity());
+
+ llvm::Value *SrcPtr = GV;
+ if (SrcPtr->getType() != BP)
+ SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+
+ Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(),
+ isVolatile);
+ }
+}
+
+/// Emit an expression as an initializer for a variable at the given
+/// location. The expression is not necessarily the normal
+/// initializer for the variable, and the address is not necessarily
+/// its normal location.
+///
+/// \param init the initializing expression
+/// \param var the variable to act as if we're initializing
+/// \param loc the address to initialize; its type is a pointer
+/// to the LLVM mapping of the variable's type
+/// \param alignment the alignment of the address
+/// \param capturedByInit true if the variable is a __block variable
+/// whose address is potentially changed by the initializer
+void CodeGenFunction::EmitExprAsInit(const Expr *init,
+ const VarDecl *var,
+ llvm::Value *loc,
+ CharUnits alignment,
+ bool capturedByInit) {
+ QualType type = var->getType();
+ bool isVolatile = type.isVolatileQualified();
+
+ if (type->isReferenceType()) {
+ RValue RV = EmitReferenceBindingToExpr(init, var);
+ if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
+ EmitStoreOfScalar(RV.getScalarVal(), loc, false,
+ alignment.getQuantity(), type);
} else if (!hasAggregateLLVMType(type)) {
- llvm::Value *V = EmitScalarExpr(Init);
- if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D);
- EmitStoreOfScalar(V, Loc, isVolatile, alignment.getQuantity(), type);
+ llvm::Value *V = EmitScalarExpr(init);
+ if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
+ EmitStoreOfScalar(V, loc, isVolatile, alignment.getQuantity(), type);
} else if (type->isAnyComplexType()) {
- ComplexPairTy complex = EmitComplexExpr(Init);
- if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D);
- StoreComplexToAddr(complex, Loc, isVolatile);
+ ComplexPairTy complex = EmitComplexExpr(init);
+ if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
+ StoreComplexToAddr(complex, loc, isVolatile);
} else {
// TODO: how can we delay here if D is captured by its initializer?
- EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true, false));
+ EmitAggExpr(init, AggValueSlot::forAddr(loc, isVolatile, true, false));
}
}
@@ -993,14 +842,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
// If this is a block variable, call _Block_object_destroy
// (on the unforwarded address).
- if (emission.IsByRef &&
- CGM.getLangOptions().getGCMode() != LangOptions::GCOnly)
- EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address);
+ if (emission.IsByRef)
+ enterByrefCleanup(emission);
}
/// Emit an alloca (or GlobalValue depending on target)
/// for the specified parameter and set up LocalDeclMap.
-void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
+void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
+ unsigned ArgNo) {
// FIXME: Why isn't ImplicitParamDecl a ParmVarDecl?
assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
"Invalid argument to EmitParmDecl");
@@ -1046,6 +895,6 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
// Emit debug info for param declaration.
if (CGDebugInfo *DI = getDebugInfo()) {
DI->setLocation(D.getLocation());
- DI->EmitDeclareOfArgVariable(&D, DeclPtr, Builder);
+ DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder);
}
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index e295267896eb..45b0b969be67 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -138,6 +138,8 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
"__cxa_atexit");
+ if (llvm::Function *Fn = dyn_cast<llvm::Function>(AtExitFn))
+ Fn->setDoesNotThrow();
llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
"__dso_handle");
@@ -149,6 +151,14 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
llvm::GlobalVariable *DeclPtr) {
+ // If we've been asked to forbid guard variables, emit an error now.
+ // This diagnostic is hard-coded for Darwin's use case; we can find
+ // better phrasing if someone else needs it.
+ if (CGM.getCodeGenOpts().ForbidGuardVariables)
+ CGM.Error(D.getLocation(),
+ "this initialization requires a guard variable, which "
+ "the kernel does not support");
+
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr);
}
@@ -166,7 +176,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
Fn->setSection(Section);
}
- if (!CGM.getLangOptions().areExceptionsEnabled())
+ if (!CGM.getLangOptions().Exceptions)
Fn->setDoesNotThrow();
return Fn;
@@ -260,12 +270,16 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() {
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
llvm::GlobalVariable *Addr) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
- SourceLocation());
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+ getTypes().getNullaryFunctionInfo(),
+ FunctionArgList(), SourceLocation());
// Use guarded initialization if the global variable is weak due to
- // being a class template's static data member.
- if (Addr->hasWeakLinkage() && D->getInstantiatedFromStaticDataMember()) {
+ // being a class template's static data member. These will always
+ // have weak_odr linkage.
+ if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage &&
+ D->isStaticDataMember() &&
+ D->getInstantiatedFromStaticDataMember()) {
EmitCXXGuardedInit(*D, Addr);
} else {
EmitCXXGlobalVarDeclInit(*D, Addr);
@@ -277,8 +291,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
llvm::Constant **Decls,
unsigned NumDecls) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
- SourceLocation());
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+ getTypes().getNullaryFunctionInfo(),
+ FunctionArgList(), SourceLocation());
for (unsigned i = 0; i != NumDecls; ++i)
if (Decls[i])
@@ -290,8 +305,9 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
- SourceLocation());
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+ getTypes().getNullaryFunctionInfo(),
+ FunctionArgList(), SourceLocation());
// Emit the dtors, in reverse order from construction.
for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
@@ -313,21 +329,19 @@ llvm::Function *
CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
const ArrayType *Array,
llvm::Value *This) {
- FunctionArgList Args;
- ImplicitParamDecl *Dst =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
- Args.push_back(std::make_pair(Dst, Dst->getType()));
+ FunctionArgList args;
+ ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);
+ args.push_back(&dst);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args,
+ CGM.getTypes().getFunctionInfo(getContext().VoidTy, args,
FunctionType::ExtInfo());
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn, Args, SourceLocation());
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FI, args,
+ SourceLocation());
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy)->getPointerTo();
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 4bce081e48dd..6cb9599e257d 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -28,24 +28,22 @@ using namespace CodeGen;
static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
// void *__cxa_allocate_exception(size_t thrown_size);
- const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
- std::vector<const llvm::Type*> Args(1, SizeTy);
+ const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()),
- Args, false);
+ llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()),
+ SizeTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
}
static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
// void __cxa_free_exception(void *thrown_exception);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Args, false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
}
@@ -55,11 +53,10 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
// void (*dest) (void *));
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- std::vector<const llvm::Type*> Args(3, Int8PtrTy);
-
+ const llvm::Type *Args[3] = { Int8PtrTy, Int8PtrTy, Int8PtrTy };
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Args, false);
+ Args, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
}
@@ -68,18 +65,18 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
// void __cxa_rethrow();
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
}
static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
// void *__cxa_get_exception_ptr(void*);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int8PtrTy, Args, false);
+ llvm::FunctionType::get(Int8PtrTy, Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
}
@@ -88,10 +85,8 @@ static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
// void *__cxa_begin_catch(void*);
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
-
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int8PtrTy, Args, false);
+ llvm::FunctionType::get(Int8PtrTy, Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
}
@@ -100,7 +95,8 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
// void __cxa_end_catch();
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
}
@@ -109,22 +105,18 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
// void __cxa_call_unexepcted(void *thrown_exception);
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
-
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Args, false);
+ Int8PtrTy, /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
-
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Args,
- false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Int8PtrTy,
+ /*IsVarArgs=*/false);
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
@@ -135,7 +127,8 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
// void __terminate();
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy,
CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort");
@@ -145,10 +138,9 @@ static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
llvm::StringRef Name) {
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
-
const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
- const llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, Args, false);
+ const llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, Int8PtrTy,
+ /*IsVarArgs=*/false);
return CGF.CGM.CreateRuntimeFunction(FTy, Name);
}
@@ -160,6 +152,7 @@ const EHPersonality EHPersonality::GNU_CPlusPlus("__gxx_personality_v0");
const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0");
const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0",
"objc_exception_throw");
+const EHPersonality EHPersonality::GNU_ObjCXX("__gnustep_objcxx_personality_v0");
static const EHPersonality &getCPersonality(const LangOptions &L) {
if (L.SjLjExceptions)
@@ -201,7 +194,7 @@ static const EHPersonality &getObjCXXPersonality(const LangOptions &L) {
// The GNU runtime's personality function inherently doesn't support
// mixed EH. Use the C++ personality just to avoid returning null.
- return getCXXPersonality(L);
+ return EHPersonality::GNU_ObjCXX;
}
const EHPersonality &EHPersonality::get(const LangOptions &L) {
@@ -273,7 +266,7 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
/// when it really needs it.
void CodeGenModule::SimplifyPersonality() {
// For now, this is really a Darwin-specific operation.
- if (Context.Target.getTriple().getOS() != llvm::Triple::Darwin)
+ if (!Context.Target.getTriple().isOSDarwin())
return;
// If we're not in ObjC++ -fexceptions, there's nothing to do.
@@ -439,7 +432,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
}
void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
- if (!CGM.getLangOptions().areExceptionsEnabled())
+ if (!CGM.getLangOptions().CXXExceptions)
return;
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
@@ -449,25 +442,28 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
if (Proto == 0)
return;
- assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack");
-
- if (!Proto->hasExceptionSpec())
- return;
-
- unsigned NumExceptions = Proto->getNumExceptions();
- EHFilterScope *Filter = EHStack.pushFilter(NumExceptions);
-
- for (unsigned I = 0; I != NumExceptions; ++I) {
- QualType Ty = Proto->getExceptionType(I);
- QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType();
- llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType,
- /*ForEH=*/true);
- Filter->setFilter(I, EHType);
+ ExceptionSpecificationType EST = Proto->getExceptionSpecType();
+ if (isNoexceptExceptionSpec(EST)) {
+ if (Proto->getNoexceptSpec(getContext()) == FunctionProtoType::NR_Nothrow) {
+ // noexcept functions are simple terminate scopes.
+ EHStack.pushTerminate();
+ }
+ } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
+ unsigned NumExceptions = Proto->getNumExceptions();
+ EHFilterScope *Filter = EHStack.pushFilter(NumExceptions);
+
+ for (unsigned I = 0; I != NumExceptions; ++I) {
+ QualType Ty = Proto->getExceptionType(I);
+ QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType();
+ llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType,
+ /*ForEH=*/true);
+ Filter->setFilter(I, EHType);
+ }
}
}
void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
- if (!CGM.getLangOptions().areExceptionsEnabled())
+ if (!CGM.getLangOptions().CXXExceptions)
return;
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
@@ -477,10 +473,14 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
if (Proto == 0)
return;
- if (!Proto->hasExceptionSpec())
- return;
-
- EHStack.popFilter();
+ ExceptionSpecificationType EST = Proto->getExceptionSpecType();
+ if (isNoexceptExceptionSpec(EST)) {
+ if (Proto->getNoexceptSpec(getContext()) == FunctionProtoType::NR_Nothrow) {
+ EHStack.popTerminate();
+ }
+ } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
+ EHStack.popFilter();
+ }
}
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
@@ -541,7 +541,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
assert(EHStack.requiresLandingPad());
assert(!EHStack.empty());
- if (!CGM.getLangOptions().areExceptionsEnabled())
+ if (!CGM.getLangOptions().Exceptions)
return 0;
// Check the innermost scope for a cached landing pad. If this is
@@ -664,7 +664,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
assert(I.next() == EHStack.end() && "EH filter is not end of EH stack");
assert(!CatchAll.isValid() && "EH filter reached after catch-all");
- // Filter scopes get added to the selector in wierd ways.
+ // Filter scopes get added to the selector in weird ways.
EHFilterScope &Filter = cast<EHFilterScope>(*I);
HasEHFilter = true;
diff --git a/lib/CodeGen/CGException.h b/lib/CodeGen/CGException.h
index 1f9b8964dcae..5a743b51f66f 100644
--- a/lib/CodeGen/CGException.h
+++ b/lib/CodeGen/CGException.h
@@ -41,6 +41,7 @@ public:
static const EHPersonality GNU_C;
static const EHPersonality GNU_C_SJLJ;
static const EHPersonality GNU_ObjC;
+ static const EHPersonality GNU_ObjCXX;
static const EHPersonality NeXT_ObjC;
static const EHPersonality GNU_CPlusPlus;
static const EHPersonality GNU_CPlusPlus_SJLJ;
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2abaadff4b6d..bc2cd35bc591 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -15,6 +15,7 @@
#include "CodeGenModule.h"
#include "CGCall.h"
#include "CGCXXABI.h"
+#include "CGDebugInfo.h"
#include "CGRecordLayout.h"
#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
@@ -215,24 +216,28 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
InitializedDecl);
}
+ if (const ObjCPropertyRefExpr *PRE =
+ dyn_cast<ObjCPropertyRefExpr>(E->IgnoreParenImpCasts()))
+ if (PRE->getGetterResultType()->isReferenceType())
+ E = PRE;
+
RValue RV;
if (E->isGLValue()) {
// Emit the expression as an lvalue.
LValue LV = CGF.EmitLValue(E);
+ if (LV.isPropertyRef()) {
+ RV = CGF.EmitLoadOfPropertyRefLValue(LV);
+ return RV.getScalarVal();
+ }
if (LV.isSimple())
return LV.getAddress();
// We have to load the lvalue.
RV = CGF.EmitLoadOfLValue(LV, E->getType());
} else {
- QualType ResultTy = E->getType();
-
llvm::SmallVector<SubobjectAdjustment, 2> Adjustments;
while (true) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
- E = PE->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
if ((CE->getCastKind() == CK_DerivedToBase ||
@@ -327,9 +332,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
}
}
-
- const llvm::Type *ResultPtrTy = CGF.ConvertType(ResultTy)->getPointerTo();
- return CGF.Builder.CreateBitCast(Object, ResultPtrTy, "temp");
+
+ return Object;
}
}
@@ -536,6 +540,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::DeclRefExprClass:
return EmitDeclRefLValue(cast<DeclRefExpr>(E));
case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
+ case Expr::GenericSelectionExprClass:
+ return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr());
case Expr::PredefinedExprClass:
return EmitPredefinedLValue(cast<PredefinedExpr>(E));
case Expr::StringLiteralClass:
@@ -718,21 +724,22 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
// Offset by the byte offset, if used.
- if (AI.FieldByteOffset) {
+ if (!AI.FieldByteOffset.isZero()) {
Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs");
+ Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
+ "bf.field.offs");
}
// Cast to the access type.
const llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(),
AI.AccessWidth,
- ExprType.getAddressSpace());
+ CGM.getContext().getTargetAddressSpace(ExprType));
Ptr = Builder.CreateBitCast(Ptr, PTy);
// Perform the load.
llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified());
- if (AI.AccessAlignment)
- Load->setAlignment(AI.AccessAlignment);
+ if (!AI.AccessAlignment.isZero())
+ Load->setAlignment(AI.AccessAlignment.getQuantity());
// Shift out unused low bits and mask out unused high bits.
llvm::Value *Val = Load;
@@ -921,9 +928,10 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
// Offset by the byte offset, if used.
- if (AI.FieldByteOffset) {
+ if (!AI.FieldByteOffset.isZero()) {
Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs");
+ Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
+ "bf.field.offs");
}
// Cast to the access type.
@@ -954,8 +962,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// If necessary, load and OR in bits that are outside of the bit-field.
if (AI.TargetBitWidth != AI.AccessWidth) {
llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified());
- if (AI.AccessAlignment)
- Load->setAlignment(AI.AccessAlignment);
+ if (!AI.AccessAlignment.isZero())
+ Load->setAlignment(AI.AccessAlignment.getQuantity());
// Compute the mask for zeroing the bits that are part of the bit-field.
llvm::APInt InvMask =
@@ -969,8 +977,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// Write the value.
llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr,
Dst.isVolatileQualified());
- if (AI.AccessAlignment)
- Store->setAlignment(AI.AccessAlignment);
+ if (!AI.AccessAlignment.isZero())
+ Store->setAlignment(AI.AccessAlignment.getQuantity());
}
}
@@ -1090,6 +1098,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
return;
}
+
+ if (const GenericSelectionExpr *Exp = dyn_cast<GenericSelectionExpr>(E)) {
+ setObjCGCLValueClass(Ctx, Exp->getResultExpr(), LV);
+ return;
+ }
+
if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
return;
@@ -1415,6 +1429,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// We know that the pointer points to a type of the correct size, unless the
// size is a VLA or Objective-C interface.
llvm::Value *Address = 0;
+ unsigned ArrayAlignment = 0;
if (const VariableArrayType *VAT =
getContext().getAsVariableArrayType(E->getType())) {
llvm::Value *VLASize = GetVLASize(VAT);
@@ -1425,7 +1440,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
llvm::Value *Base = EmitScalarExpr(E->getBase());
Address = EmitCastToVoidPtr(Base);
- Address = Builder.CreateInBoundsGEP(Address, Idx, "arrayidx");
+ if (getContext().getLangOptions().isSignedOverflowDefined())
+ Address = Builder.CreateGEP(Address, Idx, "arrayidx");
+ else
+ Address = Builder.CreateInBoundsGEP(Address, Idx, "arrayidx");
Address = Builder.CreateBitCast(Address, Base->getType());
} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
// Indexing over an interface, as in "NSString *P; P[4];"
@@ -1447,22 +1465,38 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// "gep x, i" here. Emit one "gep A, 0, i".
assert(Array->getType()->isArrayType() &&
"Array to pointer decay must have array source type!");
- llvm::Value *ArrayPtr = EmitLValue(Array).getAddress();
+ LValue ArrayLV = EmitLValue(Array);
+ llvm::Value *ArrayPtr = ArrayLV.getAddress();
llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0);
llvm::Value *Args[] = { Zero, Idx };
- Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, Args+2, "arrayidx");
+ // Propagate the alignment from the array itself to the result.
+ ArrayAlignment = ArrayLV.getAlignment();
+
+ if (getContext().getLangOptions().isSignedOverflowDefined())
+ Address = Builder.CreateGEP(ArrayPtr, Args, Args+2, "arrayidx");
+ else
+ Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, Args+2, "arrayidx");
} else {
// The base must be a pointer, which is not an aggregate. Emit it.
llvm::Value *Base = EmitScalarExpr(E->getBase());
- Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
+ if (getContext().getLangOptions().isSignedOverflowDefined())
+ Address = Builder.CreateGEP(Base, Idx, "arrayidx");
+ else
+ Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
}
QualType T = E->getBase()->getType()->getPointeeType();
assert(!T.isNull() &&
"CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type");
- LValue LV = MakeAddrLValue(Address, T);
+ // Limit the alignment to that of the result type.
+ if (ArrayAlignment) {
+ unsigned Align = getContext().getTypeAlignInChars(T).getQuantity();
+ ArrayAlignment = std::min(Align, ArrayAlignment);
+ }
+
+ LValue LV = MakeAddrLValue(Address, T, ArrayAlignment);
LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace());
if (getContext().getLangOptions().ObjC1 &&
@@ -1715,10 +1749,10 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
}
const Expr *condExpr = expr->getCond();
-
- if (int condValue = ConstantFoldsToSimpleInteger(condExpr)) {
+ bool CondExprBool;
+ if (ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) {
const Expr *live = expr->getTrueExpr(), *dead = expr->getFalseExpr();
- if (condValue == -1) std::swap(live, dead);
+ if (!CondExprBool) std::swap(live, dead);
if (!ContainsLabel(dead))
return EmitLValue(live);
@@ -1756,9 +1790,8 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
EmitBlock(contBlock);
- llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(),
+ llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(), 2,
"cond-lvalue");
- phi->reserveOperandSpace(2);
phi->addIncoming(lhs.getAddress(), lhsBlock);
phi->addIncoming(rhs.getAddress(), rhsBlock);
return MakeAddrLValue(phi, expr->getType());
@@ -1927,6 +1960,12 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(E->getLocStart());
+ DI->UpdateLineDirectiveRegion(Builder);
+ DI->EmitStopPoint(Builder);
+ }
+
// Builtins never have block type.
if (E->getCallee()->getType()->isBlockPointerType())
return EmitBlockCallExpr(E, ReturnValue);
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index f992dc7c9cb9..29c76887a7c9 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -81,6 +81,9 @@ public:
CGF.ErrorUnsupported(S, "aggregate expression");
}
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
+ void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ Visit(GE->getResultExpr());
+ }
void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
// l-values.
@@ -179,11 +182,9 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
/// move will be performed.
void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) {
if (Dest.requiresGCollection()) {
- std::pair<uint64_t, unsigned> TypeInfo =
- CGF.getContext().getTypeInfo(E->getType());
- unsigned long size = TypeInfo.first/8;
+ CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType());
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
- llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
+ llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(),
Src.getAggregateAddr(),
SizeVal);
@@ -212,11 +213,9 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
}
if (Dest.requiresGCollection()) {
- std::pair<uint64_t, unsigned> TypeInfo =
- CGF.getContext().getTypeInfo(E->getType());
- unsigned long size = TypeInfo.first/8;
+ CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType());
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
- llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
+ llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
Dest.getAddr(),
Src.getAggregateAddr(),
@@ -249,11 +248,6 @@ void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
}
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
- if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) {
- Visit(E->getSubExpr());
- return;
- }
-
switch (E->getCastKind()) {
case CK_Dynamic: {
assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?");
@@ -270,6 +264,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
}
case CK_ToUnion: {
+ if (Dest.isIgnored()) break;
+
// GCC union extension
QualType Ty = E->getSubExpr()->getType();
QualType PtrTy = CGF.getContext().getPointerType(Ty);
@@ -309,7 +305,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_LValueBitCast:
llvm_unreachable("should not be emitting lvalue bitcast as rvalue");
break;
-
+
case CK_Dependent:
case CK_BitCast:
case CK_ArrayToPointerDecay:
@@ -397,15 +393,38 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
E->getRHS()->getType())
&& "Invalid assignment");
- // FIXME: __block variables need the RHS evaluated first!
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getLHS()))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VD->hasAttr<BlocksAttr>() &&
+ E->getRHS()->HasSideEffects(CGF.getContext())) {
+ // When __block variable on LHS, the RHS must be evaluated first
+ // as it may change the 'forwarding' field via call to Block_copy.
+ LValue RHS = CGF.EmitLValue(E->getRHS());
+ LValue LHS = CGF.EmitLValue(E->getLHS());
+ bool GCollection = false;
+ if (CGF.getContext().getLangOptions().getGCMode())
+ GCollection = TypeRequiresGCollection(E->getLHS()->getType());
+ Dest = AggValueSlot::forLValue(LHS, true, GCollection);
+ EmitFinalDestCopy(E, RHS, true);
+ return;
+ }
+
LValue LHS = CGF.EmitLValue(E->getLHS());
// We have to special case property setters, otherwise we must have
// a simple lvalue (no aggregates inside vectors, bitfields).
if (LHS.isPropertyRef()) {
- AggValueSlot Slot = EnsureSlot(E->getRHS()->getType());
- CGF.EmitAggExpr(E->getRHS(), Slot);
- CGF.EmitStoreThroughPropertyRefLValue(Slot.asRValue(), LHS);
+ const ObjCPropertyRefExpr *RE = LHS.getPropertyRefExpr();
+ QualType ArgType = RE->getSetterArgType();
+ RValue Src;
+ if (ArgType->isReferenceType())
+ Src = CGF.EmitReferenceBindingToExpr(E->getRHS(), 0);
+ else {
+ AggValueSlot Slot = EnsureSlot(E->getRHS()->getType());
+ CGF.EmitAggExpr(E->getRHS(), Slot);
+ Src = Slot.asRValue();
+ }
+ CGF.EmitStoreThroughPropertyRefLValue(Src, LHS);
} else {
bool GCollection = false;
if (CGF.getContext().getLangOptions().getGCMode())
@@ -513,9 +532,8 @@ void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
/// zero to memory, return true. This can return false if uncertain, so it just
/// handles simple cases.
static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
- // (0)
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
- return isSimpleZero(PE->getSubExpr(), CGF);
+ E = E->IgnoreParens();
+
// 0
if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
return IL->getValue() == 0;
@@ -619,6 +637,14 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
+ bool hasNonTrivialCXXConstructor = false;
+ if (CGF.getContext().getLangOptions().CPlusPlus)
+ if (const RecordType *RT = CGF.getContext()
+ .getBaseElementType(ElementType)->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ hasNonTrivialCXXConstructor = !RD->hasTrivialConstructor();
+ }
+
// FIXME: were we intentionally ignoring address spaces and GC attributes?
for (uint64_t i = 0; i != NumArrayElements; ++i) {
@@ -626,7 +652,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// then we're done.
if (i == NumInitElements &&
Dest.isZeroed() &&
- CGF.getTypes().isZeroInitializable(ElementType))
+ CGF.getTypes().isZeroInitializable(ElementType) &&
+ !hasNonTrivialCXXConstructor)
break;
llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array");
@@ -634,6 +661,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (i < NumInitElements)
EmitInitializationToLValue(E->getInit(i), LV, ElementType);
+ else if (Expr *filler = E->getArrayFiller())
+ EmitInitializationToLValue(filler, LV, ElementType);
else
EmitNullInitializationToLValue(LV, ElementType);
@@ -737,18 +766,17 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
/// GetNumNonZeroBytesInInit - Get an approximate count of the number of
/// non-zero bytes that will be stored when outputting the initializer for the
/// specified initializer expression.
-static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
- return GetNumNonZeroBytesInInit(PE->getSubExpr(), CGF);
+static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
+ E = E->IgnoreParens();
// 0 and 0.0 won't require any non-zero stores!
- if (isSimpleZero(E, CGF)) return 0;
+ if (isSimpleZero(E, CGF)) return CharUnits::Zero();
// If this is an initlist expr, sum up the size of sizes of the (present)
// elements. If this is something weird, assume the whole thing is non-zero.
const InitListExpr *ILE = dyn_cast<InitListExpr>(E);
if (ILE == 0 || !CGF.getTypes().isZeroInitializable(ILE->getType()))
- return CGF.getContext().getTypeSize(E->getType())/8;
+ return CGF.getContext().getTypeSizeInChars(E->getType());
// InitListExprs for structs have to be handled carefully. If there are
// reference members, we need to consider the size of the reference, not the
@@ -756,7 +784,7 @@ static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
if (!RT->isUnionType()) {
RecordDecl *SD = E->getType()->getAs<RecordType>()->getDecl();
- uint64_t NumNonZeroBytes = 0;
+ CharUnits NumNonZeroBytes = CharUnits::Zero();
unsigned ILEElement = 0;
for (RecordDecl::field_iterator Field = SD->field_begin(),
@@ -773,7 +801,8 @@ static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
// Reference values are always non-null and have the width of a pointer.
if (Field->getType()->isReferenceType())
- NumNonZeroBytes += CGF.getContext().Target.getPointerWidth(0);
+ NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits(
+ CGF.getContext().Target.getPointerWidth(0));
else
NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF);
}
@@ -783,7 +812,7 @@ static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
}
- uint64_t NumNonZeroBytes = 0;
+ CharUnits NumNonZeroBytes = CharUnits::Zero();
for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
NumNonZeroBytes += GetNumNonZeroBytesInInit(ILE->getInit(i), CGF);
return NumNonZeroBytes;
@@ -797,28 +826,38 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
// If the slot is already known to be zeroed, nothing to do. Don't mess with
// volatile stores.
if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return;
-
+
+ // C++ objects with a user-declared constructor don't need zero'ing.
+ if (CGF.getContext().getLangOptions().CPlusPlus)
+ if (const RecordType *RT = CGF.getContext()
+ .getBaseElementType(E->getType())->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasUserDeclaredConstructor())
+ return;
+ }
+
// If the type is 16-bytes or smaller, prefer individual stores over memset.
- std::pair<uint64_t, unsigned> TypeInfo =
- CGF.getContext().getTypeInfo(E->getType());
- if (TypeInfo.first/8 <= 16)
+ std::pair<CharUnits, CharUnits> TypeInfo =
+ CGF.getContext().getTypeInfoInChars(E->getType());
+ if (TypeInfo.first <= CharUnits::fromQuantity(16))
return;
// Check to see if over 3/4 of the initializer are known to be zero. If so,
// we prefer to emit memset + individual stores for the rest.
- uint64_t NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF);
- if (NumNonZeroBytes*4 > TypeInfo.first/8)
+ CharUnits NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF);
+ if (NumNonZeroBytes*4 > TypeInfo.first)
return;
// Okay, it seems like a good idea to use an initial memset, emit the call.
- llvm::Constant *SizeVal = CGF.Builder.getInt64(TypeInfo.first/8);
- unsigned Align = TypeInfo.second/8;
+ llvm::Constant *SizeVal = CGF.Builder.getInt64(TypeInfo.first.getQuantity());
+ CharUnits Align = TypeInfo.second;
llvm::Value *Loc = Slot.getAddr();
const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
Loc = CGF.Builder.CreateBitCast(Loc, BP);
- CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, Align, false);
+ CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal,
+ Align.getQuantity(), false);
// Tell the AggExprEmitter that the slot is known zero.
Slot.setZeroed();
@@ -887,7 +926,8 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
// safely handle this, we can add a target hook.
// Get size and alignment info for this aggregate.
- std::pair<uint64_t, unsigned> TypeInfo = getContext().getTypeInfo(Ty);
+ std::pair<CharUnits, CharUnits> TypeInfo =
+ getContext().getTypeInfoInChars(Ty);
// FIXME: Handle variable sized types.
@@ -917,9 +957,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
RecordDecl *Record = RecordTy->getDecl();
if (Record->hasObjectMember()) {
- unsigned long size = TypeInfo.first/8;
+ CharUnits size = TypeInfo.first;
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
+ llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
SizeVal);
return;
@@ -928,9 +968,10 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
QualType BaseType = getContext().getBaseElementType(Ty);
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
if (RecordTy->getDecl()->hasObjectMember()) {
- unsigned long size = TypeInfo.first/8;
+ CharUnits size = TypeInfo.first;
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(SizeTy, size.getQuantity());
CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr,
SizeVal);
return;
@@ -939,6 +980,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
}
Builder.CreateMemCpy(DestPtr, SrcPtr,
- llvm::ConstantInt::get(IntPtrTy, TypeInfo.first/8),
- TypeInfo.second/8, isVolatile);
+ llvm::ConstantInt::get(IntPtrTy,
+ TypeInfo.first.getQuantity()),
+ TypeInfo.second.getQuantity(), isVolatile);
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index bba7864bff98..bdaa873f1832 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -17,6 +17,8 @@
#include "CGObjCRuntime.h"
#include "CGDebugInfo.h"
#include "llvm/Intrinsics.h"
+#include "llvm/Support/CallSite.h"
+
using namespace clang;
using namespace CodeGen;
@@ -35,13 +37,12 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
CallArgList Args;
// Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This),
- MD->getThisType(getContext())));
+ Args.add(RValue::get(This), MD->getThisType(getContext()));
// If there is a VTT parameter, emit it.
if (VTT) {
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
- Args.push_back(std::make_pair(RValue::get(VTT), T));
+ Args.add(RValue::get(VTT), T);
}
// And the rest of the call args
@@ -77,6 +78,31 @@ static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) {
return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl());
}
+// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
+// quite what we want.
+static const Expr *skipNoOpCastsAndParens(const Expr *E) {
+ while (true) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ E = PE->getSubExpr();
+ continue;
+ }
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() == CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ }
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_Extension) {
+ E = UO->getSubExpr();
+ continue;
+ }
+ }
+ return E;
+ }
+}
+
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
/// expr can be devirtualized.
static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context,
@@ -112,6 +138,7 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context,
if (MD->getParent()->hasAttr<FinalAttr>())
return true;
+ Base = skipNoOpCastsAndParens(Base);
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
// This is a record decl. We know the type and can devirtualize it.
@@ -141,10 +168,12 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context,
// extensions allowing explicit constructor function call.
RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
ReturnValueSlot ReturnValue) {
- if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
+ const Expr *callee = CE->getCallee()->IgnoreParens();
+
+ if (isa<BinaryOperator>(callee))
return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
-
- const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
+
+ const MemberExpr *ME = cast<MemberExpr>(callee);
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
CGDebugInfo *DI = getDebugInfo();
@@ -259,10 +288,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
const Expr *MemFnExpr = BO->getRHS();
const MemberPointerType *MPT =
- MemFnExpr->getType()->getAs<MemberPointerType>();
+ MemFnExpr->getType()->castAs<MemberPointerType>();
const FunctionProtoType *FPT =
- MPT->getPointeeType()->getAs<FunctionProtoType>();
+ MPT->getPointeeType()->castAs<FunctionProtoType>();
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
@@ -287,12 +316,11 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
getContext().getPointerType(getContext().getTagDeclType(RD));
// Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This), ThisType));
+ Args.add(RValue::get(This), ThisType);
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
- const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>();
- return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee,
+ return EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee,
ReturnValue, Args);
}
@@ -341,8 +369,9 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
// If we require zero initialization before (or instead of) calling the
// constructor, as can be the case with a non-user-provided default
- // constructor, emit the zero initialization now.
- if (E->requiresZeroInitialization())
+ // constructor, emit the zero initialization now, unless destination is
+ // already zeroed.
+ if (E->requiresZeroInitialization() && !Dest.isZeroed())
EmitNullInitialization(Dest.getAddr(), E->getType());
// If this is a call to a trivial default constructor, do nothing.
@@ -374,9 +403,16 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
E->arg_begin(), E->arg_end());
}
else {
- CXXCtorType Type =
- (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
- ? Ctor_Complete : Ctor_Base;
+ CXXCtorType Type;
+ CXXConstructExpr::ConstructionKind K = E->getConstructionKind();
+ if (K == CXXConstructExpr::CK_Delegating) {
+ // We should be emitting a constructor; GlobalDecl will assert this
+ Type = CurGD.getCtorType();
+ } else {
+ Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
+ ? Ctor_Complete : Ctor_Base;
+ }
+
bool ForVirtualBase =
E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase;
@@ -595,7 +631,7 @@ static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
Size = CGF.Builder.CreateExtractValue(AddRes, 0);
llvm::Value *AddDidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1);
- DidOverflow = CGF.Builder.CreateAnd(DidOverflow, AddDidOverflow);
+ DidOverflow = CGF.Builder.CreateOr(DidOverflow, AddDidOverflow);
}
Size = CGF.Builder.CreateSelect(DidOverflow,
@@ -800,15 +836,15 @@ namespace {
// The first argument is always a void*.
FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin();
- DeleteArgs.push_back(std::make_pair(RValue::get(Ptr), *AI++));
+ DeleteArgs.add(RValue::get(Ptr), *AI++);
// A member 'operator delete' can take an extra 'size_t' argument.
if (FPT->getNumArgs() == NumPlacementArgs + 2)
- DeleteArgs.push_back(std::make_pair(RValue::get(AllocSize), *AI++));
+ DeleteArgs.add(RValue::get(AllocSize), *AI++);
// Pass the rest of the arguments, which must match exactly.
for (unsigned I = 0; I != NumPlacementArgs; ++I)
- DeleteArgs.push_back(std::make_pair(getPlacementArgs()[I], *AI++));
+ DeleteArgs.add(getPlacementArgs()[I], *AI++);
// Call 'operator delete'.
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT),
@@ -857,18 +893,18 @@ namespace {
// The first argument is always a void*.
FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin();
- DeleteArgs.push_back(std::make_pair(Ptr.restore(CGF), *AI++));
+ DeleteArgs.add(Ptr.restore(CGF), *AI++);
// A member 'operator delete' can take an extra 'size_t' argument.
if (FPT->getNumArgs() == NumPlacementArgs + 2) {
RValue RV = AllocSize.restore(CGF);
- DeleteArgs.push_back(std::make_pair(RV, *AI++));
+ DeleteArgs.add(RV, *AI++);
}
// Pass the rest of the arguments, which must match exactly.
for (unsigned I = 0; I != NumPlacementArgs; ++I) {
RValue RV = getPlacementArgs()[I].restore(CGF);
- DeleteArgs.push_back(std::make_pair(RV, *AI++));
+ DeleteArgs.add(RV, *AI++);
}
// Call 'operator delete'.
@@ -895,7 +931,7 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
E->getOperatorDelete(),
NewPtr, AllocSize);
for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
- Cleanup->setPlacementArg(I, NewArgs[I+1].first);
+ Cleanup->setPlacementArg(I, NewArgs[I+1].RV);
return;
}
@@ -914,148 +950,154 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
SavedAllocSize);
for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
Cleanup->setPlacementArg(I,
- DominatingValue<RValue>::save(CGF, NewArgs[I+1].first));
+ DominatingValue<RValue>::save(CGF, NewArgs[I+1].RV));
CGF.ActivateCleanupBlock(CGF.EHStack.stable_begin());
}
llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
- QualType AllocType = E->getAllocatedType();
- if (AllocType->isArrayType())
- while (const ArrayType *AType = getContext().getAsArrayType(AllocType))
- AllocType = AType->getElementType();
+ // The element type being allocated.
+ QualType allocType = getContext().getBaseElementType(E->getAllocatedType());
- FunctionDecl *NewFD = E->getOperatorNew();
- const FunctionProtoType *NewFTy = NewFD->getType()->getAs<FunctionProtoType>();
+ // 1. Build a call to the allocation function.
+ FunctionDecl *allocator = E->getOperatorNew();
+ const FunctionProtoType *allocatorType =
+ allocator->getType()->castAs<FunctionProtoType>();
- CallArgList NewArgs;
+ CallArgList allocatorArgs;
// The allocation size is the first argument.
- QualType SizeTy = getContext().getSizeType();
+ QualType sizeType = getContext().getSizeType();
- llvm::Value *NumElements = 0;
- llvm::Value *AllocSizeWithoutCookie = 0;
- llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(),
- *this, E, NumElements,
- AllocSizeWithoutCookie);
+ llvm::Value *numElements = 0;
+ llvm::Value *allocSizeWithoutCookie = 0;
+ llvm::Value *allocSize =
+ EmitCXXNewAllocSize(getContext(), *this, E, numElements,
+ allocSizeWithoutCookie);
- NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy));
+ allocatorArgs.add(RValue::get(allocSize), sizeType);
// Emit the rest of the arguments.
// FIXME: Ideally, this should just use EmitCallArgs.
- CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin();
+ CXXNewExpr::const_arg_iterator placementArg = E->placement_arg_begin();
// First, use the types from the function type.
// We start at 1 here because the first argument (the allocation size)
// has already been emitted.
- for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) {
- QualType ArgType = NewFTy->getArgType(i);
+ for (unsigned i = 1, e = allocatorType->getNumArgs(); i != e;
+ ++i, ++placementArg) {
+ QualType argType = allocatorType->getArgType(i);
- assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
- getTypePtr() ==
- getContext().getCanonicalType(NewArg->getType()).getTypePtr() &&
+ assert(getContext().hasSameUnqualifiedType(argType.getNonReferenceType(),
+ placementArg->getType()) &&
"type mismatch in call argument!");
- NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType),
- ArgType));
-
+ EmitCallArg(allocatorArgs, *placementArg, argType);
}
// Either we've emitted all the call args, or we have a call to a
// variadic function.
- assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) &&
- "Extra arguments in non-variadic function!");
+ assert((placementArg == E->placement_arg_end() ||
+ allocatorType->isVariadic()) &&
+ "Extra arguments to non-variadic function!");
// If we still have any arguments, emit them using the type of the argument.
- for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end();
- NewArg != NewArgEnd; ++NewArg) {
- QualType ArgType = NewArg->getType();
- NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType),
- ArgType));
+ for (CXXNewExpr::const_arg_iterator placementArgsEnd = E->placement_arg_end();
+ placementArg != placementArgsEnd; ++placementArg) {
+ EmitCallArg(allocatorArgs, *placementArg, placementArg->getType());
}
- // Emit the call to new.
+ // Emit the allocation call.
RValue RV =
- EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy),
- CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD);
-
- // If an allocation function is declared with an empty exception specification
- // it returns null to indicate failure to allocate storage. [expr.new]p13.
- // (We don't need to check for null when there's no new initializer and
- // we're allocating a POD type).
- bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() &&
- !(AllocType->isPODType() && !E->hasInitializer());
-
- llvm::BasicBlock *NullCheckSource = 0;
- llvm::BasicBlock *NewNotNull = 0;
- llvm::BasicBlock *NewEnd = 0;
-
- llvm::Value *NewPtr = RV.getScalarVal();
- unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
-
- if (NullCheckResult) {
- NullCheckSource = Builder.GetInsertBlock();
- NewNotNull = createBasicBlock("new.notnull");
- NewEnd = createBasicBlock("new.end");
-
- llvm::Value *IsNull = Builder.CreateIsNull(NewPtr, "new.isnull");
- Builder.CreateCondBr(IsNull, NewEnd, NewNotNull);
- EmitBlock(NewNotNull);
+ EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType),
+ CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
+ allocatorArgs, allocator);
+
+ // Emit a null check on the allocation result if the allocation
+ // function is allowed to return null (because it has a non-throwing
+ // exception spec; for this part, we inline
+ // CXXNewExpr::shouldNullCheckAllocation()) and we have an
+ // interesting initializer.
+ bool nullCheck = allocatorType->isNothrow(getContext()) &&
+ !(allocType->isPODType() && !E->hasInitializer());
+
+ llvm::BasicBlock *nullCheckBB = 0;
+ llvm::BasicBlock *contBB = 0;
+
+ llvm::Value *allocation = RV.getScalarVal();
+ unsigned AS =
+ cast<llvm::PointerType>(allocation->getType())->getAddressSpace();
+
+ // The null-check means that the initializer is conditionally
+ // evaluated.
+ ConditionalEvaluation conditional(*this);
+
+ if (nullCheck) {
+ conditional.begin(*this);
+
+ nullCheckBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *notNullBB = createBasicBlock("new.notnull");
+ contBB = createBasicBlock("new.cont");
+
+ llvm::Value *isNull = Builder.CreateIsNull(allocation, "new.isnull");
+ Builder.CreateCondBr(isNull, contBB, notNullBB);
+ EmitBlock(notNullBB);
}
- assert((AllocSize == AllocSizeWithoutCookie) ==
+ assert((allocSize == allocSizeWithoutCookie) ==
CalculateCookiePadding(*this, E).isZero());
- if (AllocSize != AllocSizeWithoutCookie) {
+ if (allocSize != allocSizeWithoutCookie) {
assert(E->isArray());
- NewPtr = CGM.getCXXABI().InitializeArrayCookie(*this, NewPtr, NumElements,
- E, AllocType);
+ allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation,
+ numElements,
+ E, allocType);
}
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
- EHScopeStack::stable_iterator CallOperatorDelete;
+ EHScopeStack::stable_iterator operatorDeleteCleanup;
if (E->getOperatorDelete()) {
- EnterNewDeleteCleanup(*this, E, NewPtr, AllocSize, NewArgs);
- CallOperatorDelete = EHStack.stable_begin();
+ EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs);
+ operatorDeleteCleanup = EHStack.stable_begin();
}
- const llvm::Type *ElementPtrTy
- = ConvertTypeForMem(AllocType)->getPointerTo(AS);
- NewPtr = Builder.CreateBitCast(NewPtr, ElementPtrTy);
+ const llvm::Type *elementPtrTy
+ = ConvertTypeForMem(allocType)->getPointerTo(AS);
+ llvm::Value *result = Builder.CreateBitCast(allocation, elementPtrTy);
if (E->isArray()) {
- EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie);
+ EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie);
// NewPtr is a pointer to the base element type. If we're
// allocating an array of arrays, we'll need to cast back to the
// array pointer type.
- const llvm::Type *ResultTy = ConvertTypeForMem(E->getType());
- if (NewPtr->getType() != ResultTy)
- NewPtr = Builder.CreateBitCast(NewPtr, ResultTy);
+ const llvm::Type *resultType = ConvertTypeForMem(E->getType());
+ if (result->getType() != resultType)
+ result = Builder.CreateBitCast(result, resultType);
} else {
- EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie);
+ EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie);
}
// Deactivate the 'operator delete' cleanup if we finished
// initialization.
- if (CallOperatorDelete.isValid())
- DeactivateCleanupBlock(CallOperatorDelete);
+ if (operatorDeleteCleanup.isValid())
+ DeactivateCleanupBlock(operatorDeleteCleanup);
- if (NullCheckResult) {
- Builder.CreateBr(NewEnd);
- llvm::BasicBlock *NotNullSource = Builder.GetInsertBlock();
- EmitBlock(NewEnd);
-
- llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType());
- PHI->reserveOperandSpace(2);
- PHI->addIncoming(NewPtr, NotNullSource);
- PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()),
- NullCheckSource);
-
- NewPtr = PHI;
+ if (nullCheck) {
+ conditional.end(*this);
+
+ llvm::BasicBlock *notNullBB = Builder.GetInsertBlock();
+ EmitBlock(contBB);
+
+ llvm::PHINode *PHI = Builder.CreatePHI(result->getType(), 2);
+ PHI->addIncoming(result, notNullBB);
+ PHI->addIncoming(llvm::Constant::getNullValue(result->getType()),
+ nullCheckBB);
+
+ result = PHI;
}
- return NewPtr;
+ return result;
}
void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
@@ -1080,10 +1122,10 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
QualType ArgTy = DeleteFTy->getArgType(0);
llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
- DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
+ DeleteArgs.add(RValue::get(DeletePtr), ArgTy);
if (Size)
- DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
+ DeleteArgs.add(RValue::get(Size), SizeTy);
// Emit the call to delete.
EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy),
@@ -1180,7 +1222,7 @@ namespace {
QualType VoidPtrTy = DeleteFTy->getArgType(0);
llvm::Value *DeletePtr
= CGF.Builder.CreateBitCast(Ptr, CGF.ConvertType(VoidPtrTy));
- Args.push_back(std::make_pair(RValue::get(DeletePtr), VoidPtrTy));
+ Args.add(RValue::get(DeletePtr), VoidPtrTy);
// Pass the original requested size as the second argument.
if (DeleteFTy->getNumArgs() == 2) {
@@ -1203,7 +1245,7 @@ namespace {
Size = CGF.Builder.CreateAdd(Size, CookieSizeV);
}
- Args.push_back(std::make_pair(RValue::get(Size), size_t));
+ Args.add(RValue::get(Size), size_t);
}
// Emit the call to delete.
@@ -1264,9 +1306,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull");
llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end");
- llvm::Value *IsNull =
- Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()),
- "isnull");
+ llvm::Value *IsNull = Builder.CreateIsNull(Ptr, "isnull");
Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
EmitBlock(DeleteNotNull);
@@ -1306,173 +1346,253 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
EmitBlock(DeleteEnd);
}
+static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
+ // void __cxa_bad_typeid();
+
+ const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(VoidTy, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
+}
+
+static void EmitBadTypeidCall(CodeGenFunction &CGF) {
+ llvm::Value *Fn = getBadTypeidFn(CGF);
+ CGF.EmitCallOrInvoke(Fn, 0, 0).setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+}
+
+static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF,
+ const Expr *E,
+ const llvm::Type *StdTypeInfoPtrTy) {
+ // Get the vtable pointer.
+ llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress();
+
+ // C++ [expr.typeid]p2:
+ // If the glvalue expression is obtained by applying the unary * operator to
+ // a pointer and the pointer is a null pointer value, the typeid expression
+ // throws the std::bad_typeid exception.
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+ if (UO->getOpcode() == UO_Deref) {
+ llvm::BasicBlock *BadTypeidBlock =
+ CGF.createBasicBlock("typeid.bad_typeid");
+ llvm::BasicBlock *EndBlock =
+ CGF.createBasicBlock("typeid.end");
+
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
+ CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
+
+ CGF.EmitBlock(BadTypeidBlock);
+ EmitBadTypeidCall(CGF);
+ CGF.EmitBlock(EndBlock);
+ }
+ }
+
+ llvm::Value *Value = CGF.GetVTablePtr(ThisPtr,
+ StdTypeInfoPtrTy->getPointerTo());
+
+ // Load the type info.
+ Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
+ return CGF.Builder.CreateLoad(Value);
+}
+
llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
- QualType Ty = E->getType();
- const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
+ const llvm::Type *StdTypeInfoPtrTy =
+ ConvertType(E->getType())->getPointerTo();
if (E->isTypeOperand()) {
llvm::Constant *TypeInfo =
CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand());
- return Builder.CreateBitCast(TypeInfo, LTy);
+ return Builder.CreateBitCast(TypeInfo, StdTypeInfoPtrTy);
}
-
- Expr *subE = E->getExprOperand();
- Ty = subE->getType();
- CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
- Ty = CanTy.getUnqualifiedType().getNonReferenceType();
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->isPolymorphic()) {
- // FIXME: if subE is an lvalue do
- LValue Obj = EmitLValue(subE);
- llvm::Value *This = Obj.getAddress();
- // We need to do a zero check for *p, unless it has NonNullAttr.
- // FIXME: PointerType->hasAttr<NonNullAttr>()
- bool CanBeZero = false;
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(subE->IgnoreParens()))
- if (UO->getOpcode() == UO_Deref)
- CanBeZero = true;
- if (CanBeZero) {
- llvm::BasicBlock *NonZeroBlock = createBasicBlock();
- llvm::BasicBlock *ZeroBlock = createBasicBlock();
-
- llvm::Value *Zero = llvm::Constant::getNullValue(This->getType());
- Builder.CreateCondBr(Builder.CreateICmpNE(This, Zero),
- NonZeroBlock, ZeroBlock);
- EmitBlock(ZeroBlock);
- /// Call __cxa_bad_typeid
- const llvm::Type *ResultType = llvm::Type::getVoidTy(getLLVMContext());
- const llvm::FunctionType *FTy;
- FTy = llvm::FunctionType::get(ResultType, false);
- llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
- Builder.CreateCall(F)->setDoesNotReturn();
- Builder.CreateUnreachable();
- EmitBlock(NonZeroBlock);
- }
- llvm::Value *V = GetVTablePtr(This, LTy->getPointerTo());
- V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL);
- V = Builder.CreateLoad(V);
- return V;
+
+ // C++ [expr.typeid]p2:
+ // When typeid is applied to a glvalue expression whose type is a
+ // polymorphic class type, the result refers to a std::type_info object
+ // representing the type of the most derived object (that is, the dynamic
+ // type) to which the glvalue refers.
+ if (E->getExprOperand()->isGLValue()) {
+ if (const RecordType *RT =
+ E->getExprOperand()->getType()->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->isPolymorphic())
+ return EmitTypeidFromVTable(*this, E->getExprOperand(),
+ StdTypeInfoPtrTy);
}
}
- return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(Ty), LTy);
+
+ QualType OperandTy = E->getExprOperand()->getType();
+ return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(OperandTy),
+ StdTypeInfoPtrTy);
}
-llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
- const CXXDynamicCastExpr *DCE) {
- QualType SrcTy = DCE->getSubExpr()->getType();
- QualType DestTy = DCE->getTypeAsWritten();
- QualType InnerType = DestTy->getPointeeType();
+static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
+ // void *__dynamic_cast(const void *sub,
+ // const abi::__class_type_info *src,
+ // const abi::__class_type_info *dst,
+ // std::ptrdiff_t src2dst_offset);
- const llvm::Type *LTy = ConvertType(DCE->getType());
-
- bool CanBeZero = false;
- bool ToVoid = false;
- bool ThrowOnBad = false;
- if (DestTy->isPointerType()) {
- // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this
- CanBeZero = true;
- if (InnerType->isVoidType())
- ToVoid = true;
- } else {
- LTy = LTy->getPointerTo();
-
- // FIXME: What if exceptions are disabled?
- ThrowOnBad = true;
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ const llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(Int8PtrTy, Args, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast");
+}
+
+static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
+ // void __cxa_bad_cast();
+
+ const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(VoidTy, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
+}
+
+static void EmitBadCastCall(CodeGenFunction &CGF) {
+ llvm::Value *Fn = getBadCastFn(CGF);
+ CGF.EmitCallOrInvoke(Fn, 0, 0).setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+}
+
+static llvm::Value *
+EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcTy, QualType DestTy,
+ llvm::BasicBlock *CastEnd) {
+ const llvm::Type *PtrDiffLTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+ const llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+ if (const PointerType *PTy = DestTy->getAs<PointerType>()) {
+ if (PTy->getPointeeType()->isVoidType()) {
+ // C++ [expr.dynamic.cast]p7:
+ // If T is "pointer to cv void," then the result is a pointer to the
+ // most derived object pointed to by v.
+
+ // Get the vtable pointer.
+ llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo());
+
+ // Get the offset-to-top from the vtable.
+ llvm::Value *OffsetToTop =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);
+ OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top");
+
+ // Finally, add the offset to the pointer.
+ Value = CGF.EmitCastToVoidPtr(Value);
+ Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);
+
+ return CGF.Builder.CreateBitCast(Value, DestLTy);
+ }
}
- if (SrcTy->isPointerType() || SrcTy->isReferenceType())
- SrcTy = SrcTy->getPointeeType();
- SrcTy = SrcTy.getUnqualifiedType();
-
- if (DestTy->isPointerType() || DestTy->isReferenceType())
- DestTy = DestTy->getPointeeType();
- DestTy = DestTy.getUnqualifiedType();
-
- llvm::BasicBlock *ContBlock = createBasicBlock();
- llvm::BasicBlock *NullBlock = 0;
- llvm::BasicBlock *NonZeroBlock = 0;
- if (CanBeZero) {
- NonZeroBlock = createBasicBlock();
- NullBlock = createBasicBlock();
- Builder.CreateCondBr(Builder.CreateIsNotNull(V), NonZeroBlock, NullBlock);
- EmitBlock(NonZeroBlock);
+ QualType SrcRecordTy;
+ QualType DestRecordTy;
+
+ if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) {
+ SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
+ DestRecordTy = DestPTy->getPointeeType();
+ } else {
+ SrcRecordTy = SrcTy;
+ DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
}
- llvm::BasicBlock *BadCastBlock = 0;
+ assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
+ assert(DestRecordTy->isRecordType() && "dest type must be a record type!");
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+ llvm::Value *SrcRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
+ llvm::Value *DestRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
- // See if this is a dynamic_cast(void*)
- if (ToVoid) {
- llvm::Value *This = V;
- V = GetVTablePtr(This, PtrDiffTy->getPointerTo());
- V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL);
- V = Builder.CreateLoad(V, "offset to top");
- This = EmitCastToVoidPtr(This);
- V = Builder.CreateInBoundsGEP(This, V);
- V = Builder.CreateBitCast(V, LTy);
- } else {
- /// Call __dynamic_cast
- const llvm::Type *ResultType = Int8PtrTy;
- const llvm::FunctionType *FTy;
- std::vector<const llvm::Type*> ArgTys;
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(PtrDiffTy);
- FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
-
- // FIXME: Calculate better hint.
- llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL);
-
- assert(SrcTy->isRecordType() && "Src type must be record type!");
- assert(DestTy->isRecordType() && "Dest type must be record type!");
-
- llvm::Value *SrcArg
- = CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType());
- llvm::Value *DestArg
- = CGM.GetAddrOfRTTIDescriptor(DestTy.getUnqualifiedType());
-
- V = Builder.CreateBitCast(V, Int8PtrTy);
- V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"),
- V, SrcArg, DestArg, hint);
- V = Builder.CreateBitCast(V, LTy);
-
- if (ThrowOnBad) {
- BadCastBlock = createBasicBlock();
- Builder.CreateCondBr(Builder.CreateIsNotNull(V), ContBlock, BadCastBlock);
- EmitBlock(BadCastBlock);
- /// Invoke __cxa_bad_cast
- ResultType = llvm::Type::getVoidTy(getLLVMContext());
- const llvm::FunctionType *FBadTy;
- FBadTy = llvm::FunctionType::get(ResultType, false);
- llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast");
- if (llvm::BasicBlock *InvokeDest = getInvokeDest()) {
- llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
- Builder.CreateInvoke(F, Cont, InvokeDest)->setDoesNotReturn();
- EmitBlock(Cont);
- } else {
- // FIXME: Does this ever make sense?
- Builder.CreateCall(F)->setDoesNotReturn();
- }
- Builder.CreateUnreachable();
- }
+ // FIXME: Actually compute a hint here.
+ llvm::Value *OffsetHint = llvm::ConstantInt::get(PtrDiffLTy, -1ULL);
+
+ // Emit the call to __dynamic_cast.
+ Value = CGF.EmitCastToVoidPtr(Value);
+ Value = CGF.Builder.CreateCall4(getDynamicCastFn(CGF), Value,
+ SrcRTTI, DestRTTI, OffsetHint);
+ Value = CGF.Builder.CreateBitCast(Value, DestLTy);
+
+ /// C++ [expr.dynamic.cast]p9:
+ /// A failed cast to reference type throws std::bad_cast
+ if (DestTy->isReferenceType()) {
+ llvm::BasicBlock *BadCastBlock =
+ CGF.createBasicBlock("dynamic_cast.bad_cast");
+
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);
+ CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);
+
+ CGF.EmitBlock(BadCastBlock);
+ EmitBadCastCall(CGF);
}
+
+ return Value;
+}
+
+static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
+ QualType DestTy) {
+ const llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+ if (DestTy->isPointerType())
+ return llvm::Constant::getNullValue(DestLTy);
+
+ /// C++ [expr.dynamic.cast]p9:
+ /// A failed cast to reference type throws std::bad_cast
+ EmitBadCastCall(CGF);
+
+ CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));
+ return llvm::UndefValue::get(DestLTy);
+}
+
+llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
+ const CXXDynamicCastExpr *DCE) {
+ QualType DestTy = DCE->getTypeAsWritten();
+
+ if (DCE->isAlwaysNull())
+ return EmitDynamicCastToNull(*this, DestTy);
+
+ QualType SrcTy = DCE->getSubExpr()->getType();
+
+ // C++ [expr.dynamic.cast]p4:
+ // If the value of v is a null pointer value in the pointer case, the result
+ // is the null pointer value of type T.
+ bool ShouldNullCheckSrcValue = SrcTy->isPointerType();
- if (CanBeZero) {
- Builder.CreateBr(ContBlock);
- EmitBlock(NullBlock);
- Builder.CreateBr(ContBlock);
+ llvm::BasicBlock *CastNull = 0;
+ llvm::BasicBlock *CastNotNull = 0;
+ llvm::BasicBlock *CastEnd = createBasicBlock("dynamic_cast.end");
+
+ if (ShouldNullCheckSrcValue) {
+ CastNull = createBasicBlock("dynamic_cast.null");
+ CastNotNull = createBasicBlock("dynamic_cast.notnull");
+
+ llvm::Value *IsNull = Builder.CreateIsNull(Value);
+ Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
+ EmitBlock(CastNotNull);
+ }
+
+ Value = EmitDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd);
+
+ if (ShouldNullCheckSrcValue) {
+ EmitBranch(CastEnd);
+
+ EmitBlock(CastNull);
+ EmitBranch(CastEnd);
}
- EmitBlock(ContBlock);
- if (CanBeZero) {
- llvm::PHINode *PHI = Builder.CreatePHI(LTy);
- PHI->reserveOperandSpace(2);
- PHI->addIncoming(V, NonZeroBlock);
- PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock);
- V = PHI;
+
+ EmitBlock(CastEnd);
+
+ if (ShouldNullCheckSrcValue) {
+ llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2);
+ PHI->addIncoming(Value, CastNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull);
+
+ Value = PHI;
}
- return V;
+ return Value;
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 7b0292b8f225..bd1958602484 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -108,6 +108,9 @@ public:
}
ComplexPairTy VisitExpr(Expr *S);
ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
+ ComplexPairTy VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ return Visit(GE->getResultExpr());
+ }
ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
// l-values.
@@ -668,14 +671,12 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
eval.end(CGF);
// Create a PHI node for the real part.
- llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r");
- RealPN->reserveOperandSpace(2);
+ llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), 2, "cond.r");
RealPN->addIncoming(LHS.first, LHSBlock);
RealPN->addIncoming(RHS.first, RHSBlock);
// Create a PHI node for the imaginary part.
- llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), "cond.i");
- ImagPN->reserveOperandSpace(2);
+ llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), 2, "cond.i");
ImagPN->addIncoming(LHS.second, LHSBlock);
ImagPN->addIncoming(RHS.second, RHSBlock);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 40d7b6c32e4b..463b913d9285 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -38,8 +38,8 @@ class ConstStructBuilder {
CodeGenFunction *CGF;
bool Packed;
- unsigned NextFieldOffsetInBytes;
- unsigned LLVMStructAlignment;
+ CharUnits NextFieldOffsetInChars;
+ CharUnits LLVMStructAlignment;
std::vector<llvm::Constant *> Elements;
public:
static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
@@ -47,8 +47,9 @@ public:
private:
ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
- : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0),
- LLVMStructAlignment(1) { }
+ : CGM(CGM), CGF(CGF), Packed(false),
+ NextFieldOffsetInChars(CharUnits::Zero()),
+ LLVMStructAlignment(CharUnits::One()) { }
bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitExpr);
@@ -56,64 +57,71 @@ private:
void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::ConstantInt *InitExpr);
- void AppendPadding(uint64_t NumBytes);
+ void AppendPadding(CharUnits PadSize);
- void AppendTailPadding(uint64_t RecordSize);
+ void AppendTailPadding(CharUnits RecordSize);
void ConvertStructToPacked();
bool Build(InitListExpr *ILE);
- unsigned getAlignment(const llvm::Constant *C) const {
- if (Packed) return 1;
- return CGM.getTargetData().getABITypeAlignment(C->getType());
+ CharUnits getAlignment(const llvm::Constant *C) const {
+ if (Packed) return CharUnits::One();
+ return CharUnits::fromQuantity(
+ CGM.getTargetData().getABITypeAlignment(C->getType()));
}
- uint64_t getSizeInBytes(const llvm::Constant *C) const {
- return CGM.getTargetData().getTypeAllocSize(C->getType());
+ CharUnits getSizeInChars(const llvm::Constant *C) const {
+ return CharUnits::fromQuantity(
+ CGM.getTargetData().getTypeAllocSize(C->getType()));
}
};
bool ConstStructBuilder::
AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitCst) {
- uint64_t FieldOffsetInBytes = FieldOffset / 8;
- assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
+ const ASTContext &Context = CGM.getContext();
+
+ CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset);
+
+ assert(NextFieldOffsetInChars <= FieldOffsetInChars
&& "Field offset mismatch!");
- unsigned FieldAlignment = getAlignment(InitCst);
+ CharUnits FieldAlignment = getAlignment(InitCst);
// Round up the field offset to the alignment of the field type.
- uint64_t AlignedNextFieldOffsetInBytes =
- llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
+ CharUnits AlignedNextFieldOffsetInChars =
+ NextFieldOffsetInChars.RoundUpToAlignment(FieldAlignment);
- if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
+ if (AlignedNextFieldOffsetInChars > FieldOffsetInChars) {
assert(!Packed && "Alignment is wrong even with a packed struct!");
// Convert the struct to a packed struct.
ConvertStructToPacked();
- AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ AlignedNextFieldOffsetInChars = NextFieldOffsetInChars;
}
- if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
+ if (AlignedNextFieldOffsetInChars < FieldOffsetInChars) {
// We need to append padding.
- AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes);
+ AppendPadding(
+ FieldOffsetInChars - NextFieldOffsetInChars);
- assert(NextFieldOffsetInBytes == FieldOffsetInBytes &&
+ assert(NextFieldOffsetInChars == FieldOffsetInChars &&
"Did not add enough padding!");
- AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ AlignedNextFieldOffsetInChars = NextFieldOffsetInChars;
}
// Add the field.
Elements.push_back(InitCst);
- NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes +
- getSizeInBytes(InitCst);
+ NextFieldOffsetInChars = AlignedNextFieldOffsetInChars +
+ getSizeInChars(InitCst);
if (Packed)
- assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!");
+ assert(LLVMStructAlignment == CharUnits::One() &&
+ "Packed struct not byte-aligned!");
else
LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
@@ -123,17 +131,20 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset,
void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
uint64_t FieldOffset,
llvm::ConstantInt *CI) {
- if (FieldOffset > NextFieldOffsetInBytes * 8) {
+ const ASTContext &Context = CGM.getContext();
+ const uint64_t CharWidth = Context.getCharWidth();
+ uint64_t NextFieldOffsetInBits = Context.toBits(NextFieldOffsetInChars);
+ if (FieldOffset > NextFieldOffsetInBits) {
// We need to add padding.
- uint64_t NumBytes =
- llvm::RoundUpToAlignment(FieldOffset -
- NextFieldOffsetInBytes * 8, 8) / 8;
+ CharUnits PadSize = Context.toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(FieldOffset - NextFieldOffsetInBits,
+ Context.Target.getCharAlign()));
- AppendPadding(NumBytes);
+ AppendPadding(PadSize);
}
uint64_t FieldSize =
- Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue();
+ Field->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
llvm::APInt FieldValue = CI->getValue();
@@ -148,13 +159,13 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
if (FieldSize < FieldValue.getBitWidth())
FieldValue = FieldValue.trunc(FieldSize);
- if (FieldOffset < NextFieldOffsetInBytes * 8) {
+ NextFieldOffsetInBits = Context.toBits(NextFieldOffsetInChars);
+ if (FieldOffset < NextFieldOffsetInBits) {
// Either part of the field or the entire field can go into the previous
// byte.
assert(!Elements.empty() && "Elements can't be empty!");
- unsigned BitsInPreviousByte =
- NextFieldOffsetInBytes * 8 - FieldOffset;
+ unsigned BitsInPreviousByte = NextFieldOffsetInBits - FieldOffset;
bool FitsCompletelyInPreviousByte =
BitsInPreviousByte >= FieldValue.getBitWidth();
@@ -179,12 +190,12 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
}
}
- Tmp = Tmp.zext(8);
+ Tmp = Tmp.zext(CharWidth);
if (CGM.getTargetData().isBigEndian()) {
if (FitsCompletelyInPreviousByte)
Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
} else {
- Tmp = Tmp.shl(8 - BitsInPreviousByte);
+ Tmp = Tmp.shl(CharWidth - BitsInPreviousByte);
}
// 'or' in the bits that go into the previous byte.
@@ -203,19 +214,19 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
assert(isa<llvm::ArrayType>(LastElt->getType()) &&
"Expected array padding of undefs");
const llvm::ArrayType *AT = cast<llvm::ArrayType>(LastElt->getType());
- assert(AT->getElementType()->isIntegerTy(8) &&
+ assert(AT->getElementType()->isIntegerTy(CharWidth) &&
AT->getNumElements() != 0 &&
"Expected non-empty array padding of undefs");
// Remove the padding array.
- NextFieldOffsetInBytes -= AT->getNumElements();
+ NextFieldOffsetInChars -= CharUnits::fromQuantity(AT->getNumElements());
Elements.pop_back();
// Add the padding back in two chunks.
- AppendPadding(AT->getNumElements()-1);
- AppendPadding(1);
+ AppendPadding(CharUnits::fromQuantity(AT->getNumElements()-1));
+ AppendPadding(CharUnits::One());
assert(isa<llvm::UndefValue>(Elements.back()) &&
- Elements.back()->getType()->isIntegerTy(8) &&
+ Elements.back()->getType()->isIntegerTy(CharWidth) &&
"Padding addition didn't work right");
}
}
@@ -226,105 +237,104 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
return;
}
- while (FieldValue.getBitWidth() > 8) {
+ while (FieldValue.getBitWidth() > CharWidth) {
llvm::APInt Tmp;
if (CGM.getTargetData().isBigEndian()) {
// We want the high bits.
- Tmp = FieldValue.lshr(FieldValue.getBitWidth() - 8).trunc(8);
+ Tmp =
+ FieldValue.lshr(FieldValue.getBitWidth() - CharWidth).trunc(CharWidth);
} else {
// We want the low bits.
- Tmp = FieldValue.trunc(8);
+ Tmp = FieldValue.trunc(CharWidth);
- FieldValue = FieldValue.lshr(8);
+ FieldValue = FieldValue.lshr(CharWidth);
}
Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
- NextFieldOffsetInBytes++;
+ ++NextFieldOffsetInChars;
- FieldValue = FieldValue.trunc(FieldValue.getBitWidth() - 8);
+ FieldValue = FieldValue.trunc(FieldValue.getBitWidth() - CharWidth);
}
assert(FieldValue.getBitWidth() > 0 &&
"Should have at least one bit left!");
- assert(FieldValue.getBitWidth() <= 8 &&
+ assert(FieldValue.getBitWidth() <= CharWidth &&
"Should not have more than a byte left!");
- if (FieldValue.getBitWidth() < 8) {
+ if (FieldValue.getBitWidth() < CharWidth) {
if (CGM.getTargetData().isBigEndian()) {
unsigned BitWidth = FieldValue.getBitWidth();
- FieldValue = FieldValue.zext(8) << (8 - BitWidth);
+ FieldValue = FieldValue.zext(CharWidth) << (CharWidth - BitWidth);
} else
- FieldValue = FieldValue.zext(8);
+ FieldValue = FieldValue.zext(CharWidth);
}
// Append the last element.
Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(),
FieldValue));
- NextFieldOffsetInBytes++;
+ ++NextFieldOffsetInChars;
}
-void ConstStructBuilder::AppendPadding(uint64_t NumBytes) {
- if (!NumBytes)
+void ConstStructBuilder::AppendPadding(CharUnits PadSize) {
+ if (PadSize.isZero())
return;
const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- if (NumBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumBytes);
+ if (PadSize > CharUnits::One())
+ Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity());
llvm::Constant *C = llvm::UndefValue::get(Ty);
Elements.push_back(C);
- assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!");
+ assert(getAlignment(C) == CharUnits::One() &&
+ "Padding must have 1 byte alignment!");
- NextFieldOffsetInBytes += getSizeInBytes(C);
+ NextFieldOffsetInChars += getSizeInChars(C);
}
-void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) {
- assert(RecordSize % 8 == 0 && "Invalid record size!");
+void ConstStructBuilder::AppendTailPadding(CharUnits RecordSize) {
+ assert(NextFieldOffsetInChars <= RecordSize &&
+ "Size mismatch!");
- uint64_t RecordSizeInBytes = RecordSize / 8;
- assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
-
- unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
- AppendPadding(NumPadBytes);
+ AppendPadding(RecordSize - NextFieldOffsetInChars);
}
void ConstStructBuilder::ConvertStructToPacked() {
std::vector<llvm::Constant *> PackedElements;
- uint64_t ElementOffsetInBytes = 0;
+ CharUnits ElementOffsetInChars = CharUnits::Zero();
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
llvm::Constant *C = Elements[i];
- unsigned ElementAlign =
- CGM.getTargetData().getABITypeAlignment(C->getType());
- uint64_t AlignedElementOffsetInBytes =
- llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
+ CharUnits ElementAlign = CharUnits::fromQuantity(
+ CGM.getTargetData().getABITypeAlignment(C->getType()));
+ CharUnits AlignedElementOffsetInChars =
+ ElementOffsetInChars.RoundUpToAlignment(ElementAlign);
- if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
+ if (AlignedElementOffsetInChars > ElementOffsetInChars) {
// We need some padding.
- uint64_t NumBytes =
- AlignedElementOffsetInBytes - ElementOffsetInBytes;
+ CharUnits NumChars =
+ AlignedElementOffsetInChars - ElementOffsetInChars;
const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- if (NumBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumBytes);
+ if (NumChars > CharUnits::One())
+ Ty = llvm::ArrayType::get(Ty, NumChars.getQuantity());
llvm::Constant *Padding = llvm::UndefValue::get(Ty);
PackedElements.push_back(Padding);
- ElementOffsetInBytes += getSizeInBytes(Padding);
+ ElementOffsetInChars += getSizeInChars(Padding);
}
PackedElements.push_back(C);
- ElementOffsetInBytes += getSizeInBytes(C);
+ ElementOffsetInChars += getSizeInChars(C);
}
- assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
+ assert(ElementOffsetInChars == NextFieldOffsetInChars &&
"Packing the struct changed its size!");
Elements = PackedElements;
- LLVMStructAlignment = 1;
+ LLVMStructAlignment = CharUnits::One();
Packed = true;
}
@@ -334,16 +344,31 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
unsigned FieldNo = 0;
unsigned ElementNo = 0;
+ const FieldDecl *LastFD = 0;
+ bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+
for (RecordDecl::field_iterator Field = RD->field_begin(),
FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are
+ // ignored:
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD) ||
+ CGM.getContext().ZeroBitfieldFollowsBitfield((*Field), LastFD)) {
+ --FieldNo;
+ continue;
+ }
+ LastFD = (*Field);
+ }
// If this is a union, skip all the fields that aren't being initialized.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
continue;
// Don't emit anonymous bitfields, they just affect layout.
- if (Field->isBitField() && !Field->getIdentifier())
+ if (Field->isBitField() && !Field->getIdentifier()) {
+ LastFD = (*Field);
continue;
+ }
// Get the initializer. A struct can include fields without initializers,
// we just use explicit null values for them.
@@ -368,9 +393,9 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
}
}
- uint64_t LayoutSizeInBytes = Layout.getSize().getQuantity();
+ CharUnits LayoutSizeInChars = Layout.getSize();
- if (NextFieldOffsetInBytes > LayoutSizeInBytes) {
+ if (NextFieldOffsetInChars > LayoutSizeInChars) {
// If the struct is bigger than the size of the record type,
// we must have a flexible array member at the end.
assert(RD->hasFlexibleArrayMember() &&
@@ -380,23 +405,23 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
return true;
}
- uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
- LLVMStructAlignment);
+ CharUnits LLVMSizeInChars =
+ NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
// Check if we need to convert the struct to a packed struct.
- if (NextFieldOffsetInBytes <= LayoutSizeInBytes &&
- LLVMSizeInBytes > LayoutSizeInBytes) {
+ if (NextFieldOffsetInChars <= LayoutSizeInChars &&
+ LLVMSizeInChars > LayoutSizeInChars) {
assert(!Packed && "Size mismatch!");
ConvertStructToPacked();
- assert(NextFieldOffsetInBytes <= LayoutSizeInBytes &&
+ assert(NextFieldOffsetInChars <= LayoutSizeInChars &&
"Converting to packed did not help!");
}
// Append tail padding if necessary.
- AppendTailPadding(CGM.getContext().toBits(Layout.getSize()));
+ AppendTailPadding(LayoutSizeInChars);
- assert(Layout.getSize().getQuantity() == NextFieldOffsetInBytes &&
+ assert(LayoutSizeInChars == NextFieldOffsetInChars &&
"Tail padding mismatch!");
return true;
@@ -413,9 +438,9 @@ llvm::Constant *ConstStructBuilder::
llvm::ConstantStruct::get(CGM.getLLVMContext(),
Builder.Elements, Builder.Packed);
- assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes,
- Builder.getAlignment(Result)) ==
- Builder.getSizeInBytes(Result) && "Size mismatch!");
+ assert(Builder.NextFieldOffsetInChars.RoundUpToAlignment(
+ Builder.getAlignment(Result)) ==
+ Builder.getSizeInChars(Result) && "Size mismatch!");
return Result;
}
@@ -447,6 +472,10 @@ public:
return Visit(PE->getSubExpr());
}
+ llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ return Visit(GE->getResultExpr());
+ }
+
llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return Visit(E->getInitializer());
}
@@ -480,18 +509,17 @@ public:
}
llvm::Constant *VisitCastExpr(CastExpr* E) {
+ Expr *subExpr = E->getSubExpr();
+ llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF);
+ if (!C) return 0;
+
+ const llvm::Type *destType = ConvertType(E->getType());
+
switch (E->getCastKind()) {
case CK_ToUnion: {
// GCC cast to union extension
assert(E->getType()->isUnionType() &&
"Destination type is not union type!");
- const llvm::Type *Ty = ConvertType(E->getType());
- Expr *SubExpr = E->getSubExpr();
-
- llvm::Constant *C =
- CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF);
- if (!C)
- return 0;
// Build a struct with the union sub-element as the first member,
// and padded to the appropriate size
@@ -500,7 +528,7 @@ public:
Elts.push_back(C);
Types.push_back(C->getType());
unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType());
- unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(Ty);
+ unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(destType);
assert(CurSize <= TotalSize && "Union size mismatch!");
if (unsigned NumPadBytes = TotalSize - CurSize) {
@@ -520,40 +548,103 @@ public:
const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
return CGM.getCXXABI().EmitNullMemberPointer(MPT);
}
-
- case CK_BaseToDerivedMemberPointer: {
- Expr *SubExpr = E->getSubExpr();
- llvm::Constant *C =
- CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF);
- if (!C) return 0;
+ case CK_DerivedToBaseMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
return CGM.getCXXABI().EmitMemberPointerConversion(C, E);
- }
- case CK_BitCast:
- // This must be a member function pointer cast.
- return Visit(E->getSubExpr());
-
- default: {
- // FIXME: This should be handled by the CK_NoOp cast kind.
- // Explicit and implicit no-op casts
- QualType Ty = E->getType(), SubTy = E->getSubExpr()->getType();
- if (CGM.getContext().hasSameUnqualifiedType(Ty, SubTy))
- return Visit(E->getSubExpr());
-
- // Handle integer->integer casts for address-of-label differences.
- if (Ty->isIntegerType() && SubTy->isIntegerType() &&
- CGF) {
- llvm::Value *Src = Visit(E->getSubExpr());
- if (Src == 0) return 0;
-
- // Use EmitScalarConversion to perform the conversion.
- return cast<llvm::Constant>(CGF->EmitScalarConversion(Src, SubTy, Ty));
- }
-
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return C;
+
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_LValueBitCast:
+ case CK_BitCast:
+ if (C->getType() == destType) return C;
+ return llvm::ConstantExpr::getBitCast(C, destType);
+
+ case CK_Dependent: llvm_unreachable("saw dependent cast!");
+
+ // These will never be supported.
+ case CK_ObjCObjectLValueCast:
+ case CK_GetObjCProperty:
+ case CK_ToVoid:
+ case CK_Dynamic:
return 0;
+
+ // These might need to be supported for constexpr.
+ case CK_UserDefinedConversion:
+ case CK_ConstructorConversion:
+ return 0;
+
+ // These should eventually be supported.
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_MemberPointerToBoolean:
+ case CK_VectorSplat:
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexToBoolean:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralComplexToBoolean:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ return 0;
+
+ case CK_PointerToIntegral:
+ if (!E->getType()->isBooleanType())
+ return llvm::ConstantExpr::getPtrToInt(C, destType);
+ // fallthrough
+
+ case CK_PointerToBoolean:
+ return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C,
+ llvm::ConstantPointerNull::get(cast<llvm::PointerType>(C->getType())));
+
+ case CK_NullToPointer:
+ return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(destType));
+
+ case CK_IntegralCast: {
+ bool isSigned = subExpr->getType()->isSignedIntegerType();
+ return llvm::ConstantExpr::getIntegerCast(C, destType, isSigned);
+ }
+
+ case CK_IntegralToPointer: {
+ bool isSigned = subExpr->getType()->isSignedIntegerType();
+ C = llvm::ConstantExpr::getIntegerCast(C, CGM.IntPtrTy, isSigned);
+ return llvm::ConstantExpr::getIntToPtr(C, destType);
}
+
+ case CK_IntegralToBoolean:
+ return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C,
+ llvm::Constant::getNullValue(C->getType()));
+
+ case CK_IntegralToFloating:
+ if (subExpr->getType()->isSignedIntegerType())
+ return llvm::ConstantExpr::getSIToFP(C, destType);
+ else
+ return llvm::ConstantExpr::getUIToFP(C, destType);
+
+ case CK_FloatingToIntegral:
+ if (E->getType()->isSignedIntegerType())
+ return llvm::ConstantExpr::getFPToSI(C, destType);
+ else
+ return llvm::ConstantExpr::getFPToUI(C, destType);
+
+ case CK_FloatingToBoolean:
+ return llvm::ConstantExpr::getFCmp(llvm::CmpInst::FCMP_UNE, C,
+ llvm::Constant::getNullValue(C->getType()));
+
+ case CK_FloatingCast:
+ return llvm::ConstantExpr::getFPCast(C, destType);
}
+ llvm_unreachable("Invalid CastKind");
}
llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
@@ -562,7 +653,7 @@ public:
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
unsigned NumInitElements = ILE->getNumInits();
- if (NumInitElements == 1 &&
+ if (NumInitElements == 1 && ILE->getType() == ILE->getInit(0)->getType() &&
(isa<StringLiteral>(ILE->getInit(0)) ||
isa<ObjCEncodeExpr>(ILE->getInit(0))))
return Visit(ILE->getInit(0));
@@ -591,8 +682,16 @@ public:
// Initialize remaining array elements.
// FIXME: This doesn't handle member pointers correctly!
+ llvm::Constant *fillC;
+ if (Expr *filler = ILE->getArrayFiller())
+ fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
+ else
+ fillC = llvm::Constant::getNullValue(ElemTy);
+ if (!fillC)
+ return 0;
+ RewriteType |= (fillC->getType() != ElemTy);
for (; i < NumElements; ++i)
- Elts.push_back(llvm::Constant::getNullValue(ElemTy));
+ Elts.push_back(fillC);
if (RewriteType) {
// FIXME: Try to avoid packing the array
@@ -730,7 +829,7 @@ public:
E->getType().isConstant(CGM.getContext()),
llvm::GlobalValue::InternalLinkage,
C, ".compoundliteral", 0, false,
- E->getType().getAddressSpace());
+ CGM.getContext().getTargetAddressSpace(E->getType()));
return C;
}
case Expr::DeclRefExprClass: {
@@ -907,12 +1006,29 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
llvm::SmallVector<llvm::Constant *, 4> Inits;
unsigned NumElts = Result.Val.getVectorLength();
- for (unsigned i = 0; i != NumElts; ++i) {
- APValue &Elt = Result.Val.getVectorElt(i);
- if (Elt.isInt())
- Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt()));
- else
- Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat()));
+ if (Context.getLangOptions().AltiVec &&
+ isa<CastExpr>(E) &&
+ cast<CastExpr>(E)->getCastKind() == CK_VectorSplat) {
+ // AltiVec vector initialization with a single literal
+ APValue &Elt = Result.Val.getVectorElt(0);
+
+ llvm::Constant* InitValue = Elt.isInt()
+ ? cast<llvm::Constant>
+ (llvm::ConstantInt::get(VMContext, Elt.getInt()))
+ : cast<llvm::Constant>
+ (llvm::ConstantFP::get(VMContext, Elt.getFloat()));
+
+ for (unsigned i = 0; i != NumElts; ++i)
+ Inits.push_back(InitValue);
+
+ } else {
+ for (unsigned i = 0; i != NumElts; ++i) {
+ APValue &Elt = Result.Val.getVectorElt(i);
+ if (Elt.isInt())
+ Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt()));
+ else
+ Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat()));
+ }
}
return llvm::ConstantVector::get(Inits);
}
@@ -963,7 +1079,8 @@ static void
FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
std::vector<llvm::Constant *> &Elements,
uint64_t StartOffset) {
- assert(StartOffset % 8 == 0 && "StartOffset not byte aligned!");
+ assert(StartOffset % CGM.getContext().getCharWidth() == 0 &&
+ "StartOffset not byte aligned!");
if (CGM.getTypes().isZeroInitializable(T))
return;
@@ -1022,8 +1139,8 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
"Should only see pointers to data members here!");
- uint64_t StartIndex = StartOffset / 8;
- uint64_t EndIndex = StartIndex + CGM.getContext().getTypeSize(T) / 8;
+ CharUnits StartIndex = CGM.getContext().toCharUnitsFromBits(StartOffset);
+ CharUnits EndIndex = StartIndex + CGM.getContext().getTypeSizeInChars(T);
// FIXME: hardcodes Itanium member pointer representation!
llvm::Constant *NegativeOne =
@@ -1031,8 +1148,8 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
-1ULL, /*isSigned*/true);
// Fill in the null data member pointer.
- for (uint64_t I = StartIndex; I != EndIndex; ++I)
- Elements[I] = NegativeOne;
+ for (CharUnits I = StartIndex; I != EndIndex; ++I)
+ Elements[I.getQuantity()] = NegativeOne;
}
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 3e1debd820b4..6bcc425ce62f 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -140,9 +140,7 @@ public:
}
}
- const llvm::IntegerType *Ty = cast<llvm::IntegerType>(V->getType());
- Value *Zero = llvm::ConstantInt::get(Ty, 0);
- return Builder.CreateICmpNE(V, Zero, "tobool");
+ return Builder.CreateIsNotNull(V, "tobool");
}
//===--------------------------------------------------------------------===//
@@ -163,10 +161,13 @@ public:
Value *VisitParenExpr(ParenExpr *PE) {
return Visit(PE->getSubExpr());
}
+ Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ return Visit(GE->getResultExpr());
+ }
// Leaves.
Value *VisitIntegerLiteral(const IntegerLiteral *E) {
- return llvm::ConstantInt::get(VMContext, E->getValue());
+ return Builder.getInt(E->getValue());
}
Value *VisitFloatingLiteral(const FloatingLiteral *E) {
return llvm::ConstantFP::get(VMContext, E->getValue());
@@ -184,15 +185,14 @@ public:
return EmitNullValue(E->getType());
}
Value *VisitOffsetOfExpr(OffsetOfExpr *E);
- Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
+ Value *VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel());
return Builder.CreateBitCast(V, ConvertType(E->getType()));
}
Value *VisitSizeOfPackExpr(SizeOfPackExpr *E) {
- return llvm::ConstantInt::get(ConvertType(E->getType()),
- E->getPackLength());
+ return llvm::ConstantInt::get(ConvertType(E->getType()),E->getPackLength());
}
Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
@@ -212,13 +212,12 @@ public:
assert(!Result.HasSideEffects && "Constant declref with side-effect?!");
llvm::Constant *C;
- if (Result.Val.isInt()) {
- C = llvm::ConstantInt::get(VMContext, Result.Val.getInt());
- } else if (Result.Val.isFloat()) {
+ if (Result.Val.isInt())
+ C = Builder.getInt(Result.Val.getInt());
+ else if (Result.Val.isFloat())
C = llvm::ConstantFP::get(VMContext, Result.Val.getFloat());
- } else {
+ else
return EmitLoadOfLValue(E);
- }
// Make sure we emit a debug reference to the global variable.
if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
@@ -245,6 +244,9 @@ public:
return EmitLoadOfLValue(E);
}
Value *VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (E->getMethodDecl() &&
+ E->getMethodDecl()->getResultType()->isReferenceType())
+ return EmitLoadOfLValue(E);
return CGF.EmitObjCMessageExpr(E).getScalarVal();
}
@@ -358,13 +360,21 @@ public:
return 0;
}
Value *VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
- return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue());
+ return Builder.getInt1(E->getValue());
}
Value *VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) {
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
+ Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
+ return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue());
+ }
+
+ Value *VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
+ return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue());
+ }
+
Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) {
// C++ [expr.pseudo]p1:
// The result shall only be used as the operand for the function call
@@ -385,7 +395,7 @@ public:
}
Value *VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
- return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue());
+ return Builder.getInt1(E->getValue());
}
// Binary Operators.
@@ -579,14 +589,14 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// Insert the element in element zero of an undef vector
llvm::Value *UnV = llvm::UndefValue::get(DstTy);
- llvm::Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, 0);
+ llvm::Value *Idx = Builder.getInt32(0);
UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp");
// Splat the element across to all elements
llvm::SmallVector<llvm::Constant*, 16> Args;
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
for (unsigned i = 0; i != NumElements; ++i)
- Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0));
+ Args.push_back(Builder.getInt32(0));
llvm::Constant *Mask = llvm::ConstantVector::get(Args);
llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
@@ -683,8 +693,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
// Shuffle LHS & RHS into one input vector.
llvm::SmallVector<llvm::Constant*, 32> concat;
for (unsigned i = 0; i != LHSElts; ++i) {
- concat.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 2*i));
- concat.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 2*i+1));
+ concat.push_back(Builder.getInt32(2*i));
+ concat.push_back(Builder.getInt32(2*i+1));
}
Value* CV = llvm::ConstantVector::get(concat);
@@ -726,18 +736,16 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
MTy->getNumElements());
Value* NewV = llvm::UndefValue::get(RTy);
for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) {
- Value *Indx = llvm::ConstantInt::get(CGF.Int32Ty, i);
+ Value *Indx = Builder.getInt32(i);
Indx = Builder.CreateExtractElement(Mask, Indx, "shuf_idx");
Indx = Builder.CreateZExt(Indx, CGF.Int32Ty, "idx_zext");
// Handle vec3 special since the index will be off by one for the RHS.
if ((LHSElts == 6) && (E->getNumSubExprs() == 3)) {
Value *cmpIndx, *newIndx;
- cmpIndx = Builder.CreateICmpUGT(Indx,
- llvm::ConstantInt::get(CGF.Int32Ty, 3),
+ cmpIndx = Builder.CreateICmpUGT(Indx, Builder.getInt32(3),
"cmp_shuf_idx");
- newIndx = Builder.CreateSub(Indx, llvm::ConstantInt::get(CGF.Int32Ty,1),
- "shuf_idx_adj");
+ newIndx = Builder.CreateSub(Indx, Builder.getInt32(1), "shuf_idx_adj");
Indx = Builder.CreateSelect(cmpIndx, newIndx, Indx, "sel_shuf_idx");
}
Value *VExt = Builder.CreateExtractElement(LHS, Indx, "shuf_elt");
@@ -775,7 +783,7 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
CGF.EmitScalarExpr(E->getBase());
else
EmitLValue(E->getBase());
- return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+ return Builder.getInt(Result.Val.getInt());
}
// Emit debug info for aggregate now, if it was delayed to reduce
@@ -875,8 +883,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
llvm::ShuffleVectorInst *SVV = cast<llvm::ShuffleVectorInst>(V);
for (unsigned j = 0; j != CurIdx; ++j)
Args.push_back(getMaskElt(SVV, j, 0, CGF.Int32Ty));
- Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty,
- ResElts + C->getZExtValue()));
+ Args.push_back(Builder.getInt32(ResElts + C->getZExtValue()));
for (unsigned j = CurIdx + 1; j != ResElts; ++j)
Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
@@ -892,8 +899,8 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
}
}
}
- Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, CurIdx);
- V = Builder.CreateInsertElement(V, Init, Idx, "vecinit");
+ V = Builder.CreateInsertElement(V, Init, Builder.getInt32(CurIdx),
+ "vecinit");
VIsUndefShuffle = false;
++CurIdx;
continue;
@@ -918,7 +925,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
Args.push_back(getMaskElt(cast<llvm::ShuffleVectorInst>(V), j, 0,
CGF.Int32Ty));
} else {
- Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j));
+ Args.push_back(Builder.getInt32(j));
}
}
for (unsigned j = 0, je = InitElts; j != je; ++j)
@@ -937,7 +944,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
// to the vector initializer into V.
if (Args.empty()) {
for (unsigned j = 0; j != InitElts; ++j)
- Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j));
+ Args.push_back(Builder.getInt32(j));
for (unsigned j = InitElts; j != ResElts; ++j)
Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
llvm::Constant *Mask = llvm::ConstantVector::get(Args);
@@ -946,9 +953,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
Args.clear();
for (unsigned j = 0; j != CurIdx; ++j)
- Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j));
+ Args.push_back(Builder.getInt32(j));
for (unsigned j = 0; j != InitElts; ++j)
- Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j+Offset));
+ Args.push_back(Builder.getInt32(j+Offset));
for (unsigned j = CurIdx + InitElts; j != ResElts; ++j)
Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
}
@@ -969,7 +976,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Emit remaining default initializers
for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) {
- Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, CurIdx);
+ Value *Idx = Builder.getInt32(CurIdx);
llvm::Value *Init = llvm::Constant::getNullValue(EltTy);
V = Builder.CreateInsertElement(V, Init, Idx, "vecinit");
}
@@ -1123,7 +1130,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType());
return RV.getScalarVal();
}
-
+
case CK_LValueToRValue:
assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
assert(E->isGLValue() && "lvalue-to-rvalue applied to r-value!");
@@ -1160,13 +1167,13 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
// Insert the element in element zero of an undef vector
llvm::Value *UnV = llvm::UndefValue::get(DstTy);
- llvm::Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, 0);
+ llvm::Value *Idx = Builder.getInt32(0);
UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp");
// Splat the element across to all elements
llvm::SmallVector<llvm::Constant*, 16> Args;
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Int32Ty, 0);
+ llvm::Constant *Zero = Builder.getInt32(0);
for (unsigned i = 0; i < NumElements; i++)
Args.push_back(Zero);
@@ -1218,10 +1225,8 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
}
Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
- llvm::Value *V = CGF.GetAddrOfBlockDecl(E);
- if (E->getType().isObjCGCWeak())
- return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V);
- return CGF.EmitLoadOfScalar(V, false, 0, E->getType());
+ LValue LV = CGF.EmitBlockDeclRefLValue(E);
+ return CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal();
}
//===----------------------------------------------------------------------===//
@@ -1278,10 +1283,12 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount);
- if (type->isSignedIntegerType())
+ // Note that signed integer inc/dec with width less than int can't
+ // overflow because of promotion rules; we're just eliding a few steps here.
+ if (type->isSignedIntegerType() &&
+ value->getType()->getPrimitiveSizeInBits() >=
+ CGF.CGM.IntTy->getBitWidth())
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
-
- // Unsigned integer inc is always two's complement.
else
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
@@ -1295,21 +1302,30 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
CGF.GetVLASize(CGF.getContext().getAsVariableArrayType(type));
value = CGF.EmitCastToVoidPtr(value);
if (!isInc) vlaSize = Builder.CreateNSWNeg(vlaSize, "vla.negsize");
- value = Builder.CreateInBoundsGEP(value, vlaSize, "vla.inc");
+ if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ value = Builder.CreateGEP(value, vlaSize, "vla.inc");
+ else
+ value = Builder.CreateInBoundsGEP(value, vlaSize, "vla.inc");
value = Builder.CreateBitCast(value, input->getType());
// Arithmetic on function pointers (!) is just +-1.
} else if (type->isFunctionType()) {
- llvm::Value *amt = llvm::ConstantInt::get(CGF.Int32Ty, amount);
+ llvm::Value *amt = Builder.getInt32(amount);
value = CGF.EmitCastToVoidPtr(value);
- value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
+ if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ value = Builder.CreateGEP(value, amt, "incdec.funcptr");
+ else
+ value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
value = Builder.CreateBitCast(value, input->getType());
// For everything else, we can just do a simple increment.
} else {
- llvm::Value *amt = llvm::ConstantInt::get(CGF.Int32Ty, amount);
- value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
+ llvm::Value *amt = Builder.getInt32(amount);
+ if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ value = Builder.CreateGEP(value, amt, "incdec.ptr");
+ else
+ value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
}
// Vector increment/decrement.
@@ -1357,7 +1373,10 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *sizeValue =
llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity());
- value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
+ if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
+ else
+ value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
value = Builder.CreateBitCast(value, input->getType());
}
@@ -1413,7 +1432,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
// Try folding the offsetof to a constant.
Expr::EvalResult EvalResult;
if (E->Evaluate(EvalResult, CGF.getContext()))
- return llvm::ConstantInt::get(VMContext, EvalResult.Val.getInt());
+ return Builder.getInt(EvalResult.Val.getInt());
// Loop over the components of the offsetof to compute the value.
unsigned n = E->getNumComponents();
@@ -1499,12 +1518,13 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
return Result;
}
-/// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of
+/// VisitUnaryExprOrTypeTraitExpr - Return the size or alignment of the type of
/// argument of the sizeof expression as an integer.
Value *
-ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
+ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *E) {
QualType TypeToSize = E->getTypeOfArgument();
- if (E->isSizeOf()) {
+ if (E->getKind() == UETT_SizeOf) {
if (const VariableArrayType *VAT =
CGF.getContext().getAsVariableArrayType(TypeToSize)) {
if (E->isArgumentType()) {
@@ -1524,7 +1544,7 @@ ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
// folding logic so we don't have to duplicate it here.
Expr::EvalResult Result;
E->Evaluate(Result, CGF.getContext());
- return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+ return Builder.getInt(Result.Val.getInt());
}
Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
@@ -1664,8 +1684,7 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
if (Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::Value *IntMin =
- llvm::ConstantInt::get(VMContext,
- llvm::APInt::getSignedMinValue(Ty->getBitWidth()));
+ Builder.getInt(llvm::APInt::getSignedMinValue(Ty->getBitWidth()));
llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL);
llvm::Value *Cond1 = Builder.CreateICmpEQ(Ops.RHS, Zero);
@@ -1715,7 +1734,7 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
}
- if (Ops.Ty->isUnsignedIntegerType())
+ if (Ops.Ty->hasUnsignedIntegerRepresentation())
return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem");
else
return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem");
@@ -1801,8 +1820,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Builder.CreateBr(continueBB);
Builder.SetInsertPoint(continueBB);
- llvm::PHINode *phi = Builder.CreatePHI(opTy);
- phi->reserveOperandSpace(2);
+ llvm::PHINode *phi = Builder.CreatePHI(opTy, 2);
phi->addIncoming(result, initialBB);
phi->addIncoming(handlerResult, overflowBB);
@@ -1889,6 +1907,8 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
return Builder.CreateBitCast(Res, Ptr->getType());
}
+ if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ return Builder.CreateGEP(Ptr, Idx, "add.ptr");
return Builder.CreateInBoundsGEP(Ptr, Idx, "add.ptr");
}
@@ -1964,38 +1984,39 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
return Builder.CreateBitCast(Res, Ops.LHS->getType());
}
+ if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr");
return Builder.CreateInBoundsGEP(Ops.LHS, Idx, "sub.ptr");
- } else {
- // pointer - pointer
- Value *LHS = Ops.LHS;
- Value *RHS = Ops.RHS;
-
- CharUnits ElementSize;
-
- // Handle GCC extension for pointer arithmetic on void* and function pointer
- // types.
- if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
- ElementSize = CharUnits::One();
- } else {
- ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType);
- }
-
- const llvm::Type *ResultType = ConvertType(Ops.Ty);
- LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast");
- RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
- Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
+ }
+
+ // pointer - pointer
+ Value *LHS = Ops.LHS;
+ Value *RHS = Ops.RHS;
- // Optimize out the shift for element size of 1.
- if (ElementSize.isOne())
- return BytesBetween;
+ CharUnits ElementSize;
- // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
- // pointer difference in C is only defined in the case where both operands
- // are pointing to elements of an array.
- Value *BytesPerElt =
- llvm::ConstantInt::get(ResultType, ElementSize.getQuantity());
- return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
- }
+ // Handle GCC extension for pointer arithmetic on void* and function pointer
+ // types.
+ if (LHSElementType->isVoidType() || LHSElementType->isFunctionType())
+ ElementSize = CharUnits::One();
+ else
+ ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType);
+
+ const llvm::Type *ResultType = ConvertType(Ops.Ty);
+ LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast");
+ RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
+ Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
+
+ // Optimize out the shift for element size of 1.
+ if (ElementSize.isOne())
+ return BytesBetween;
+
+ // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
+ // pointer difference in C is only defined in the case where both operands
+ // are pointing to elements of an array.
+ Value *BytesPerElt =
+ llvm::ConstantInt::get(ResultType, ElementSize.getQuantity());
+ return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
}
Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
@@ -2100,7 +2121,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
// If AltiVec, the comparison results in a numeric type, so we use
// intrinsics comparing vectors and giving 0 or 1 as a result
- if (LHSTy->isVectorType() && CGF.getContext().getLangOptions().AltiVec) {
+ if (LHSTy->isVectorType() && !E->getType()->isVectorType()) {
// constants for mapping CR6 register bits to predicate result
enum { CR6_EQ=0, CR6_EQ_REV, CR6_LT, CR6_LT_REV } CR6;
@@ -2157,7 +2178,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
break;
}
- Value *CR6Param = llvm::ConstantInt::get(CGF.Int32Ty, CR6);
+ Value *CR6Param = Builder.getInt32(CR6);
llvm::Function *F = CGF.CGM.getIntrinsic(ID);
Result = Builder.CreateCall3(F, CR6Param, FirstVecArg, SecondVecArg, "");
return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType());
@@ -2257,8 +2278,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// If we have 0 && RHS, see if we can elide RHS, if so, just return 0.
// If we have 1 && X, just emit X without inserting the control flow.
- if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) {
- if (Cond == 1) { // If we have 1 && X, just emit X.
+ bool LHSCondVal;
+ if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) {
+ if (LHSCondVal) { // If we have 1 && X, just emit X.
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
// ZExt result to int or bool.
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext");
@@ -2280,9 +2302,8 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// Any edges into the ContBlock are now from an (indeterminate number of)
// edges from this first condition. All of these values will be false. Start
// setting up the PHI node in the Cont Block for this.
- llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext),
+ llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2,
"", ContBlock);
- PN->reserveOperandSpace(2); // Normal case, two inputs.
for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock);
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
@@ -2297,6 +2318,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
// Emit an unconditional branch from this block to ContBlock. Insert an entry
// into the phi node for the edge with the value of RHSCond.
+ if (CGF.getDebugInfo())
+ // There is no need to emit line number for unconditional branch.
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
CGF.EmitBlock(ContBlock);
PN->addIncoming(RHSCond, RHSBlock);
@@ -2309,8 +2333,9 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
// If we have 1 || RHS, see if we can elide RHS, if so, just return 1.
// If we have 0 || X, just emit X without inserting the control flow.
- if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) {
- if (Cond == -1) { // If we have 0 || X, just emit X.
+ bool LHSCondVal;
+ if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) {
+ if (!LHSCondVal) { // If we have 0 || X, just emit X.
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
// ZExt result to int or bool.
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext");
@@ -2332,9 +2357,8 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
// Any edges into the ContBlock are now from an (indeterminate number of)
// edges from this first condition. All of these values will be true. Start
// setting up the PHI node in the Cont Block for this.
- llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext),
+ llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2,
"", ContBlock);
- PN->reserveOperandSpace(2); // Normal case, two inputs.
for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock);
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
@@ -2375,12 +2399,10 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
/// flow into selects in some cases.
static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
CodeGenFunction &CGF) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
- return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr(), CGF);
+ E = E->IgnoreParens();
- // TODO: Allow anything we can constant fold to an integer or fp constant.
- if (isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) ||
- isa<FloatingLiteral>(E))
+ // Anything that is an integer or floating point constant is fine.
+ if (E->isConstantInitializer(CGF.getContext(), false))
return true;
// Non-volatile automatic variables too, to get "cond ? X : Y" where
@@ -2409,9 +2431,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// If the condition constant folds and can be elided, try to avoid emitting
// the condition and the dead arm.
- if (int Cond = CGF.ConstantFoldsToSimpleInteger(condExpr)){
+ bool CondExprBool;
+ if (CGF.ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) {
Expr *live = lhsExpr, *dead = rhsExpr;
- if (Cond == -1) std::swap(live, dead);
+ if (!CondExprBool) std::swap(live, dead);
// If the dead side doesn't have labels we need, and if the Live side isn't
// the gnu missing ?: extension (which we could handle, but don't bother
@@ -2436,7 +2459,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
std::vector<llvm::Constant*> Zvals;
for (unsigned i = 0; i < numElem; ++i)
- Zvals.push_back(llvm::ConstantInt::get(elemType,0));
+ Zvals.push_back(llvm::ConstantInt::get(elemType, 0));
llvm::Value *zeroVec = llvm::ConstantVector::get(Zvals);
llvm::Value *TestMSB = Builder.CreateICmpSLT(CondV, zeroVec);
@@ -2507,8 +2530,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
return LHS;
// Create a PHI node for the real part.
- llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond");
- PN->reserveOperandSpace(2);
+ llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), 2, "cond");
PN->addIncoming(LHS, LHSBlock);
PN->addIncoming(RHS, RHSBlock);
return PN;
@@ -2544,8 +2566,13 @@ Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
assert(E && !hasAggregateLLVMType(E->getType()) &&
"Invalid scalar expression to emit");
- return ScalarExprEmitter(*this, IgnoreResultAssign)
+ if (isa<CXXDefaultArgExpr>(E))
+ disableDebugInfo();
+ Value *V = ScalarExprEmitter(*this, IgnoreResultAssign)
.Visit(const_cast<Expr*>(E));
+ if (isa<CXXDefaultArgExpr>(E))
+ enableDebugInfo();
+ return V;
}
/// EmitScalarConversion - Emit a conversion from the specified type to the
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 5d3490769991..5b0d41e776f2 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -119,28 +119,26 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
/// CodeGenFunction.
void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
- FunctionArgList Args;
+ FunctionArgList args;
// Check if we should generate debug info for this method.
- if (CGM.getDebugInfo() && !OMD->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getDebugInfo();
+ if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>())
+ DebugInfo = CGM.getModuleDebugInfo();
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(OMD);
CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
- Args.push_back(std::make_pair(OMD->getSelfDecl(),
- OMD->getSelfDecl()->getType()));
- Args.push_back(std::make_pair(OMD->getCmdDecl(),
- OMD->getCmdDecl()->getType()));
+ args.push_back(OMD->getSelfDecl());
+ args.push_back(OMD->getCmdDecl());
for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
E = OMD->param_end(); PI != E; ++PI)
- Args.push_back(std::make_pair(*PI, (*PI)->getType()));
+ args.push_back(*PI);
CurGD = OMD;
- StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocStart());
+ StartFunction(OMD, OMD->getResultType(), Fn, FI, args, OMD->getLocStart());
}
void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
@@ -155,27 +153,24 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
CallArgList Args;
RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue,
Types.ConvertType(getContext().VoidPtrTy)));
- Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ Args.add(RV, getContext().VoidPtrTy);
RV = RValue::get(Builder.CreateBitCast(LV.getAddress(),
Types.ConvertType(getContext().VoidPtrTy)));
- Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ Args.add(RV, getContext().VoidPtrTy);
// sizeof (Type of Ivar)
CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
llvm::Value *SizeVal =
llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
Size.getQuantity());
- Args.push_back(std::make_pair(RValue::get(SizeVal),
- getContext().LongTy));
+ Args.add(RValue::get(SizeVal), getContext().LongTy);
llvm::Value *isAtomic =
llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
IsAtomic ? 1 : 0);
- Args.push_back(std::make_pair(RValue::get(isAtomic),
- getContext().BoolTy));
+ Args.add(RValue::get(isAtomic), getContext().BoolTy);
llvm::Value *hasStrong =
llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
IsStrong ? 1 : 0);
- Args.push_back(std::make_pair(RValue::get(hasStrong),
- getContext().BoolTy));
+ Args.add(RValue::get(hasStrong), getContext().BoolTy);
EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
FunctionType::ExtInfo()),
GetCopyStructFn, ReturnValueSlot(), Args);
@@ -236,10 +231,10 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
llvm::Value *True =
llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(SelfAsId), IdTy));
- Args.push_back(std::make_pair(RValue::get(CmdVal), Cmd->getType()));
- Args.push_back(std::make_pair(RValue::get(Offset), getContext().LongTy));
- Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy));
+ Args.add(RValue::get(SelfAsId), IdTy);
+ Args.add(RValue::get(CmdVal), Cmd->getType());
+ Args.add(RValue::get(Offset), getContext().getPointerDiffType());
+ Args.add(RValue::get(True), getContext().BoolTy);
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args,
@@ -263,6 +258,22 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
CGM.getObjCRuntime().GetGetStructFunction()) {
GenerateObjCGetterBody(Ivar, true, false);
}
+ else if (IsAtomic &&
+ (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
+ Triple.getArch() == llvm::Triple::x86 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(4)) &&
+ CGM.getObjCRuntime().GetGetStructFunction()) {
+ GenerateObjCGetterBody(Ivar, true, false);
+ }
+ else if (IsAtomic &&
+ (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
+ Triple.getArch() == llvm::Triple::x86_64 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(8)) &&
+ CGM.getObjCRuntime().GetGetStructFunction()) {
+ GenerateObjCGetterBody(Ivar, true, false);
+ }
else if (IVART->isAnyComplexType()) {
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
Ivar, 0);
@@ -272,18 +283,36 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
}
else if (hasAggregateLLVMType(IVART)) {
bool IsStrong = false;
- if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(IVART)))
+ if ((IsStrong = IvarTypeWithAggrGCObjects(IVART))
&& CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect
&& CGM.getObjCRuntime().GetGetStructFunction()) {
GenerateObjCGetterBody(Ivar, IsAtomic, IsStrong);
}
else {
- if (PID->getGetterCXXConstructor()) {
+ const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl();
+
+ if (PID->getGetterCXXConstructor() &&
+ classDecl && !classDecl->hasTrivialConstructor()) {
ReturnStmt *Stmt =
new (getContext()) ReturnStmt(SourceLocation(),
PID->getGetterCXXConstructor(),
0);
EmitReturnStmt(*Stmt);
+ } else if (IsAtomic &&
+ !IVART->isAnyComplexType() &&
+ Triple.getArch() == llvm::Triple::x86 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(4)) &&
+ CGM.getObjCRuntime().GetGetStructFunction()) {
+ GenerateObjCGetterBody(Ivar, true, false);
+ }
+ else if (IsAtomic &&
+ !IVART->isAnyComplexType() &&
+ Triple.getArch() == llvm::Triple::x86_64 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(8)) &&
+ CGM.getObjCRuntime().GetGetStructFunction()) {
+ GenerateObjCGetterBody(Ivar, true, false);
}
else {
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
@@ -295,11 +324,17 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
else {
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
Ivar, 0);
- CodeGenTypes &Types = CGM.getTypes();
- RValue RV = EmitLoadOfLValue(LV, IVART);
- RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
+ if (PD->getType()->isReferenceType()) {
+ RValue RV = RValue::get(LV.getAddress());
+ EmitReturnOfRValue(RV, PD->getType());
+ }
+ else {
+ CodeGenTypes &Types = CGM.getTypes();
+ RValue RV = EmitLoadOfLValue(LV, IVART);
+ RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
Types.ConvertType(PD->getType())));
- EmitReturnOfRValue(RV, PD->getType());
+ EmitReturnOfRValue(RV, PD->getType());
+ }
}
}
@@ -318,31 +353,42 @@ void CodeGenFunction::GenerateObjCAtomicSetterBody(ObjCMethodDecl *OMD,
RValue RV =
RValue::get(Builder.CreateBitCast(LV.getAddress(),
Types.ConvertType(getContext().VoidPtrTy)));
- Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ Args.add(RV, getContext().VoidPtrTy);
llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()];
llvm::Value *ArgAsPtrTy =
Builder.CreateBitCast(Arg,
Types.ConvertType(getContext().VoidPtrTy));
RV = RValue::get(ArgAsPtrTy);
- Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ Args.add(RV, getContext().VoidPtrTy);
// sizeof (Type of Ivar)
CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
llvm::Value *SizeVal =
llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
Size.getQuantity());
- Args.push_back(std::make_pair(RValue::get(SizeVal),
- getContext().LongTy));
+ Args.add(RValue::get(SizeVal), getContext().LongTy);
llvm::Value *True =
llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
- Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy));
+ Args.add(RValue::get(True), getContext().BoolTy);
llvm::Value *False =
llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
- Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy));
+ Args.add(RValue::get(False), getContext().BoolTy);
EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
FunctionType::ExtInfo()),
GetCopyStructFn, ReturnValueSlot(), Args);
}
+static bool
+IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID,
+ QualType IvarT) {
+ bool HasTrvialAssignment = true;
+ if (PID->getSetterCXXAssignment()) {
+ const CXXRecordDecl *classDecl = IvarT->getAsCXXRecordDecl();
+ HasTrvialAssignment =
+ (!classDecl || classDecl->hasTrivialCopyAssignment());
+ }
+ return HasTrvialAssignment;
+}
+
/// GenerateObjCSetter - Generate an Objective-C property setter
/// function. The given Decl must be an ObjCImplementationDecl. @synthesize
/// is illegal within a category.
@@ -353,7 +399,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface());
-
+ const llvm::Triple &Triple = getContext().Target.getTriple();
+ QualType IVART = Ivar->getType();
bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy;
bool IsAtomic =
!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
@@ -394,32 +441,34 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
llvm::Value *False =
llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(SelfAsId), IdTy));
- Args.push_back(std::make_pair(RValue::get(CmdVal), Cmd->getType()));
- Args.push_back(std::make_pair(RValue::get(Offset), getContext().LongTy));
- Args.push_back(std::make_pair(RValue::get(ArgAsId), IdTy));
- Args.push_back(std::make_pair(RValue::get(IsAtomic ? True : False),
- getContext().BoolTy));
- Args.push_back(std::make_pair(RValue::get(IsCopy ? True : False),
- getContext().BoolTy));
+ Args.add(RValue::get(SelfAsId), IdTy);
+ Args.add(RValue::get(CmdVal), Cmd->getType());
+ Args.add(RValue::get(Offset), getContext().getPointerDiffType());
+ Args.add(RValue::get(ArgAsId), IdTy);
+ Args.add(RValue::get(IsAtomic ? True : False), getContext().BoolTy);
+ Args.add(RValue::get(IsCopy ? True : False), getContext().BoolTy);
// FIXME: We shouldn't need to get the function info here, the runtime
// already should have computed it to build the function.
EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
FunctionType::ExtInfo()),
SetPropertyFn,
ReturnValueSlot(), Args);
- } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) &&
- !Ivar->getType()->isAnyComplexType() &&
- IndirectObjCSetterArg(*CurFnInfo)
+ } else if (IsAtomic && hasAggregateLLVMType(IVART) &&
+ !IVART->isAnyComplexType() &&
+ IvarAssignHasTrvialAssignment(PID, IVART) &&
+ ((Triple.getArch() == llvm::Triple::x86 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(4))) ||
+ (Triple.getArch() == llvm::Triple::x86_64 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(8))))
&& CGM.getObjCRuntime().GetSetStructFunction()) {
- // objc_copyStruct (&structIvar, &Arg,
- // sizeof (struct something), true, false);
+ // objc_copyStruct (&structIvar, &Arg,
+ // sizeof (struct something), true, false);
GenerateObjCAtomicSetterBody(OMD, Ivar);
} else if (PID->getSetterCXXAssignment()) {
EmitIgnoredExpr(PID->getSetterCXXAssignment());
} else {
- const llvm::Triple &Triple = getContext().Target.getTriple();
- QualType IVART = Ivar->getType();
if (IsAtomic &&
IVART->isScalarType() &&
(Triple.getArch() == llvm::Triple::arm ||
@@ -429,6 +478,22 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
CGM.getObjCRuntime().GetGetStructFunction()) {
GenerateObjCAtomicSetterBody(OMD, Ivar);
}
+ else if (IsAtomic &&
+ (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
+ Triple.getArch() == llvm::Triple::x86 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(4)) &&
+ CGM.getObjCRuntime().GetGetStructFunction()) {
+ GenerateObjCAtomicSetterBody(OMD, Ivar);
+ }
+ else if (IsAtomic &&
+ (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
+ Triple.getArch() == llvm::Triple::x86_64 &&
+ (getContext().getTypeSizeInChars(IVART)
+ > CharUnits::fromQuantity(8)) &&
+ CGM.getObjCRuntime().GetGetStructFunction()) {
+ GenerateObjCAtomicSetterBody(OMD, Ivar);
+ }
else {
// FIXME: Find a clean way to avoid AST node creation.
SourceLocation Loc = PD->getLocation();
@@ -436,7 +501,10 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc);
ParmVarDecl *ArgDecl = *OMD->param_begin();
- DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), VK_LValue, Loc);
+ QualType T = ArgDecl->getType();
+ if (T->isReferenceType())
+ T = cast<ReferenceType>(T)->getPointeeType();
+ DeclRefExpr Arg(ArgDecl, T, VK_LValue, Loc);
ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true);
// The property type can differ from the ivar type in some situations with
@@ -460,20 +528,104 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FinishFunction();
}
+// FIXME: these are stolen from CGClass.cpp, which is lame.
+namespace {
+ struct CallArrayIvarDtor : EHScopeStack::Cleanup {
+ const ObjCIvarDecl *ivar;
+ llvm::Value *self;
+ CallArrayIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
+ : ivar(ivar), self(self) {}
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ LValue lvalue =
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
+
+ QualType type = ivar->getType();
+ const ConstantArrayType *arrayType
+ = CGF.getContext().getAsConstantArrayType(type);
+ QualType baseType = CGF.getContext().getBaseElementType(arrayType);
+ const CXXRecordDecl *classDecl = baseType->getAsCXXRecordDecl();
+
+ llvm::Value *base
+ = CGF.Builder.CreateBitCast(lvalue.getAddress(),
+ CGF.ConvertType(baseType)->getPointerTo());
+ CGF.EmitCXXAggrDestructorCall(classDecl->getDestructor(),
+ arrayType, base);
+ }
+ };
+
+ struct CallIvarDtor : EHScopeStack::Cleanup {
+ const ObjCIvarDecl *ivar;
+ llvm::Value *self;
+ CallIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
+ : ivar(ivar), self(self) {}
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ LValue lvalue =
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
+
+ QualType type = ivar->getType();
+ const CXXRecordDecl *classDecl = type->getAsCXXRecordDecl();
+
+ CGF.EmitCXXDestructorCall(classDecl->getDestructor(),
+ Dtor_Complete, /*ForVirtualBase=*/false,
+ lvalue.getAddress());
+ }
+ };
+}
+
+static void emitCXXDestructMethod(CodeGenFunction &CGF,
+ ObjCImplementationDecl *impl) {
+ CodeGenFunction::RunCleanupsScope scope(CGF);
+
+ llvm::Value *self = CGF.LoadObjCSelf();
+
+ ObjCInterfaceDecl *iface
+ = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface());
+ for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
+ ivar; ivar = ivar->getNextIvar()) {
+ QualType type = ivar->getType();
+
+ // Drill down to the base element type.
+ QualType baseType = type;
+ const ConstantArrayType *arrayType =
+ CGF.getContext().getAsConstantArrayType(baseType);
+ if (arrayType) baseType = CGF.getContext().getBaseElementType(arrayType);
+
+ // Check whether the ivar is a destructible type.
+ QualType::DestructionKind destructKind = baseType.isDestructedType();
+ assert(destructKind == type.isDestructedType());
+
+ switch (destructKind) {
+ case QualType::DK_none:
+ continue;
+
+ case QualType::DK_cxx_destructor:
+ if (arrayType)
+ CGF.EHStack.pushCleanup<CallArrayIvarDtor>(NormalAndEHCleanup,
+ ivar, self);
+ else
+ CGF.EHStack.pushCleanup<CallIvarDtor>(NormalAndEHCleanup,
+ ivar, self);
+ break;
+ }
+ }
+
+ assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?");
+}
+
void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD,
bool ctor) {
- llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
StartObjCMethod(MD, IMP->getClassInterface());
- for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
- E = IMP->init_end(); B != E; ++B) {
- CXXCtorInitializer *Member = (*B);
- IvarInitializers.push_back(Member);
- }
+
+ // Emit .cxx_construct.
if (ctor) {
- for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) {
- CXXCtorInitializer *IvarInit = IvarInitializers[I];
+ llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
+ for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
+ E = IMP->init_end(); B != E; ++B) {
+ CXXCtorInitializer *IvarInit = (*B);
FieldDecl *Field = IvarInit->getAnyMember();
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
@@ -486,37 +638,10 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
llvm::Value *SelfAsId =
Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
EmitReturnOfRValue(RValue::get(SelfAsId), IdTy);
+
+ // Emit .cxx_destruct.
} else {
- // dtor
- for (size_t i = IvarInitializers.size(); i > 0; --i) {
- FieldDecl *Field = IvarInitializers[i - 1]->getAnyMember();
- QualType FieldType = Field->getType();
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
-
- ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
- LoadObjCSelf(), Ivar, 0);
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor();
- if (!Dtor->isTrivial()) {
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LV.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(Dtor,
- Array, BaseAddrPtr);
- } else {
- EmitCXXDestructorCall(Dtor,
- Dtor_Complete, /*ForVirtualBase=*/false,
- LV.getAddress());
- }
- }
- }
+ emitCXXDestructMethod(*this, IMP);
}
FinishFunction();
}
@@ -585,16 +710,14 @@ static RValue GenerateMessageSendSuper(CodeGenFunction &CGF,
RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
ReturnValueSlot Return) {
const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr();
- QualType ResultType;
+ QualType ResultType = E->getGetterResultType();
Selector S;
if (E->isExplicitProperty()) {
const ObjCPropertyDecl *Property = E->getExplicitProperty();
S = Property->getGetterName();
- ResultType = E->getType();
} else {
const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter();
S = Getter->getSelector();
- ResultType = Getter->getResultType(); // with reference!
}
llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
@@ -615,14 +738,8 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
LValue Dst) {
const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr();
Selector S = E->getSetterSelector();
- QualType ArgType;
- if (E->isImplicitProperty()) {
- const ObjCMethodDecl *Setter = E->getImplicitPropertySetter();
- ObjCMethodDecl::param_iterator P = Setter->param_begin();
- ArgType = (*P)->getType();
- } else {
- ArgType = E->getType();
- }
+ QualType ArgType = E->getSetterArgType();
+
// FIXME. Other than scalars, AST is not adequate for setter and
// getter type mismatches which require conversion.
if (Src.isScalar()) {
@@ -635,7 +752,7 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
}
CallArgList Args;
- Args.push_back(std::make_pair(Src, ArgType));
+ Args.add(Src, ArgType);
llvm::Value *Receiver = Dst.getPropertyRefBaseAddr();
QualType ResultType = getContext().VoidTy;
@@ -707,22 +824,19 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
CallArgList Args;
// The first argument is a temporary of the enumeration-state type.
- Args.push_back(std::make_pair(RValue::get(StatePtr),
- getContext().getPointerType(StateTy)));
+ Args.add(RValue::get(StatePtr), getContext().getPointerType(StateTy));
// The second argument is a temporary array with space for NumItems
// pointers. We'll actually be loading elements from the array
// pointer written into the control state; this buffer is so that
// collections that *aren't* backed by arrays can still queue up
// batches of elements.
- Args.push_back(std::make_pair(RValue::get(ItemsPtr),
- getContext().getPointerType(ItemsTy)));
+ Args.add(RValue::get(ItemsPtr), getContext().getPointerType(ItemsTy));
// The third argument is the capacity of that temporary array.
const llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy);
llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems);
- Args.push_back(std::make_pair(RValue::get(Count),
- getContext().UnsignedLongTy));
+ Args.add(RValue::get(Count), getContext().UnsignedLongTy);
// Start the enumeration.
RValue CountRV =
@@ -764,11 +878,11 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(LoopBodyBB);
// The current index into the buffer.
- llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, "forcoll.index");
+ llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.index");
index->addIncoming(zero, LoopInitBB);
// The current buffer size.
- llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, "forcoll.count");
+ llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.count");
count->addIncoming(initialBufferLimit, LoopInitBB);
// Check whether the mutations value has changed from where it was
@@ -779,7 +893,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
= Builder.CreateLoad(StateMutationsPtr, "statemutations");
llvm::BasicBlock *WasMutatedBB = createBasicBlock("forcoll.mutated");
- llvm::BasicBlock *WasNotMutatedBB = createBasicBlock("forcool.notmutated");
+ llvm::BasicBlock *WasNotMutatedBB = createBasicBlock("forcoll.notmutated");
Builder.CreateCondBr(Builder.CreateICmpEQ(currentMutations, initialMutations),
WasNotMutatedBB, WasMutatedBB);
@@ -791,8 +905,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
ConvertType(getContext().getObjCIdType()),
"tmp");
CallArgList Args2;
- Args2.push_back(std::make_pair(RValue::get(V),
- getContext().getObjCIdType()));
+ Args2.add(RValue::get(V), getContext().getObjCIdType());
// FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function.
EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2,
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 5f19dc6e5647..c4dc4c41da6d 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides Objective-C code generation targetting the GNU runtime. The
+// This provides Objective-C code generation targeting the GNU runtime. The
// class in this file generates structures used by the GNU Objective-C runtime
// library. These structures are defined in objc/objc.h and objc/objc-api.h in
// the GNU runtime distribution.
@@ -24,90 +24,342 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/LLVMContext.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetData.h"
-#include <map>
+#include <stdarg.h>
using namespace clang;
using namespace CodeGen;
using llvm::dyn_cast;
-// The version of the runtime that this class targets. Must match the version
-// in the runtime.
-static const int RuntimeVersion = 8;
-static const int NonFragileRuntimeVersion = 9;
-static const int ProtocolVersion = 2;
-static const int NonFragileProtocolVersion = 3;
namespace {
-class CGObjCGNU : public CodeGen::CGObjCRuntime {
-private:
- CodeGen::CodeGenModule &CGM;
+/// Class that lazily initialises the runtime function. Avoids inserting the
+/// types and the function declaration into a module if they're not used, and
+/// avoids constructing the type more than once if it's used more than once.
+class LazyRuntimeFunction {
+ CodeGenModule *CGM;
+ std::vector<const llvm::Type*> ArgTys;
+ const char *FunctionName;
+ llvm::Function *Function;
+ public:
+ /// Constructor leaves this class uninitialized, because it is intended to
+ /// be used as a field in another class and not all of the types that are
+ /// used as arguments will necessarily be available at construction time.
+ LazyRuntimeFunction() : CGM(0), FunctionName(0), Function(0) {}
+
+ /// Initialises the lazy function with the name, return type, and the types
+ /// of the arguments.
+ END_WITH_NULL
+ void init(CodeGenModule *Mod, const char *name,
+ const llvm::Type *RetTy, ...) {
+ CGM =Mod;
+ FunctionName = name;
+ Function = 0;
+ ArgTys.clear();
+ va_list Args;
+ va_start(Args, RetTy);
+ while (const llvm::Type *ArgTy = va_arg(Args, const llvm::Type*))
+ ArgTys.push_back(ArgTy);
+ va_end(Args);
+ // Push the return type on at the end so we can pop it off easily
+ ArgTys.push_back(RetTy);
+ }
+ /// Overloaded cast operator, allows the class to be implicitly cast to an
+ /// LLVM constant.
+ operator llvm::Function*() {
+ if (!Function) {
+ if (0 == FunctionName) return 0;
+ // We put the return type on the end of the vector, so pop it back off
+ const llvm::Type *RetTy = ArgTys.back();
+ ArgTys.pop_back();
+ llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
+ Function =
+ cast<llvm::Function>(CGM->CreateRuntimeFunction(FTy, FunctionName));
+ // We won't need to use the types again, so we may as well clean up the
+ // vector now
+ ArgTys.resize(0);
+ }
+ return Function;
+ }
+};
+
+
+/// GNU Objective-C runtime code generation. This class implements the parts of
+/// Objective-C support that are specific to the GNU family of runtimes (GCC and
+/// GNUstep).
+class CGObjCGNU : public CGObjCRuntime {
+protected:
+ /// The module that is using this class
+ CodeGenModule &CGM;
+ /// The LLVM module into which output is inserted
llvm::Module &TheModule;
+ /// strut objc_super. Used for sending messages to super. This structure
+ /// contains the receiver (object) and the expected class.
+ const llvm::StructType *ObjCSuperTy;
+ /// struct objc_super*. The type of the argument to the superclass message
+ /// lookup functions.
+ const llvm::PointerType *PtrToObjCSuperTy;
+ /// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring
+ /// SEL is included in a header somewhere, in which case it will be whatever
+ /// type is declared in that header, most likely {i8*, i8*}.
const llvm::PointerType *SelectorTy;
+ /// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the
+ /// places where it's used
const llvm::IntegerType *Int8Ty;
+ /// Pointer to i8 - LLVM type of char*, for all of the places where the
+ /// runtime needs to deal with C strings.
const llvm::PointerType *PtrToInt8Ty;
- const llvm::FunctionType *IMPTy;
+ /// Instance Method Pointer type. This is a pointer to a function that takes,
+ /// at a minimum, an object and a selector, and is the generic type for
+ /// Objective-C methods. Due to differences between variadic / non-variadic
+ /// calling conventions, it must always be cast to the correct type before
+ /// actually being used.
+ const llvm::PointerType *IMPTy;
+ /// Type of an untyped Objective-C object. Clang treats id as a built-in type
+ /// when compiling Objective-C code, so this may be an opaque pointer (i8*),
+ /// but if the runtime header declaring it is included then it may be a
+ /// pointer to a structure.
const llvm::PointerType *IdTy;
+ /// Pointer to a pointer to an Objective-C object. Used in the new ABI
+ /// message lookup function and some GC-related functions.
const llvm::PointerType *PtrToIdTy;
+ /// The clang type of id. Used when using the clang CGCall infrastructure to
+ /// call Objective-C methods.
CanQualType ASTIdTy;
+ /// LLVM type for C int type.
const llvm::IntegerType *IntTy;
+ /// LLVM type for an opaque pointer. This is identical to PtrToInt8Ty, but is
+ /// used in the code to document the difference between i8* meaning a pointer
+ /// to a C string and i8* meaning a pointer to some opaque type.
const llvm::PointerType *PtrTy;
+ /// LLVM type for C long type. The runtime uses this in a lot of places where
+ /// it should be using intptr_t, but we can't fix this without breaking
+ /// compatibility with GCC...
const llvm::IntegerType *LongTy;
+ /// LLVM type for C size_t. Used in various runtime data structures.
const llvm::IntegerType *SizeTy;
+ /// LLVM type for C ptrdiff_t. Mainly used in property accessor functions.
const llvm::IntegerType *PtrDiffTy;
+ /// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance
+ /// variables.
const llvm::PointerType *PtrToIntTy;
+ /// LLVM type for Objective-C BOOL type.
const llvm::Type *BoolTy;
+ /// Metadata kind used to tie method lookups to message sends. The GNUstep
+ /// runtime provides some LLVM passes that can use this to do things like
+ /// automatic IMP caching and speculative inlining.
+ unsigned msgSendMDKind;
+ /// Helper function that generates a constant string and returns a pointer to
+ /// the start of the string. The result of this function can be used anywhere
+ /// where the C code specifies const char*.
+ llvm::Constant *MakeConstantString(const std::string &Str,
+ const std::string &Name="") {
+ llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
+ }
+ /// Emits a linkonce_odr string, whose name is the prefix followed by the
+ /// string value. This allows the linker to combine the strings between
+ /// different modules. Used for EH typeinfo names, selector strings, and a
+ /// few other things.
+ llvm::Constant *ExportUniqueString(const std::string &Str,
+ const std::string prefix) {
+ std::string name = prefix + Str;
+ llvm::Constant *ConstStr = TheModule.getGlobalVariable(name);
+ if (!ConstStr) {
+ llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true);
+ ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
+ llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str);
+ }
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
+ }
+ /// Generates a global structure, initialized by the elements in the vector.
+ /// The element types must match the types of the structure elements in the
+ /// first argument.
+ llvm::GlobalVariable *MakeGlobal(const llvm::StructType *Ty,
+ std::vector<llvm::Constant*> &V,
+ llvm::StringRef Name="",
+ llvm::GlobalValue::LinkageTypes linkage
+ =llvm::GlobalValue::InternalLinkage) {
+ llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
+ return new llvm::GlobalVariable(TheModule, Ty, false,
+ linkage, C, Name);
+ }
+ /// Generates a global array. The vector must contain the same number of
+ /// elements that the array type declares, of the type specified as the array
+ /// element type.
+ llvm::GlobalVariable *MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> &V,
+ llvm::StringRef Name="",
+ llvm::GlobalValue::LinkageTypes linkage
+ =llvm::GlobalValue::InternalLinkage) {
+ llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
+ return new llvm::GlobalVariable(TheModule, Ty, false,
+ linkage, C, Name);
+ }
+ /// Generates a global array, inferring the array type from the specified
+ /// element type and the size of the initialiser.
+ llvm::GlobalVariable *MakeGlobalArray(const llvm::Type *Ty,
+ std::vector<llvm::Constant*> &V,
+ llvm::StringRef Name="",
+ llvm::GlobalValue::LinkageTypes linkage
+ =llvm::GlobalValue::InternalLinkage) {
+ llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size());
+ return MakeGlobal(ArrayTy, V, Name, linkage);
+ }
+ /// Ensures that the value has the required type, by inserting a bitcast if
+ /// required. This function lets us avoid inserting bitcasts that are
+ /// redundant.
+ llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){
+ if (V->getType() == Ty) return V;
+ return B.CreateBitCast(V, Ty);
+ }
+ // Some zeros used for GEPs in lots of places.
+ llvm::Constant *Zeros[2];
+ /// Null pointer value. Mainly used as a terminator in various arrays.
+ llvm::Constant *NULLPtr;
+ /// LLVM context.
+ llvm::LLVMContext &VMContext;
+private:
+ /// Placeholder for the class. Lots of things refer to the class before we've
+ /// actually emitted it. We use this alias as a placeholder, and then replace
+ /// it with a pointer to the class structure before finally emitting the
+ /// module.
llvm::GlobalAlias *ClassPtrAlias;
+ /// Placeholder for the metaclass. Lots of things refer to the class before
+ /// we've / actually emitted it. We use this alias as a placeholder, and then
+ /// replace / it with a pointer to the metaclass structure before finally
+ /// emitting the / module.
llvm::GlobalAlias *MetaClassPtrAlias;
+ /// All of the classes that have been generated for this compilation units.
std::vector<llvm::Constant*> Classes;
+ /// All of the categories that have been generated for this compilation units.
std::vector<llvm::Constant*> Categories;
+ /// All of the Objective-C constant strings that have been generated for this
+ /// compilation units.
std::vector<llvm::Constant*> ConstantStrings;
+ /// Map from string values to Objective-C constant strings in the output.
+ /// Used to prevent emitting Objective-C strings more than once. This should
+ /// not be required at all - CodeGenModule should manage this list.
llvm::StringMap<llvm::Constant*> ObjCStrings;
- llvm::Function *LoadFunction;
+ /// All of the protocols that have been declared.
llvm::StringMap<llvm::Constant*> ExistingProtocols;
- typedef std::pair<std::string, std::string> TypedSelector;
- std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
- llvm::StringMap<llvm::GlobalAlias*> UntypedSelectors;
- // Selectors that we don't emit in GC mode
+ /// For each variant of a selector, we store the type encoding and a
+ /// placeholder value. For an untyped selector, the type will be the empty
+ /// string. Selector references are all done via the module's selector table,
+ /// so we create an alias as a placeholder and then replace it with the real
+ /// value later.
+ typedef std::pair<std::string, llvm::GlobalAlias*> TypedSelector;
+ /// Type of the selector map. This is roughly equivalent to the structure
+ /// used in the GNUstep runtime, which maintains a list of all of the valid
+ /// types for a selector in a table.
+ typedef llvm::DenseMap<Selector, llvm::SmallVector<TypedSelector, 2> >
+ SelectorMap;
+ /// A map from selectors to selector types. This allows us to emit all
+ /// selectors of the same name and type together.
+ SelectorMap SelectorTable;
+
+ /// Selectors related to memory management. When compiling in GC mode, we
+ /// omit these.
Selector RetainSel, ReleaseSel, AutoreleaseSel;
- // Functions used for GC.
- llvm::Constant *IvarAssignFn, *StrongCastAssignFn, *MemMoveFn, *WeakReadFn,
- *WeakAssignFn, *GlobalAssignFn;
- // Some zeros used for GEPs in lots of places.
- llvm::Constant *Zeros[2];
- llvm::Constant *NULLPtr;
- llvm::LLVMContext &VMContext;
- /// Metadata kind used to tie method lookups to message sends.
- unsigned msgSendMDKind;
+ /// Runtime functions used for memory management in GC mode. Note that clang
+ /// supports code generation for calling these functions, but neither GNU
+ /// runtime actually supports this API properly yet.
+ LazyRuntimeFunction IvarAssignFn, StrongCastAssignFn, MemMoveFn, WeakReadFn,
+ WeakAssignFn, GlobalAssignFn;
+
+protected:
+ /// Function used for throwing Objective-C exceptions.
+ LazyRuntimeFunction ExceptionThrowFn;
+ /// Function used for rethrowing exceptions, used at the end of @finally or
+ /// @synchronize blocks.
+ LazyRuntimeFunction ExceptionReThrowFn;
+ /// Function called when entering a catch function. This is required for
+ /// differentiating Objective-C exceptions and foreign exceptions.
+ LazyRuntimeFunction EnterCatchFn;
+ /// Function called when exiting from a catch block. Used to do exception
+ /// cleanup.
+ LazyRuntimeFunction ExitCatchFn;
+ /// Function called when entering an @synchronize block. Acquires the lock.
+ LazyRuntimeFunction SyncEnterFn;
+ /// Function called when exiting an @synchronize block. Releases the lock.
+ LazyRuntimeFunction SyncExitFn;
+
+private:
+
+ /// Function called if fast enumeration detects that the collection is
+ /// modified during the update.
+ LazyRuntimeFunction EnumerationMutationFn;
+ /// Function for implementing synthesized property getters that return an
+ /// object.
+ LazyRuntimeFunction GetPropertyFn;
+ /// Function for implementing synthesized property setters that return an
+ /// object.
+ LazyRuntimeFunction SetPropertyFn;
+ /// Function used for non-object declared property getters.
+ LazyRuntimeFunction GetStructPropertyFn;
+ /// Function used for non-object declared property setters.
+ LazyRuntimeFunction SetStructPropertyFn;
+
+ /// The version of the runtime that this class targets. Must match the
+ /// version in the runtime.
+ const int RuntimeVersion;
+ /// The version of the protocol class. Used to differentiate between ObjC1
+ /// and ObjC2 protocols. Objective-C 1 protocols can not contain optional
+ /// components and can not contain declared properties. We always emit
+ /// Objective-C 2 property structures, but we have to pretend that they're
+ /// Objective-C 1 property structures when targeting the GCC runtime or it
+ /// will abort.
+ const int ProtocolVersion;
private:
+ /// Generates an instance variable list structure. This is a structure
+ /// containing a size and an array of structures containing instance variable
+ /// metadata. This is used purely for introspection in the fragile ABI. In
+ /// the non-fragile ABI, it's used for instance variable fixup.
llvm::Constant *GenerateIvarList(
const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets);
- llvm::Constant *GenerateMethodList(const std::string &ClassName,
- const std::string &CategoryName,
+ /// Generates a method list structure. This is a structure containing a size
+ /// and an array of structures containing method metadata.
+ ///
+ /// This structure is used by both classes and categories, and contains a next
+ /// pointer allowing them to be chained together in a linked list.
+ llvm::Constant *GenerateMethodList(const llvm::StringRef &ClassName,
+ const llvm::StringRef &CategoryName,
const llvm::SmallVectorImpl<Selector> &MethodSels,
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
bool isClassMethodList);
+ /// Emits an empty protocol. This is used for @protocol() where no protocol
+ /// is found. The runtime will (hopefully) fix up the pointer to refer to the
+ /// real protocol.
llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName);
+ /// Generates a list of property metadata structures. This follows the same
+ /// pattern as method and instance variable metadata lists.
llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID,
llvm::SmallVectorImpl<Selector> &InstanceMethodSels,
llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes);
+ /// Generates a list of referenced protocols. Classes, categories, and
+ /// protocols all use this structure.
llvm::Constant *GenerateProtocolList(
const llvm::SmallVectorImpl<std::string> &Protocols);
- // To ensure that all protocols are seen by the runtime, we add a category on
- // a class defined in the runtime, declaring no methods, but adopting the
- // protocols.
+ /// To ensure that all protocols are seen by the runtime, we add a category on
+ /// a class defined in the runtime, declaring no methods, but adopting the
+ /// protocols. This is a horribly ugly hack, but it allows us to collect all
+ /// of the protocols without changing the ABI.
void GenerateProtocolHolderCategory(void);
+ /// Generates a class structure.
llvm::Constant *GenerateClassStructure(
llvm::Constant *MetaClass,
llvm::Constant *SuperClass,
@@ -121,31 +373,43 @@ private:
llvm::Constant *IvarOffsets,
llvm::Constant *Properties,
bool isMeta=false);
+ /// Generates a method list. This is used by protocols to define the required
+ /// and optional methods.
llvm::Constant *GenerateProtocolMethodList(
const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes);
- llvm::Constant *MakeConstantString(const std::string &Str, const std::string
- &Name="");
- llvm::Constant *ExportUniqueString(const std::string &Str, const std::string
- prefix);
- llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, llvm::StringRef Name="",
- llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
- llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, llvm::StringRef Name="",
- llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
+ /// Returns a selector with the specified type encoding. An empty string is
+ /// used to return an untyped selector (with the types field set to NULL).
+ llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ const std::string &TypeEncoding, bool lval);
+ /// Returns the variable used to store the offset of an instance variable.
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
+ /// Emits a reference to a class. This allows the linker to object if there
+ /// is no class of the matching name.
void EmitClassRef(const std::string &className);
- llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){
- if (V->getType() == Ty) return V;
- return B.CreateBitCast(V, Ty);
- }
+protected:
+ /// Looks up the method for sending a message to the specified object. This
+ /// mechanism differs between the GCC and GNU runtimes, so this method must be
+ /// overridden in subclasses.
+ virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
+ llvm::Value *&Receiver,
+ llvm::Value *cmd,
+ llvm::MDNode *node) = 0;
+ /// Looks up the method for sending a message to a superclass. This mechanism
+ /// differs between the GCC and GNU runtimes, so this method must be
+ /// overridden in subclasses.
+ virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
+ llvm::Value *ObjCSuper,
+ llvm::Value *cmd) = 0;
public:
- CGObjCGNU(CodeGen::CodeGenModule &cgm);
+ CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
+ unsigned protocolClassVersion);
+
virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
- virtual CodeGen::RValue
- GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+
+ virtual RValue
+ GenerateMessageSend(CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
@@ -153,8 +417,8 @@ public:
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
- virtual CodeGen::RValue
- GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+ virtual RValue
+ GenerateMessageSendSuper(CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
@@ -186,41 +450,174 @@ public:
virtual llvm::Function *GetGetStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
- virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitTryStmt(CodeGenFunction &CGF,
const ObjCAtTryStmt &S);
- virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitSynchronizedStmt(CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S);
- virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitThrowStmt(CodeGenFunction &CGF,
const ObjCAtThrowStmt &S);
- virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ virtual llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
- virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitObjCWeakAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst);
- virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitObjCGlobalAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest,
bool threadlocal=false);
- virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitObjCIvarAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest,
llvm::Value *ivarOffset);
- virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitObjCStrongCastAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest);
- virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ virtual void EmitGCMemmoveCollectable(CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
llvm::Value *Size);
- virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+ virtual LValue EmitObjCValueForIvar(CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers);
- virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
- virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
+ virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
return NULLPtr;
}
};
+/// Class representing the legacy GCC Objective-C ABI. This is the default when
+/// -fobjc-nonfragile-abi is not specified.
+///
+/// The GCC ABI target actually generates code that is approximately compatible
+/// with the new GNUstep runtime ABI, but refrains from using any features that
+/// would not work with the GCC runtime. For example, clang always generates
+/// the extended form of the class structure, and the extra fields are simply
+/// ignored by GCC libobjc.
+class CGObjCGCC : public CGObjCGNU {
+ /// 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;
+protected:
+ virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
+ llvm::Value *&Receiver,
+ llvm::Value *cmd,
+ llvm::MDNode *node) {
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *imp = Builder.CreateCall2(MsgLookupFn,
+ EnforceType(Builder, Receiver, IdTy),
+ EnforceType(Builder, cmd, SelectorTy));
+ cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node);
+ return imp;
+ }
+ 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, lookupArgs+2);
+ }
+ public:
+ CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
+ // 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);
+ }
+};
+/// Class used when targeting the new GNUstep runtime ABI.
+class CGObjCGNUstep : public CGObjCGNU {
+ /// The slot lookup function. Returns a pointer to a cacheable structure
+ /// that contains (among other things) the IMP.
+ LazyRuntimeFunction SlotLookupFn;
+ /// The GNUstep ABI superclass message lookup function. Takes a pointer to
+ /// a structure describing the receiver and the class, and a selector as
+ /// arguments. Returns the slot for the corresponding method. Superclass
+ /// message lookup rarely changes, so this is a good caching opportunity.
+ LazyRuntimeFunction SlotLookupSuperFn;
+ /// Type of an slot structure pointer. This is returned by the various
+ /// lookup functions.
+ llvm::Type *SlotTy;
+ protected:
+ virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
+ llvm::Value *&Receiver,
+ llvm::Value *cmd,
+ llvm::MDNode *node) {
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Function *LookupFn = SlotLookupFn;
+
+ // Store the receiver on the stack so that we can reload it later
+ llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType());
+ Builder.CreateStore(Receiver, ReceiverPtr);
+
+ llvm::Value *self;
+
+ if (isa<ObjCMethodDecl>(CGF.CurCodeDecl)) {
+ self = CGF.LoadObjCSelf();
+ } else {
+ self = llvm::ConstantPointerNull::get(IdTy);
+ }
+
+ // The lookup function is guaranteed not to capture the receiver pointer.
+ LookupFn->setDoesNotCapture(1);
+
+ llvm::CallInst *slot =
+ Builder.CreateCall3(LookupFn,
+ EnforceType(Builder, ReceiverPtr, PtrToIdTy),
+ EnforceType(Builder, cmd, SelectorTy),
+ EnforceType(Builder, self, IdTy));
+ slot->setOnlyReadsMemory();
+ slot->setMetadata(msgSendMDKind, node);
+
+ // Load the imp from the slot
+ llvm::Value *imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+
+ // The lookup function may have changed the receiver, so make sure we use
+ // the new one.
+ Receiver = Builder.CreateLoad(ReceiverPtr, true);
+ return imp;
+ }
+ virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
+ llvm::Value *ObjCSuper,
+ llvm::Value *cmd) {
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
+
+ llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs,
+ lookupArgs+2);
+ slot->setOnlyReadsMemory();
+
+ return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+ }
+ public:
+ CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
+ llvm::StructType *SlotStructTy = llvm::StructType::get(VMContext, PtrTy,
+ PtrTy, PtrTy, IntTy, IMPTy, NULL);
+ SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
+ // Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
+ SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy,
+ SelectorTy, IdTy, NULL);
+ // Slot_t objc_msg_lookup_super(struct objc_super*, SEL);
+ SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
+ PtrToObjCSuperTy, SelectorTy, NULL);
+ // If we're in ObjC++ mode, then we want to make
+ if (CGM.getLangOptions().CPlusPlus) {
+ const llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+ // void *__cxa_begin_catch(void *e)
+ EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL);
+ // void __cxa_end_catch(void)
+ EnterCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL);
+ // void _Unwind_Resume_or_Rethrow(void*)
+ ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy, NULL);
+ }
+ }
+};
+
} // end anonymous namespace
@@ -242,45 +639,34 @@ void CGObjCGNU::EmitClassRef(const std::string &className) {
llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
}
-static std::string SymbolNameForMethod(const std::string &ClassName, const
- std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
-{
- std::string MethodNameColonStripped = MethodName;
+static std::string SymbolNameForMethod(const llvm::StringRef &ClassName,
+ const llvm::StringRef &CategoryName, const Selector MethodName,
+ bool isClassMethod) {
+ std::string MethodNameColonStripped = MethodName.getAsString();
std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
':', '_');
- return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
- CategoryName + "_" + MethodNameColonStripped;
-}
-static std::string MangleSelectorTypes(const std::string &TypeString) {
- std::string Mangled = TypeString;
- // Simple mangling to avoid breaking when we mix JIT / static code.
- // Not part of the ABI, subject to change without notice.
- std::replace(Mangled.begin(), Mangled.end(), '@', '_');
- std::replace(Mangled.begin(), Mangled.end(), ':', 'J');
- std::replace(Mangled.begin(), Mangled.end(), '*', 'e');
- std::replace(Mangled.begin(), Mangled.end(), '#', 'E');
- std::replace(Mangled.begin(), Mangled.end(), ':', 'j');
- std::replace(Mangled.begin(), Mangled.end(), '(', 'g');
- std::replace(Mangled.begin(), Mangled.end(), ')', 'G');
- std::replace(Mangled.begin(), Mangled.end(), '[', 'h');
- std::replace(Mangled.begin(), Mangled.end(), ']', 'H');
- return Mangled;
+ return (llvm::Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
+ CategoryName + "_" + MethodNameColonStripped).str();
}
-CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
- : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0),
- MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) {
+CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
+ unsigned protocolClassVersion)
+ : CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()),
+ ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion),
+ ProtocolVersion(protocolClassVersion) {
+
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
+ CodeGenTypes &Types = CGM.getTypes();
IntTy = cast<llvm::IntegerType>(
- CGM.getTypes().ConvertType(CGM.getContext().IntTy));
+ Types.ConvertType(CGM.getContext().IntTy));
LongTy = cast<llvm::IntegerType>(
- CGM.getTypes().ConvertType(CGM.getContext().LongTy));
+ Types.ConvertType(CGM.getContext().LongTy));
SizeTy = cast<llvm::IntegerType>(
- CGM.getTypes().ConvertType(CGM.getContext().getSizeType()));
+ Types.ConvertType(CGM.getContext().getSizeType()));
PtrDiffTy = cast<llvm::IntegerType>(
- CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()));
+ Types.ConvertType(CGM.getContext().getPointerDiffType()));
BoolTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
Int8Ty = llvm::Type::getInt8Ty(VMContext);
@@ -302,20 +688,54 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
PtrTy = PtrToInt8Ty;
// Object type
- ASTIdTy = CGM.getContext().getCanonicalType(CGM.getContext().getObjCIdType());
- if (QualType() == ASTIdTy) {
- IdTy = PtrToInt8Ty;
- } else {
+ QualType UnqualIdTy = CGM.getContext().getObjCIdType();
+ ASTIdTy = CanQualType();
+ if (UnqualIdTy != QualType()) {
+ ASTIdTy = CGM.getContext().getCanonicalType(UnqualIdTy);
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
+ } else {
+ IdTy = PtrToInt8Ty;
}
PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
+ ObjCSuperTy = llvm::StructType::get(VMContext, IdTy, IdTy, NULL);
+ PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy);
+
+ const llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+
+ // void objc_exception_throw(id);
+ ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL);
+ ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL);
+ // int objc_sync_enter(id);
+ SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy, NULL);
+ // int objc_sync_exit(id);
+ SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy, NULL);
+
+ // void objc_enumerationMutation (id)
+ EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy,
+ IdTy, NULL);
+
+ // id objc_getProperty(id, SEL, ptrdiff_t, BOOL)
+ GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy,
+ PtrDiffTy, BoolTy, NULL);
+ // void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL)
+ SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy,
+ PtrDiffTy, IdTy, BoolTy, BoolTy, NULL);
+ // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
+ GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy,
+ PtrDiffTy, BoolTy, BoolTy, NULL);
+ // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
+ SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy,
+ PtrDiffTy, BoolTy, BoolTy, NULL);
+
// IMP type
std::vector<const llvm::Type*> IMPArgs;
IMPArgs.push_back(IdTy);
IMPArgs.push_back(SelectorTy);
- IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
+ IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs,
+ true));
+ // Don't bother initialising the GC stuff unless we're compiling in GC mode
if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
// Get selectors needed in GC mode
RetainSel = GetNullarySelector("retain", CGM.getContext());
@@ -325,34 +745,21 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
// Get functions needed in GC mode
// id objc_assign_ivar(id, id, ptrdiff_t);
- std::vector<const llvm::Type*> Args(1, IdTy);
- Args.push_back(PtrToIdTy);
- Args.push_back(PtrDiffTy);
- llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Args, false);
- IvarAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
+ IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy,
+ NULL);
// id objc_assign_strongCast (id, id*)
- Args.pop_back();
- FTy = llvm::FunctionType::get(IdTy, Args, false);
- StrongCastAssignFn =
- CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
+ StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy,
+ PtrToIdTy, NULL);
// id objc_assign_global(id, id*);
- FTy = llvm::FunctionType::get(IdTy, Args, false);
- GlobalAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
+ GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy,
+ NULL);
// id objc_assign_weak(id, id*);
- FTy = llvm::FunctionType::get(IdTy, Args, false);
- WeakAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
+ WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy, NULL);
// id objc_read_weak(id*);
- Args.clear();
- Args.push_back(PtrToIdTy);
- FTy = llvm::FunctionType::get(IdTy, Args, false);
- WeakReadFn = CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
+ WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy, NULL);
// void *objc_memmove_collectable(void*, void *, size_t);
- Args.clear();
- Args.push_back(PtrToInt8Ty);
- Args.push_back(PtrToInt8Ty);
- Args.push_back(SizeTy);
- FTy = llvm::FunctionType::get(IdTy, Args, false);
- MemMoveFn = CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
+ MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy,
+ SizeTy, NULL);
}
}
@@ -378,79 +785,127 @@ llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
}
llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
+ const std::string &TypeEncoding, bool lval) {
+
+ llvm::SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel];
+ llvm::GlobalAlias *SelValue = 0;
+
+
+ for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
+ e = Types.end() ; i!=e ; i++) {
+ if (i->first == TypeEncoding) {
+ SelValue = i->second;
+ break;
+ }
+ }
+ if (0 == SelValue) {
+ SelValue = new llvm::GlobalAlias(SelectorTy,
+ llvm::GlobalValue::PrivateLinkage,
+ ".objc_selector_"+Sel.getAsString(), NULL,
+ &TheModule);
+ Types.push_back(TypedSelector(TypeEncoding, SelValue));
+ }
+
+ if (lval) {
+ llvm::Value *tmp = Builder.CreateAlloca(SelValue->getType());
+ Builder.CreateStore(SelValue, tmp);
+ return tmp;
+ }
+ return SelValue;
+}
+
+llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
bool lval) {
- llvm::GlobalAlias *&US = UntypedSelectors[Sel.getAsString()];
- if (US == 0)
- US = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
- llvm::GlobalValue::PrivateLinkage,
- ".objc_untyped_selector_alias"+Sel.getAsString(),
- NULL, &TheModule);
- if (lval)
- return US;
- return Builder.CreateLoad(US);
+ return GetSelector(Builder, Sel, std::string(), lval);
}
llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
*Method) {
-
- std::string SelName = Method->getSelector().getAsString();
std::string SelTypes;
CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes);
- // Typed selectors
- TypedSelector Selector = TypedSelector(SelName,
- SelTypes);
-
- // If it's already cached, return it.
- if (TypedSelectors[Selector]) {
- return Builder.CreateLoad(TypedSelectors[Selector]);
- }
-
- // If it isn't, cache it.
- llvm::GlobalAlias *Sel = new llvm::GlobalAlias(
- llvm::PointerType::getUnqual(SelectorTy),
- llvm::GlobalValue::PrivateLinkage, ".objc_selector_alias" + SelName,
- NULL, &TheModule);
- TypedSelectors[Selector] = Sel;
-
- return Builder.CreateLoad(Sel);
+ return GetSelector(Builder, Method->getSelector(), SelTypes, false);
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
- llvm_unreachable("asking for catch type for ObjC type in GNU runtime");
- return 0;
-}
+ if (!CGM.getLangOptions().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.getLangOptions().ObjCNonFragileABI) {
+ return MakeConstantString("@id");
+ } else {
+ return 0;
+ }
+ }
-llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str,
- const std::string &Name) {
- llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
- return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
-}
-llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str,
- const std::string prefix) {
- std::string name = prefix + Str;
- llvm::Constant *ConstStr = TheModule.getGlobalVariable(name);
- if (!ConstStr) {
- llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true);
- ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
- llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str);
+ // 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());
+ }
+ // For Objective-C++, we want to provide the ability to catch both C++ and
+ // Objective-C objects in the same function.
+
+ // There's a particular fixed type info for 'id'.
+ if (T->isObjCIdType() ||
+ T->isObjCQualifiedIdType()) {
+ llvm::Constant *IDEHType =
+ CGM.getModule().getGlobalVariable("__objc_id_type_info");
+ if (!IDEHType)
+ IDEHType =
+ new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, "__objc_id_type_info");
+ return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty);
}
- return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
-}
-
-llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, llvm::StringRef Name,
- llvm::GlobalValue::LinkageTypes linkage) {
- llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
- return new llvm::GlobalVariable(TheModule, Ty, false,
- linkage, C, Name);
-}
-llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, llvm::StringRef Name,
- llvm::GlobalValue::LinkageTypes linkage) {
- llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
- return new llvm::GlobalVariable(TheModule, Ty, false,
- linkage, C, Name);
+ const ObjCObjectPointerType *PT =
+ T->getAs<ObjCObjectPointerType>();
+ assert(PT && "Invalid @catch type.");
+ const ObjCInterfaceType *IT = PT->getInterfaceType();
+ assert(IT && "Invalid @catch type.");
+ std::string className = IT->getDecl()->getIdentifier()->getName();
+
+ std::string typeinfoName = "__objc_eh_typeinfo_" + className;
+
+ // Return the existing typeinfo if it exists
+ llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName);
+ if (typeinfo) return typeinfo;
+
+ // Otherwise create it.
+
+ // vtable for gnustep::libobjc::__objc_class_type_info
+ // It's quite ugly hard-coding this. Ideally we'd generate it using the host
+ // platform's name mangling.
+ const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE";
+ llvm::Constant *Vtable = TheModule.getGlobalVariable(vtableName);
+ if (!Vtable) {
+ Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true,
+ llvm::GlobalValue::ExternalLinkage, 0, vtableName);
+ }
+ llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2);
+ Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, &Two, 1);
+ Vtable = llvm::ConstantExpr::getBitCast(Vtable, PtrToInt8Ty);
+
+ llvm::Constant *typeName =
+ ExportUniqueString(className, "__objc_eh_typename_");
+
+ std::vector<llvm::Constant*> fields;
+ fields.push_back(Vtable);
+ fields.push_back(typeName);
+ llvm::Constant *TI =
+ MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty,
+ NULL), fields, "__objc_eh_typeinfo_" + className,
+ llvm::GlobalValue::LinkOnceODRLinkage);
+ return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty);
}
/// Generate an NSConstantString object.
@@ -479,8 +934,8 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
///Generates a message send where the super is the receiver. This is a message
///send to self with special delivery semantics indicating which class's method
///should be called.
-CodeGen::RValue
-CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
+RValue
+CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
@@ -505,18 +960,13 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CallArgList ActualArgs;
- ActualArgs.push_back(
- std::make_pair(RValue::get(Builder.CreateBitCast(Receiver, IdTy)),
- ASTIdTy));
- ActualArgs.push_back(std::make_pair(RValue::get(cmd),
- CGF.getContext().getObjCSelType()));
+ ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy);
+ ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
- const llvm::FunctionType *impType =
- Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
llvm::Value *ReceiverClass = 0;
if (isCategoryImpl) {
@@ -570,43 +1020,20 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0));
Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
- // Get the IMP
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy));
- Params.push_back(SelectorTy);
-
- llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
- llvm::Value *imp;
-
- if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
- // The lookup function returns a slot, which can be safely cached.
- llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy,
- IntTy, llvm::PointerType::getUnqual(impType), NULL);
-
- llvm::Constant *lookupFunction =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::PointerType::getUnqual(SlotTy), Params, true),
- "objc_slot_lookup_super");
-
- llvm::CallInst *slot = Builder.CreateCall(lookupFunction, lookupArgs,
- lookupArgs+2);
- slot->setOnlyReadsMemory();
+ ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
+ const llvm::FunctionType *impType =
+ Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
- imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
- } else {
- llvm::Constant *lookupFunction =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::PointerType::getUnqual(impType), Params, true),
- "objc_msg_lookup_super");
- imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2);
- }
+ // Get the IMP
+ llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd);
+ imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType));
llvm::Value *impMD[] = {
llvm::MDString::get(VMContext, Sel.getAsString()),
llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()),
llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage)
};
- llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3);
+ llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
llvm::Instruction *call;
RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
@@ -616,8 +1043,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
/// Generate code for a message send expression.
-CodeGen::RValue
-CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+RValue
+CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
@@ -646,11 +1073,10 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
// paragraph and insist on sending messages to nil that have structure
// returns. With GCC, this generates a random return value (whatever happens
// to be on the stack / in those registers at the time) on most platforms,
- // and generates a SegV on SPARC. With LLVM it corrupts the stack.
- bool isPointerSizedReturn = false;
- if (ResultType->isAnyPointerType() ||
- ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType())
- isPointerSizedReturn = true;
+ // and generates an illegal instruction trap on SPARC. With LLVM it corrupts
+ // the stack.
+ bool isPointerSizedReturn = (ResultType->isAnyPointerType() ||
+ ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType());
llvm::BasicBlock *startBB = 0;
llvm::BasicBlock *messageBB = 0;
@@ -673,13 +1099,22 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
cmd = GetSelector(Builder, Method);
else
cmd = GetSelector(Builder, Sel);
- CallArgList ActualArgs;
+ cmd = EnforceType(Builder, cmd, SelectorTy);
+ Receiver = EnforceType(Builder, Receiver, IdTy);
- Receiver = Builder.CreateBitCast(Receiver, IdTy);
- ActualArgs.push_back(
- std::make_pair(RValue::get(Receiver), ASTIdTy));
- ActualArgs.push_back(std::make_pair(RValue::get(cmd),
- CGF.getContext().getObjCSelType()));
+ llvm::Value *impMD[] = {
+ llvm::MDString::get(VMContext, Sel.getAsString()),
+ llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""),
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0)
+ };
+ llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
+
+ // Get the IMP to call
+ llvm::Value *imp = LookupIMP(CGF, Receiver, cmd, node);
+
+ CallArgList ActualArgs;
+ ActualArgs.add(RValue::get(Receiver), ASTIdTy);
+ ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
@@ -687,72 +1122,12 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
FunctionType::ExtInfo());
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
-
- llvm::Value *impMD[] = {
- llvm::MDString::get(VMContext, Sel.getAsString()),
- llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""),
- llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0)
- };
- llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3);
+ imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType));
- llvm::Value *imp;
// For sender-aware dispatch, we pass the sender as the third argument to a
// lookup function. When sending messages from C code, the sender is nil.
// objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
- if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
-
- std::vector<const llvm::Type*> Params;
- llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType());
- Builder.CreateStore(Receiver, ReceiverPtr);
- Params.push_back(ReceiverPtr->getType());
- Params.push_back(SelectorTy);
- llvm::Value *self;
-
- if (isa<ObjCMethodDecl>(CGF.CurCodeDecl)) {
- self = CGF.LoadObjCSelf();
- } else {
- self = llvm::ConstantPointerNull::get(IdTy);
- }
-
- Params.push_back(self->getType());
-
- // The lookup function returns a slot, which can be safely cached.
- llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy,
- IntTy, llvm::PointerType::getUnqual(impType), NULL);
- llvm::Constant *lookupFunction =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::PointerType::getUnqual(SlotTy), Params, true),
- "objc_msg_lookup_sender");
-
- // The lookup function is guaranteed not to capture the receiver pointer.
- if (llvm::Function *LookupFn = dyn_cast<llvm::Function>(lookupFunction)) {
- LookupFn->setDoesNotCapture(1);
- }
-
- llvm::CallInst *slot =
- Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self);
- slot->setOnlyReadsMemory();
- slot->setMetadata(msgSendMDKind, node);
-
- imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
-
- // The lookup function may have changed the receiver, so make sure we use
- // the new one.
- ActualArgs[0] = std::make_pair(RValue::get(
- Builder.CreateLoad(ReceiverPtr, true)), ASTIdTy);
- } else {
- std::vector<const llvm::Type*> Params;
- Params.push_back(Receiver->getType());
- Params.push_back(SelectorTy);
- llvm::Constant *lookupFunction =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::PointerType::getUnqual(impType), Params, true),
- "objc_msg_lookup");
-
- imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);
- cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node);
- }
llvm::Instruction *call;
RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
0, &call);
@@ -765,13 +1140,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(continueBB);
if (msgRet.isScalar()) {
llvm::Value *v = msgRet.getScalarVal();
- llvm::PHINode *phi = Builder.CreatePHI(v->getType());
+ llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
phi->addIncoming(v, messageBB);
phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB);
msgRet = RValue::get(phi);
} else if (msgRet.isAggregate()) {
llvm::Value *v = msgRet.getAggregateAddr();
- llvm::PHINode *phi = Builder.CreatePHI(v->getType());
+ llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
const llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType());
llvm::AllocaInst *NullVal =
CGF.CreateTempAlloca(RetTy->getElementType(), "null");
@@ -782,11 +1157,11 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
msgRet = RValue::getAggregate(phi);
} else /* isComplex() */ {
std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal();
- llvm::PHINode *phi = Builder.CreatePHI(v.first->getType());
+ llvm::PHINode *phi = Builder.CreatePHI(v.first->getType(), 2);
phi->addIncoming(v.first, messageBB);
phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()),
startBB);
- llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType());
+ llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType(), 2);
phi2->addIncoming(v.second, messageBB);
phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()),
startBB);
@@ -798,8 +1173,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
/// Generates a MethodList. Used in construction of a objc_class and
/// objc_category structures.
-llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
- const std::string &CategoryName,
+llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName,
+ const llvm::StringRef &CategoryName,
const llvm::SmallVectorImpl<Selector> &MethodSels,
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes,
bool isClassMethodList) {
@@ -809,24 +1184,24 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
llvm::StructType *ObjCMethodTy = llvm::StructType::get(VMContext,
PtrToInt8Ty, // Really a selector, but the runtime creates it us.
PtrToInt8Ty, // Method types
- llvm::PointerType::getUnqual(IMPTy), //Method pointer
+ IMPTy, //Method pointer
NULL);
std::vector<llvm::Constant*> Methods;
std::vector<llvm::Constant*> Elements;
for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) {
Elements.clear();
- if (llvm::Constant *Method =
+ llvm::Constant *Method =
TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
- MethodSels[i].getAsString(),
- isClassMethodList))) {
- llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString());
- Elements.push_back(C);
- Elements.push_back(MethodTypes[i]);
- Method = llvm::ConstantExpr::getBitCast(Method,
- llvm::PointerType::getUnqual(IMPTy));
- Elements.push_back(Method);
- Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements));
- }
+ MethodSels[i],
+ isClassMethodList));
+ assert(Method && "Can't generate metadata for method that doesn't exist");
+ llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString());
+ Elements.push_back(C);
+ Elements.push_back(MethodTypes[i]);
+ Method = llvm::ConstantExpr::getBitCast(Method,
+ IMPTy);
+ Elements.push_back(Method);
+ Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements));
}
// Array of method structures
@@ -951,8 +1326,10 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(llvm::ConstantInt::get(LongTy, info));
if (isMeta) {
llvm::TargetData td(&TheModule);
- Elements.push_back(llvm::ConstantInt::get(LongTy,
- td.getTypeSizeInBits(ClassTy)/8));
+ Elements.push_back(
+ llvm::ConstantInt::get(LongTy,
+ td.getTypeSizeInBits(ClassTy) /
+ CGM.getContext().getCharWidth()));
} else
Elements.push_back(InstanceSize);
Elements.push_back(IVars);
@@ -1063,10 +1440,9 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
std::vector<llvm::Constant*> Elements;
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
- int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ?
- NonFragileProtocolVersion : ProtocolVersion;
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ ProtocolVersion), IdTy));
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
Elements.push_back(ProtocolList);
Elements.push_back(MethodList);
@@ -1225,10 +1601,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::vector<llvm::Constant*> Elements;
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
- int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ?
- NonFragileProtocolVersion : ProtocolVersion;
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ ProtocolVersion), IdTy));
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
Elements.push_back(ProtocolList);
Elements.push_back(InstanceMethodList);
@@ -1486,13 +1861,9 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
"__objc_ivar_offset_value_" + ClassName +"." +
IVD->getNameAsString()));
}
- llvm::Constant *IvarOffsetArrayInit =
- llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy,
- IvarOffsetValues.size()), IvarOffsetValues);
- llvm::GlobalVariable *IvarOffsetArray = new llvm::GlobalVariable(TheModule,
- IvarOffsetArrayInit->getType(), false,
- llvm::GlobalValue::InternalLinkage, IvarOffsetArrayInit,
- ".ivar.offsets");
+ llvm::GlobalVariable *IvarOffsetArray =
+ MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets");
+
// Collect information about instance methods
llvm::SmallVector<Selector, 16> InstanceMethodSels;
@@ -1620,8 +1991,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Only emit an ObjC load function if no Objective-C stuff has been called
if (Classes.empty() && Categories.empty() && ConstantStrings.empty() &&
- ExistingProtocols.empty() && TypedSelectors.empty() &&
- UntypedSelectors.empty())
+ ExistingProtocols.empty() && SelectorTable.empty())
return NULL;
// Add all referenced protocols to a category.
@@ -1630,12 +2000,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
const llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>(
SelectorTy->getElementType());
const llvm::Type *SelStructPtrTy = SelectorTy;
- bool isSelOpaque = false;
if (SelStructTy == 0) {
SelStructTy = llvm::StructType::get(VMContext, PtrToInt8Ty,
PtrToInt8Ty, NULL);
SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy);
- isSelOpaque = true;
}
// Name the ObjC types to make the IR a bit easier to read
@@ -1652,7 +2020,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
ConstantStrings.push_back(NULLPtr);
llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass;
+
if (StringClass.empty()) StringClass = "NXConstantString";
+
Elements.push_back(MakeConstantString(StringClass,
".objc_static_class_name"));
Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy,
@@ -1682,75 +2052,62 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.clear();
// Pointer to an array of selectors used in this module.
std::vector<llvm::Constant*> Selectors;
- for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator
- iter = TypedSelectors.begin(), iterEnd = TypedSelectors.end();
- iter != iterEnd ; ++iter) {
- Elements.push_back(ExportUniqueString(iter->first.first, ".objc_sel_name"));
- Elements.push_back(MakeConstantString(iter->first.second,
- ".objc_sel_types"));
- Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
- Elements.clear();
- }
- for (llvm::StringMap<llvm::GlobalAlias*>::iterator
- iter = UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
- iter != iterEnd; ++iter) {
- Elements.push_back(
- ExportUniqueString(iter->getKeyData(), ".objc_sel_name"));
- Elements.push_back(NULLPtr);
- Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
- Elements.clear();
+ std::vector<llvm::GlobalAlias*> SelectorAliases;
+ for (SelectorMap::iterator iter = SelectorTable.begin(),
+ iterEnd = SelectorTable.end(); iter != iterEnd ; ++iter) {
+
+ std::string SelNameStr = iter->first.getAsString();
+ llvm::Constant *SelName = ExportUniqueString(SelNameStr, ".objc_sel_name");
+
+ llvm::SmallVectorImpl<TypedSelector> &Types = iter->second;
+ for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
+ e = Types.end() ; i!=e ; i++) {
+
+ llvm::Constant *SelectorTypeEncoding = NULLPtr;
+ if (!i->first.empty())
+ SelectorTypeEncoding = MakeConstantString(i->first, ".objc_sel_types");
+
+ Elements.push_back(SelName);
+ Elements.push_back(SelectorTypeEncoding);
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+
+ // Store the selector alias for later replacement
+ SelectorAliases.push_back(i->second);
+ }
}
+ unsigned SelectorCount = Selectors.size();
+ // NULL-terminate the selector list. This should not actually be required,
+ // because the selector list has a length field. Unfortunately, the GCC
+ // runtime decides to ignore the length field and expects a NULL terminator,
+ // and GCC cooperates with this by always setting the length to 0.
Elements.push_back(NULLPtr);
Elements.push_back(NULLPtr);
Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
Elements.clear();
+
// Number of static selectors
- Elements.push_back(llvm::ConstantInt::get(LongTy, Selectors.size() ));
- llvm::Constant *SelectorList = MakeGlobal(
- llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors,
+ Elements.push_back(llvm::ConstantInt::get(LongTy, SelectorCount));
+ llvm::Constant *SelectorList = MakeGlobalArray(SelStructTy, Selectors,
".objc_selector_list");
Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList,
SelStructPtrTy));
// Now that all of the static selectors exist, create pointers to them.
- int index = 0;
- for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator
- iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end();
- iter != iterEnd; ++iter) {
+ for (unsigned int i=0 ; i<SelectorCount ; i++) {
+
llvm::Constant *Idxs[] = {Zeros[0],
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
- llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy,
- true, llvm::GlobalValue::LinkOnceODRLinkage,
- llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
- MangleSelectorTypes(".objc_sel_ptr"+iter->first.first+"."+
- iter->first.second));
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), i), Zeros[0]};
+ // FIXME: We're generating redundant loads and stores here!
+ llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(SelectorList,
+ Idxs, 2);
// If selectors are defined as an opaque type, cast the pointer to this
// type.
- if (isSelOpaque) {
- SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,
- llvm::PointerType::getUnqual(SelectorTy));
- }
- (*iter).second->replaceAllUsesWith(SelPtr);
- (*iter).second->eraseFromParent();
- }
- for (llvm::StringMap<llvm::GlobalAlias*>::iterator
- iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end();
- iter != iterEnd; iter++) {
- llvm::Constant *Idxs[] = {Zeros[0],
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]};
- llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy,
- true, llvm::GlobalValue::LinkOnceODRLinkage,
- llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
- MangleSelectorTypes(std::string(".objc_sel_ptr")+iter->getKey().str()));
- // If selectors are defined as an opaque type, cast the pointer to this
- // type.
- if (isSelOpaque) {
- SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,
- llvm::PointerType::getUnqual(SelectorTy));
- }
- (*iter).second->replaceAllUsesWith(SelPtr);
- (*iter).second->eraseFromParent();
+ SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, SelectorTy);
+ SelectorAliases[i]->replaceAllUsesWith(SelPtr);
+ SelectorAliases[i]->eraseFromParent();
}
+
// Number of classes defined.
Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext),
Classes.size()));
@@ -1772,19 +2129,22 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy,
PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
Elements.clear();
- // Runtime version used for compatibility checking.
- if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
- Elements.push_back(llvm::ConstantInt::get(LongTy,
- NonFragileRuntimeVersion));
- } else {
- Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
- }
+ // Runtime version, used for ABI compatibility checking.
+ Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
// sizeof(ModuleTy)
llvm::TargetData td(&TheModule);
- Elements.push_back(llvm::ConstantInt::get(LongTy,
- td.getTypeSizeInBits(ModuleTy)/8));
- //FIXME: Should be the path to the file where this module was declared
- Elements.push_back(NULLPtr);
+ Elements.push_back(
+ llvm::ConstantInt::get(LongTy,
+ td.getTypeSizeInBits(ModuleTy) /
+ CGM.getContext().getCharWidth()));
+
+ // The path to the source file where this module was declared
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ const FileEntry *mainFile = SM.getFileEntryForID(SM.getMainFileID());
+ std::string path =
+ std::string(mainFile->getDir()->getName()) + '/' + mainFile->getName();
+ Elements.push_back(MakeConstantString(path, ".objc_source_file_name"));
+
Elements.push_back(SymTab);
llvm::Value *Module = MakeGlobal(ModuleTy, Elements);
@@ -1813,9 +2173,9 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
const ObjCCategoryImplDecl *OCD =
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
- std::string CategoryName = OCD ? OCD->getNameAsString() : "";
- std::string ClassName = CD->getName();
- std::string MethodName = OMD->getSelector().getAsString();
+ llvm::StringRef CategoryName = OCD ? OCD->getName() : "";
+ llvm::StringRef ClassName = CD->getName();
+ Selector MethodName = OMD->getSelector();
bool isClassMethod = !OMD->isInstanceMethod();
CodeGenTypes &Types = CGM.getTypes();
@@ -1833,121 +2193,31 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
}
llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(IdTy);
- Params.push_back(SelectorTy);
- Params.push_back(SizeTy);
- Params.push_back(BoolTy);
- // void objc_getProperty (id, SEL, ptrdiff_t, bool)
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(IdTy, Params, false);
- return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
- "objc_getProperty"));
+ return GetPropertyFn;
}
llvm::Function *CGObjCGNU::GetPropertySetFunction() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(IdTy);
- Params.push_back(SelectorTy);
- Params.push_back(SizeTy);
- Params.push_back(IdTy);
- Params.push_back(BoolTy);
- Params.push_back(BoolTy);
- // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
- return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
- "objc_setProperty"));
+ return SetPropertyFn;
}
llvm::Function *CGObjCGNU::GetGetStructFunction() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(PtrTy);
- Params.push_back(PtrTy);
- Params.push_back(PtrDiffTy);
- Params.push_back(BoolTy);
- Params.push_back(BoolTy);
- // objc_setPropertyStruct (void*, void*, ptrdiff_t, BOOL, BOOL)
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
- return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
- "objc_getPropertyStruct"));
+ return GetStructPropertyFn;
}
llvm::Function *CGObjCGNU::GetSetStructFunction() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(PtrTy);
- Params.push_back(PtrTy);
- Params.push_back(PtrDiffTy);
- Params.push_back(BoolTy);
- Params.push_back(BoolTy);
- // objc_setPropertyStruct (void*, void*, ptrdiff_t, BOOL, BOOL)
- const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
- return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
- "objc_setPropertyStruct"));
+ return SetStructPropertyFn;
}
llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
- CodeGen::CodeGenTypes &Types = CGM.getTypes();
- ASTContext &Ctx = CGM.getContext();
- // void objc_enumerationMutation (id)
- llvm::SmallVector<CanQualType,1> Params;
- Params.push_back(ASTIdTy);
- const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo()), false);
- return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
+ return EnumerationMutationFn;
}
-namespace {
- struct CallSyncExit : EHScopeStack::Cleanup {
- llvm::Value *SyncExitFn;
- llvm::Value *SyncArg;
- CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
- : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
-
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
- CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
- }
- };
-}
-
-void CGObjCGNU::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitSynchronizedStmt(CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S) {
- std::vector<const llvm::Type*> Args(1, IdTy);
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
-
- // Evaluate the lock operand. This should dominate the cleanup.
- llvm::Value *SyncArg =
- CGF.EmitScalarExpr(S.getSynchExpr());
-
- // Acquire the lock.
- llvm::Value *SyncEnter = CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
- SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
- CGF.Builder.CreateCall(SyncEnter, SyncArg);
-
- // Register an all-paths cleanup to release the lock.
- llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
- CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, SyncExit, SyncArg);
-
- // Emit the body of the statement.
- CGF.EmitStmt(S.getSynchBody());
-
- // Pop the lock-release cleanup.
- CGF.PopCleanupBlock();
+ EmitAtSynchronizedStmt(CGF, S, SyncEnterFn, SyncExitFn);
}
-namespace {
- struct CatchHandler {
- const VarDecl *Variable;
- const Stmt *Body;
- llvm::BasicBlock *Block;
- llvm::Value *TypeInfo;
- };
-}
-void CGObjCGNU::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF,
const ObjCAtTryStmt &S) {
// Unlike the Apple non-fragile runtimes, which also uses
// unwind-based zero cost exceptions, the GNU Objective C runtime's
@@ -1957,127 +2227,17 @@ void CGObjCGNU::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
// catch handlers with calls to __blah_begin_catch/__blah_end_catch
// (or even _Unwind_DeleteException), but probably doesn't
// interoperate very well with foreign exceptions.
-
- // Jump destination for falling out of catch bodies.
- CodeGenFunction::JumpDest Cont;
- if (S.getNumCatchStmts())
- Cont = CGF.getJumpDestInCurrentScope("eh.cont");
-
- // We handle @finally statements by pushing them as a cleanup
- // before entering the catch.
- CodeGenFunction::FinallyInfo FinallyInfo;
- if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) {
- std::vector<const llvm::Type*> Args(1, IdTy);
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
- llvm::Constant *Rethrow =
- CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
-
- FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(), 0, 0,
- Rethrow);
- }
-
- llvm::SmallVector<CatchHandler, 8> Handlers;
-
- // Enter the catch, if there is one.
- if (S.getNumCatchStmts()) {
- for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) {
- const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I);
- const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
-
- Handlers.push_back(CatchHandler());
- CatchHandler &Handler = Handlers.back();
- Handler.Variable = CatchDecl;
- Handler.Body = CatchStmt->getCatchBody();
- Handler.Block = CGF.createBasicBlock("catch");
-
- // @catch() and @catch(id) both catch any ObjC exception.
- // Treat them as catch-alls.
- // FIXME: this is what this code was doing before, but should 'id'
- // really be catching foreign exceptions?
- if (!CatchDecl
- || CatchDecl->getType()->isObjCIdType()
- || CatchDecl->getType()->isObjCQualifiedIdType()) {
-
- Handler.TypeInfo = 0; // catch-all
-
- // Don't consider any other catches.
- break;
- }
-
- // All other types should be Objective-C interface pointer types.
- const ObjCObjectPointerType *OPT =
- CatchDecl->getType()->getAs<ObjCObjectPointerType>();
- assert(OPT && "Invalid @catch type.");
- const ObjCInterfaceDecl *IDecl =
- OPT->getObjectType()->getInterface();
- assert(IDecl && "Invalid @catch type.");
- Handler.TypeInfo = MakeConstantString(IDecl->getNameAsString());
- }
-
- EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
- for (unsigned I = 0, E = Handlers.size(); I != E; ++I)
- Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block);
- }
-
- // Emit the try body.
- CGF.EmitStmt(S.getTryBody());
-
- // Leave the try.
- if (S.getNumCatchStmts())
- CGF.EHStack.popCatch();
-
- // Remember where we were.
- CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
-
- // Emit the handlers.
- for (unsigned I = 0, E = Handlers.size(); I != E; ++I) {
- CatchHandler &Handler = Handlers[I];
- CGF.EmitBlock(Handler.Block);
-
- llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
-
- // Bind the catch parameter if it exists.
- if (const VarDecl *CatchParam = Handler.Variable) {
- const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
- Exn = CGF.Builder.CreateBitCast(Exn, CatchType);
-
- CGF.EmitAutoVarDecl(*CatchParam);
- CGF.Builder.CreateStore(Exn, CGF.GetAddrOfLocalVar(CatchParam));
- }
-
- CGF.ObjCEHValueStack.push_back(Exn);
- CGF.EmitStmt(Handler.Body);
- CGF.ObjCEHValueStack.pop_back();
-
- CGF.EmitBranchThroughCleanup(Cont);
- }
-
- // Go back to the try-statement fallthrough.
- CGF.Builder.restoreIP(SavedIP);
-
- // Pop out of the finally.
- if (S.getFinallyStmt())
- CGF.ExitFinallyBlock(FinallyInfo);
-
- if (Cont.isValid()) {
- if (Cont.getBlock()->use_empty())
- delete Cont.getBlock();
- else
- CGF.EmitBlock(Cont.getBlock());
- }
+ //
+ // In Objective-C++ mode, we actually emit something equivalent to the C++
+ // exception handler.
+ EmitTryCatchStmt(CGF, S, EnterCatchFn, ExitCatchFn, ExceptionReThrowFn);
+ return ;
}
-void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
const ObjCAtThrowStmt &S) {
llvm::Value *ExceptionAsObject;
- std::vector<const llvm::Type*> Args(1, IdTy);
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
- llvm::Value *ThrowFn =
- CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
-
if (const Expr *ThrowExpr = S.getThrowExpr()) {
llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr);
ExceptionAsObject = Exception;
@@ -2100,24 +2260,24 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
// as a result of stupidity.
llvm::BasicBlock *UnwindBB = CGF.getInvokeDest();
if (!UnwindBB) {
- CGF.Builder.CreateCall(ThrowFn, ExceptionAsObject);
+ CGF.Builder.CreateCall(ExceptionThrowFn, ExceptionAsObject);
CGF.Builder.CreateUnreachable();
} else {
- CGF.Builder.CreateInvoke(ThrowFn, UnwindBB, UnwindBB, &ExceptionAsObject,
+ CGF.Builder.CreateInvoke(ExceptionThrowFn, UnwindBB, UnwindBB, &ExceptionAsObject,
&ExceptionAsObject+1);
}
// Clear the insertion point to indicate we are in unreachable code.
CGF.Builder.ClearInsertionPoint();
}
-llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
CGBuilderTy B = CGF.Builder;
AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy);
return B.CreateCall(WeakReadFn, AddrWeakObj);
}
-void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
CGBuilderTy B = CGF.Builder;
src = EnforceType(B, src, IdTy);
@@ -2125,7 +2285,7 @@ void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
B.CreateCall2(WeakAssignFn, src, dst);
}
-void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
CGBuilderTy B = CGF.Builder;
@@ -2138,7 +2298,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
assert(false && "EmitObjCGlobalAssign - Threal Local API NYI");
}
-void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
CGBuilderTy B = CGF.Builder;
@@ -2147,7 +2307,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
}
-void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
CGBuilderTy B = CGF.Builder;
src = EnforceType(B, src, IdTy);
@@ -2155,7 +2315,7 @@ void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
B.CreateCall2(StrongCastAssignFn, src, dst);
}
-void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
llvm::Value *Size) {
@@ -2212,7 +2372,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
return IvarOffsetPointer;
}
-LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
+LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF,
QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
@@ -2240,19 +2400,23 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
return 0;
}
-llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
if (CGM.getLangOptions().ObjCNonFragileABI) {
Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
- return CGF.Builder.CreateLoad(CGF.Builder.CreateLoad(
- ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar"));
+ return CGF.Builder.CreateZExtOrBitCast(
+ CGF.Builder.CreateLoad(CGF.Builder.CreateLoad(
+ ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar")),
+ PtrDiffTy);
}
uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
- return llvm::ConstantInt::get(LongTy, Offset, "ivar");
+ return llvm::ConstantInt::get(PtrDiffTy, Offset, "ivar");
}
-CodeGen::CGObjCRuntime *
-CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM) {
- return new CGObjCGNU(CGM);
+CGObjCRuntime *
+clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) {
+ if (CGM.getLangOptions().ObjCNonFragileABI)
+ return new CGObjCGNUstep(CGM);
+ return new CGObjCGCC(CGM);
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 8dbd85f8b738..2b1cfe3da5bd 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides Objective-C code generation targetting the Apple runtime.
+// This provides Objective-C code generation targeting the Apple runtime.
//
//===----------------------------------------------------------------------===//
@@ -42,9 +42,6 @@
using namespace clang;
using namespace CodeGen;
-// Common CGObjCRuntime functions, these don't belong here, but they
-// don't belong in CGObjCRuntime either so we will live with it for
-// now.
static void EmitNullReturnInitialization(CodeGenFunction &CGF,
ReturnValueSlot &returnSlot,
@@ -55,112 +52,6 @@ static void EmitNullReturnInitialization(CodeGenFunction &CGF,
CGF.EmitNullInitialization(returnSlot.getValue(), resultType);
}
-static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *OID,
- const ObjCImplementationDecl *ID,
- const ObjCIvarDecl *Ivar) {
- const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
-
- // FIXME: We should eliminate the need to have ObjCImplementationDecl passed
- // in here; it should never be necessary because that should be the lexical
- // decl context for the ivar.
-
- // If we know have an implementation (and the ivar is in it) then
- // look up in the implementation layout.
- const ASTRecordLayout *RL;
- if (ID && ID->getClassInterface() == Container)
- RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
- else
- RL = &CGM.getContext().getASTObjCInterfaceLayout(Container);
-
- // Compute field index.
- //
- // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is
- // implemented. This should be fixed to get the information from the layout
- // directly.
- unsigned Index = 0;
- llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
- CGM.getContext().ShallowCollectObjCIvars(Container, Ivars);
- for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
- if (Ivar == Ivars[k])
- break;
- ++Index;
- }
- assert(Index != Ivars.size() && "Ivar is not inside container!");
- assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
-
- return RL->getFieldOffset(Index);
-}
-
-uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *OID,
- const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, OID, 0, Ivar) / 8;
-}
-
-uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
- const ObjCImplementationDecl *OID,
- const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) / 8;
-}
-
-LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *OID,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers,
- llvm::Value *Offset) {
- // Compute (type*) ( (char *) BaseValue + Offset)
- const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- QualType IvarTy = Ivar->getType();
- const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
- llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr);
- V = CGF.Builder.CreateGEP(V, Offset, "add.ptr");
- V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
-
- if (!Ivar->isBitField()) {
- LValue LV = CGF.MakeAddrLValue(V, IvarTy);
- LV.getQuals().addCVRQualifiers(CVRQualifiers);
- return LV;
- }
-
- // We need to compute an access strategy for this bit-field. We are given the
- // offset to the first byte in the bit-field, the sub-byte offset is taken
- // from the original layout. We reuse the normal bit-field access strategy by
- // treating this as an access to a struct where the bit-field is in byte 0,
- // and adjust the containing type size as appropriate.
- //
- // FIXME: Note that currently we make a very conservative estimate of the
- // alignment of the bit-field, because (a) it is not clear what guarantees the
- // runtime makes us, and (b) we don't have a way to specify that the struct is
- // at an alignment plus offset.
- //
- // Note, there is a subtle invariant here: we can only call this routine on
- // non-synthesized ivars but we may be called for synthesized ivars. However,
- // a synthesized ivar can never be a bit-field, so this is safe.
- const ASTRecordLayout &RL =
- CGF.CGM.getContext().getASTObjCInterfaceLayout(OID);
- uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize());
- uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar);
- uint64_t BitOffset = FieldBitOffset % 8;
- uint64_t ContainingTypeAlign = 8;
- uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset);
- uint64_t BitFieldSize =
- Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue();
-
- // Allocate a new CGBitFieldInfo object to describe this access.
- //
- // FIXME: This is incredibly wasteful, these should be uniqued or part of some
- // layout object. However, this is blocked on other cleanups to the
- // Objective-C code, so for now we just live with allocating a bunch of these
- // objects.
- CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
- CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
- ContainingTypeSize, ContainingTypeAlign));
-
- return LValue::MakeBitfield(V, *Info,
- IvarTy.getCVRQualifiers() | CVRQualifiers);
-}
///
@@ -328,7 +219,7 @@ public:
CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
Params.push_back(IdType);
Params.push_back(SelType);
- Params.push_back(Ctx.LongTy);
+ Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
@@ -346,7 +237,7 @@ public:
CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
Params.push_back(IdType);
Params.push_back(SelType);
- Params.push_back(Ctx.LongTy);
+ Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(IdType);
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
@@ -1294,7 +1185,8 @@ private:
llvm::Value *Receiver,
QualType Arg0Ty,
bool IsSuper,
- const CallArgList &CallArgs);
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
@@ -1555,7 +1447,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// Create and init a super structure; this is a (receiver, class)
// pair we will pass to objc_msgSendSuper.
llvm::Value *ObjCSuper =
- CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super");
+ CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super");
llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
CGF.Builder.CreateStore(ReceiverAsObject,
@@ -1630,9 +1522,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
- ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty));
- ActualArgs.push_back(std::make_pair(RValue::get(Sel),
- CGF.getContext().getObjCSelType()));
+ ActualArgs.add(RValue::get(Arg0), Arg0Ty);
+ ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
@@ -2177,6 +2068,8 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
4, true);
DefinedCategories.push_back(GV);
DefinedCategoryNames.insert(ExtName.str());
+ // method definition entries must be clear for next implementation.
+ MethodDefinitions.clear();
}
// FIXME: Get from somewhere?
@@ -2304,6 +2197,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
else
GV = CreateMetadataVar(Name, Init, Section, 4, true);
DefinedClasses.push_back(GV);
+ // method definition entries must be clear for next implementation.
+ MethodDefinitions.clear();
}
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
@@ -3596,7 +3491,9 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
llvm::ConstantArray::get(VMContext,
Ident->getNameStart()),
- "__TEXT,__cstring,cstring_literals",
+ ((ObjCABI == 2) ?
+ "__TEXT,__objc_classname,cstring_literals" :
+ "__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
@@ -3668,7 +3565,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
// Note that 'i' here is actually the field index inside RD of Field,
// although this dependency is hidden.
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- FieldOffset = RL.getFieldOffset(i) / 8;
+ FieldOffset = RL.getFieldOffset(i) / ByteSizeInBits;
} else
FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
@@ -3920,7 +3817,9 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string& BitMap) {
llvm::GlobalVariable * Entry =
CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
llvm::ConstantArray::get(VMContext, BitMap.c_str()),
- "__TEXT,__cstring,cstring_literals",
+ ((ObjCABI == 2) ?
+ "__TEXT,__objc_classname,cstring_literals" :
+ "__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -3999,7 +3898,9 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_",
llvm::ConstantArray::get(VMContext, Sel.getAsString()),
- "__TEXT,__cstring,cstring_literals",
+ ((ObjCABI == 2) ?
+ "__TEXT,__objc_methname,cstring_literals" :
+ "__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
@@ -4019,7 +3920,9 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
llvm::ConstantArray::get(VMContext, TypeStr),
- "__TEXT,__cstring,cstring_literals",
+ ((ObjCABI == 2) ?
+ "__TEXT,__objc_methtype,cstring_literals" :
+ "__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
@@ -4035,7 +3938,9 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
llvm::ConstantArray::get(VMContext, TypeStr),
- "__TEXT,__cstring,cstring_literals",
+ ((ObjCABI == 2) ?
+ "__TEXT,__objc_methtype,cstring_literals" :
+ "__TEXT,__cstring,cstring_literals"),
1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
@@ -4173,11 +4078,11 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// }
RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
Ctx.getTranslationUnitDecl(),
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_objc_super"));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.getObjCIdType(), 0, 0, false));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.getObjCClassType(), 0, 0, false));
RD->completeDefinition();
@@ -4636,11 +4541,11 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// First the clang type for struct _message_ref_t
RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct,
Ctx.getTranslationUnitDecl(),
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.VoidPtrTy, 0, 0, false));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
Ctx.getObjCSelType(), 0, 0, false));
RD->completeDefinition();
@@ -4966,7 +4871,7 @@ void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
if (!RL.getFieldCount())
InstanceStart = InstanceSize;
else
- InstanceStart = RL.getFieldOffset(0) / 8;
+ InstanceStart = RL.getFieldOffset(0) / CGM.getContext().getCharWidth();
}
void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
@@ -5017,14 +4922,14 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
Root = Super;
IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString());
- if (Root->hasAttr<WeakImportAttr>())
+ if (Root->isWeakImported())
IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
// work on super class metadata symbol.
std::string SuperClassName =
ObjCMetaClassName +
ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(SuperClassName);
- if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>())
+ if (ID->getClassInterface()->getSuperClass()->isWeakImported())
SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags,
@@ -5054,7 +4959,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
std::string RootClassName =
ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName);
- if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>())
+ if (ID->getClassInterface()->getSuperClass()->isWeakImported())
SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
GetClassSizeInfo(ID, InstanceStart, InstanceSize);
@@ -5076,6 +4981,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
// Force the definition of the EHType if necessary.
if (flags & CLS_EXCEPTION)
GetInterfaceEHType(ID->getClassInterface(), true);
+ // Make sure method definition entries are all clear for next implementation.
+ MethodDefinitions.clear();
}
/// GenerateProtocolRef - This routine is called to generate code for
@@ -5136,7 +5043,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values[0] = GetClassName(OCD->getIdentifier());
// meta-class entry symbol
llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName);
- if (Interface->hasAttr<WeakImportAttr>())
+ if (Interface->isWeakImported())
ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
Values[1] = ClassGV;
@@ -5204,6 +5111,8 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
// Determine if this category is also "non-lazy".
if (ImplementationIsNonLazy(OCD))
DefinedNonLazyCategories.push_back(GCATV);
+ // method definition entries must be clear for next implementation.
+ MethodDefinitions.clear();
}
/// GetMethodConstant - Return a struct objc_method constant for the
@@ -5622,7 +5531,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
llvm::Value *Receiver,
QualType Arg0Ty,
bool IsSuper,
- const CallArgList &CallArgs) {
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
// FIXME. Even though IsSuper is passes. This function doese not handle calls
// to 'super' receivers.
CodeGenTypes &Types = CGM.getTypes();
@@ -5685,15 +5595,15 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
llvm::Value *Arg1 = CGF.Builder.CreateBitCast(GV, ObjCTypes.MessageRefPtrTy);
CallArgList ActualArgs;
- ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty));
- ActualArgs.push_back(std::make_pair(RValue::get(Arg1),
- ObjCTypes.MessageRefCPtrTy));
+ ActualArgs.add(RValue::get(Arg0), Arg0Ty);
+ ActualArgs.add(RValue::get(Arg1), ObjCTypes.MessageRefCPtrTy);
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
Callee = CGF.Builder.CreateLoad(Callee);
- const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(FnInfo1, Method ? Method->isVariadic() : false);
Callee = CGF.Builder.CreateBitCast(Callee,
llvm::PointerType::getUnqual(FTy));
return CGF.EmitCall(FnInfo1, Callee, Return, ActualArgs);
@@ -5716,7 +5626,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
false, CallArgs, Method, ObjCTypes)
: EmitMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs);
+ false, CallArgs, Method);
}
llvm::GlobalVariable *
@@ -5807,7 +5717,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
/// decl.
llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
- if (ID->hasAttr<WeakImportAttr>()) {
+ if (ID->isWeakImported()) {
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
@@ -5834,7 +5744,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// Create and init a super structure; this is a (receiver, class)
// pair we will pass to objc_msgSendSuper.
llvm::Value *ObjCSuper =
- CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super");
+ CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super");
llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
@@ -5870,7 +5780,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
true, CallArgs, Method, ObjCTypes)
: EmitMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs);
+ true, CallArgs, Method);
}
llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
@@ -6008,65 +5918,12 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
return;
}
-namespace {
- struct CallSyncExit : EHScopeStack::Cleanup {
- llvm::Value *SyncExitFn;
- llvm::Value *SyncArg;
- CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
- : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
-
- void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
- CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
- }
- };
-}
-
void
CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S) {
- // Evaluate the lock operand. This should dominate the cleanup.
- llvm::Value *SyncArg = CGF.EmitScalarExpr(S.getSynchExpr());
-
- // Acquire the lock.
- SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg)
- ->setDoesNotThrow();
-
- // Register an all-paths cleanup to release the lock.
- CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup,
- ObjCTypes.getSyncExitFn(),
- SyncArg);
-
- // Emit the body of the statement.
- CGF.EmitStmt(S.getSynchBody());
-
- // Pop the lock-release cleanup.
- CGF.PopCleanupBlock();
-}
-
-namespace {
- struct CatchHandler {
- const VarDecl *Variable;
- const Stmt *Body;
- llvm::BasicBlock *Block;
- llvm::Value *TypeInfo;
- };
-
- struct CallObjCEndCatch : EHScopeStack::Cleanup {
- CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) :
- MightThrow(MightThrow), Fn(Fn) {}
- bool MightThrow;
- llvm::Value *Fn;
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- if (!MightThrow) {
- CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
- return;
- }
-
- CGF.EmitCallOrInvoke(Fn, 0, 0);
- }
- };
+ EmitAtSynchronizedStmt(CGF, S,
+ cast<llvm::Function>(ObjCTypes.getSyncEnterFn()),
+ cast<llvm::Function>(ObjCTypes.getSyncExitFn()));
}
llvm::Constant *
@@ -6096,104 +5953,10 @@ CGObjCNonFragileABIMac::GetEHType(QualType T) {
void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S) {
- // Jump destination for falling out of catch bodies.
- CodeGenFunction::JumpDest Cont;
- if (S.getNumCatchStmts())
- Cont = CGF.getJumpDestInCurrentScope("eh.cont");
-
- CodeGenFunction::FinallyInfo FinallyInfo;
- if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
- FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(),
- ObjCTypes.getObjCBeginCatchFn(),
- ObjCTypes.getObjCEndCatchFn(),
- ObjCTypes.getExceptionRethrowFn());
-
- llvm::SmallVector<CatchHandler, 8> Handlers;
-
- // Enter the catch, if there is one.
- if (S.getNumCatchStmts()) {
- for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) {
- const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I);
- const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
-
- Handlers.push_back(CatchHandler());
- CatchHandler &Handler = Handlers.back();
- Handler.Variable = CatchDecl;
- Handler.Body = CatchStmt->getCatchBody();
- Handler.Block = CGF.createBasicBlock("catch");
-
- // @catch(...) always matches.
- if (!CatchDecl) {
- Handler.TypeInfo = 0; // catch-all
- // Don't consider any other catches.
- break;
- }
-
- Handler.TypeInfo = GetEHType(CatchDecl->getType());
- }
-
- EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
- for (unsigned I = 0, E = Handlers.size(); I != E; ++I)
- Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block);
- }
-
- // Emit the try body.
- CGF.EmitStmt(S.getTryBody());
-
- // Leave the try.
- if (S.getNumCatchStmts())
- CGF.EHStack.popCatch();
-
- // Remember where we were.
- CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
-
- // Emit the handlers.
- for (unsigned I = 0, E = Handlers.size(); I != E; ++I) {
- CatchHandler &Handler = Handlers[I];
-
- CGF.EmitBlock(Handler.Block);
- llvm::Value *RawExn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
-
- // Enter the catch.
- llvm::CallInst *Exn =
- CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), RawExn,
- "exn.adjusted");
- Exn->setDoesNotThrow();
-
- // Add a cleanup to leave the catch.
- bool EndCatchMightThrow = (Handler.Variable == 0);
- CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
- EndCatchMightThrow,
- ObjCTypes.getObjCEndCatchFn());
-
- // Bind the catch parameter if it exists.
- if (const VarDecl *CatchParam = Handler.Variable) {
- const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
- llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType);
-
- CGF.EmitAutoVarDecl(*CatchParam);
- CGF.Builder.CreateStore(CastExn, CGF.GetAddrOfLocalVar(CatchParam));
- }
-
- CGF.ObjCEHValueStack.push_back(Exn);
- CGF.EmitStmt(Handler.Body);
- CGF.ObjCEHValueStack.pop_back();
-
- // Leave the earlier cleanup.
- CGF.PopCleanupBlock();
-
- CGF.EmitBranchThroughCleanup(Cont);
- }
-
- // Go back to the try-statement fallthrough.
- CGF.Builder.restoreIP(SavedIP);
-
- // Pop out of the normal cleanup on the finally.
- if (S.getFinallyStmt())
- CGF.ExitFinallyBlock(FinallyInfo);
-
- if (Cont.isValid())
- CGF.EmitBlock(Cont.getBlock());
+ EmitTryCatchStmt(CGF, S,
+ cast<llvm::Function>(ObjCTypes.getObjCBeginCatchFn()),
+ cast<llvm::Function>(ObjCTypes.getObjCEndCatchFn()),
+ cast<llvm::Function>(ObjCTypes.getExceptionRethrowFn()));
}
/// EmitThrowStmt - Generate code for a throw statement.
@@ -6290,10 +6053,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
CodeGen::CGObjCRuntime *
CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
+ if (CGM.getLangOptions().ObjCNonFragileABI)
+ return new CGObjCNonFragileABIMac(CGM);
return new CGObjCMac(CGM);
}
-
-CodeGen::CGObjCRuntime *
-CodeGen::CreateMacNonFragileABIObjCRuntime(CodeGen::CodeGenModule &CGM) {
- return new CGObjCNonFragileABIMac(CGM);
-}
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
new file mode 100644
index 000000000000..3d854d41acbe
--- /dev/null
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -0,0 +1,310 @@
+//==- CGObjCRuntime.cpp - Interface to Shared Objective-C Runtime Features ==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This abstract class defines the interface for Objective-C runtime-specific
+// code generation. It provides some concrete helper methods for functionality
+// shared between all (or most) of the Objective-C runtimes supported by clang.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGObjCRuntime.h"
+
+#include "CGRecordLayout.h"
+#include "CodeGenModule.h"
+#include "CodeGenFunction.h"
+#include "CGCleanup.h"
+
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtObjC.h"
+
+#include "llvm/Support/CallSite.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *OID,
+ const ObjCImplementationDecl *ID,
+ const ObjCIvarDecl *Ivar) {
+ const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
+
+ // FIXME: We should eliminate the need to have ObjCImplementationDecl passed
+ // in here; it should never be necessary because that should be the lexical
+ // decl context for the ivar.
+
+ // If we know have an implementation (and the ivar is in it) then
+ // look up in the implementation layout.
+ const ASTRecordLayout *RL;
+ if (ID && ID->getClassInterface() == Container)
+ RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
+ else
+ RL = &CGM.getContext().getASTObjCInterfaceLayout(Container);
+
+ // Compute field index.
+ //
+ // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is
+ // implemented. This should be fixed to get the information from the layout
+ // directly.
+ unsigned Index = 0;
+ llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
+ CGM.getContext().ShallowCollectObjCIvars(Container, Ivars);
+ for (unsigned k = 0, e = Ivars.size(); k != e; ++k) {
+ if (Ivar == Ivars[k])
+ break;
+ ++Index;
+ }
+ assert(Index != Ivars.size() && "Ivar is not inside container!");
+ assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
+
+ return RL->getFieldOffset(Index);
+}
+
+uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCInterfaceDecl *OID,
+ const ObjCIvarDecl *Ivar) {
+ return LookupFieldBitOffset(CGM, OID, 0, Ivar) /
+ CGM.getContext().getCharWidth();
+}
+
+uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
+ const ObjCImplementationDecl *OID,
+ const ObjCIvarDecl *Ivar) {
+ return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) /
+ CGM.getContext().getCharWidth();
+}
+
+LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *OID,
+ llvm::Value *BaseValue,
+ const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers,
+ llvm::Value *Offset) {
+ // Compute (type*) ( (char *) BaseValue + Offset)
+ const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ QualType IvarTy = Ivar->getType();
+ const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
+ llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr);
+ V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
+ V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
+
+ if (!Ivar->isBitField()) {
+ LValue LV = CGF.MakeAddrLValue(V, IvarTy);
+ LV.getQuals().addCVRQualifiers(CVRQualifiers);
+ return LV;
+ }
+
+ // We need to compute an access strategy for this bit-field. We are given the
+ // offset to the first byte in the bit-field, the sub-byte offset is taken
+ // from the original layout. We reuse the normal bit-field access strategy by
+ // treating this as an access to a struct where the bit-field is in byte 0,
+ // and adjust the containing type size as appropriate.
+ //
+ // FIXME: Note that currently we make a very conservative estimate of the
+ // alignment of the bit-field, because (a) it is not clear what guarantees the
+ // runtime makes us, and (b) we don't have a way to specify that the struct is
+ // at an alignment plus offset.
+ //
+ // Note, there is a subtle invariant here: we can only call this routine on
+ // non-synthesized ivars but we may be called for synthesized ivars. However,
+ // a synthesized ivar can never be a bit-field, so this is safe.
+ const ASTRecordLayout &RL =
+ CGF.CGM.getContext().getASTObjCInterfaceLayout(OID);
+ uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize());
+ uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar);
+ uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
+ uint64_t ContainingTypeAlign = CGF.CGM.getContext().Target.getCharAlign();
+ uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset);
+ uint64_t BitFieldSize =
+ Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue();
+
+ // Allocate a new CGBitFieldInfo object to describe this access.
+ //
+ // FIXME: This is incredibly wasteful, these should be uniqued or part of some
+ // layout object. However, this is blocked on other cleanups to the
+ // Objective-C code, so for now we just live with allocating a bunch of these
+ // objects.
+ CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
+ CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
+ ContainingTypeSize, ContainingTypeAlign));
+
+ return LValue::MakeBitfield(V, *Info,
+ IvarTy.getCVRQualifiers() | CVRQualifiers);
+}
+
+namespace {
+ struct CatchHandler {
+ const VarDecl *Variable;
+ const Stmt *Body;
+ llvm::BasicBlock *Block;
+ llvm::Value *TypeInfo;
+ };
+
+ struct CallObjCEndCatch : EHScopeStack::Cleanup {
+ CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) :
+ MightThrow(MightThrow), Fn(Fn) {}
+ bool MightThrow;
+ llvm::Value *Fn;
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ if (!MightThrow) {
+ CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
+ return;
+ }
+
+ CGF.EmitCallOrInvoke(Fn, 0, 0);
+ }
+ };
+}
+
+
+void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
+ const ObjCAtTryStmt &S,
+ llvm::Function *beginCatchFn,
+ llvm::Function *endCatchFn,
+ llvm::Function *exceptionRethrowFn) {
+ // Jump destination for falling out of catch bodies.
+ CodeGenFunction::JumpDest Cont;
+ if (S.getNumCatchStmts())
+ Cont = CGF.getJumpDestInCurrentScope("eh.cont");
+
+ CodeGenFunction::FinallyInfo FinallyInfo;
+ if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
+ FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(),
+ beginCatchFn,
+ endCatchFn,
+ exceptionRethrowFn);
+
+ llvm::SmallVector<CatchHandler, 8> Handlers;
+
+ // Enter the catch, if there is one.
+ if (S.getNumCatchStmts()) {
+ for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) {
+ const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I);
+ const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+
+ Handlers.push_back(CatchHandler());
+ CatchHandler &Handler = Handlers.back();
+ Handler.Variable = CatchDecl;
+ Handler.Body = CatchStmt->getCatchBody();
+ Handler.Block = CGF.createBasicBlock("catch");
+
+ // @catch(...) always matches.
+ if (!CatchDecl) {
+ Handler.TypeInfo = 0; // catch-all
+ // Don't consider any other catches.
+ break;
+ }
+
+ Handler.TypeInfo = GetEHType(CatchDecl->getType());
+ }
+
+ EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size());
+ for (unsigned I = 0, E = Handlers.size(); I != E; ++I)
+ Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block);
+ }
+
+ // Emit the try body.
+ CGF.EmitStmt(S.getTryBody());
+
+ // Leave the try.
+ if (S.getNumCatchStmts())
+ CGF.EHStack.popCatch();
+
+ // Remember where we were.
+ CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
+
+ // Emit the handlers.
+ for (unsigned I = 0, E = Handlers.size(); I != E; ++I) {
+ CatchHandler &Handler = Handlers[I];
+
+ CGF.EmitBlock(Handler.Block);
+ llvm::Value *RawExn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
+
+ // Enter the catch.
+ llvm::Value *Exn = RawExn;
+ if (beginCatchFn) {
+ Exn = CGF.Builder.CreateCall(beginCatchFn, RawExn, "exn.adjusted");
+ cast<llvm::CallInst>(Exn)->setDoesNotThrow();
+ }
+
+ if (endCatchFn) {
+ // Add a cleanup to leave the catch.
+ bool EndCatchMightThrow = (Handler.Variable == 0);
+
+ CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
+ EndCatchMightThrow,
+ endCatchFn);
+ }
+
+ // Bind the catch parameter if it exists.
+ if (const VarDecl *CatchParam = Handler.Variable) {
+ const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType());
+ llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType);
+
+ CGF.EmitAutoVarDecl(*CatchParam);
+ CGF.Builder.CreateStore(CastExn, CGF.GetAddrOfLocalVar(CatchParam));
+ }
+
+ CGF.ObjCEHValueStack.push_back(Exn);
+ CGF.EmitStmt(Handler.Body);
+ CGF.ObjCEHValueStack.pop_back();
+
+ // Leave the earlier cleanup.
+ if (endCatchFn)
+ CGF.PopCleanupBlock();
+
+ CGF.EmitBranchThroughCleanup(Cont);
+ }
+
+ // Go back to the try-statement fallthrough.
+ CGF.Builder.restoreIP(SavedIP);
+
+ // Pop out of the normal cleanup on the finally.
+ if (S.getFinallyStmt())
+ CGF.ExitFinallyBlock(FinallyInfo);
+
+ if (Cont.isValid())
+ CGF.EmitBlock(Cont.getBlock());
+}
+
+namespace {
+ struct CallSyncExit : EHScopeStack::Cleanup {
+ llvm::Value *SyncExitFn;
+ llvm::Value *SyncArg;
+ CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
+ : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
+
+ void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
+ }
+ };
+}
+
+void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
+ const ObjCAtSynchronizedStmt &S,
+ llvm::Function *syncEnterFn,
+ llvm::Function *syncExitFn) {
+ // Evaluate the lock operand. This should dominate the cleanup.
+ llvm::Value *SyncArg =
+ CGF.EmitScalarExpr(S.getSynchExpr());
+
+ // Acquire the lock.
+ SyncArg = CGF.Builder.CreateBitCast(SyncArg, syncEnterFn->getFunctionType()->getParamType(0));
+ CGF.Builder.CreateCall(syncEnterFn, SyncArg);
+
+ // Register an all-paths cleanup to release the lock.
+ CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn,
+ SyncArg);
+
+ // Emit the body of the statement.
+ CGF.EmitStmt(S.getSynchBody());
+
+ // Pop the lock-release cleanup.
+ CGF.PopCleanupBlock();
+}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 5ad3a50adc3f..0cc2d824d401 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -17,7 +17,6 @@
#define CLANG_CODEGEN_OBCJRUNTIME_H
#include "clang/Basic/IdentifierTable.h" // Selector
#include "clang/AST/DeclObjC.h"
-#include <string>
#include "CGBuilder.h"
#include "CGCall.h"
@@ -87,6 +86,26 @@ protected:
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers,
llvm::Value *Offset);
+ /// Emits a try / catch statement. This function is intended to be called by
+ /// subclasses, and provides a generic mechanism for generating these, which
+ /// should be usable by all runtimes. The caller must provide the functions to
+ /// call when entering and exiting a @catch() block, and the function used to
+ /// rethrow exceptions. If the begin and end catch functions are NULL, then
+ /// the function assumes that the EH personality function provides the
+ /// thrown object directly.
+ void EmitTryCatchStmt(CodeGenFunction &CGF,
+ const ObjCAtTryStmt &S,
+ llvm::Function *beginCatchFn,
+ llvm::Function *endCatchFn,
+ llvm::Function *exceptionRethrowFn);
+ /// Emits an @synchronize() statement, using the syncEnterFn and syncExitFn
+ /// arguments as the functions called to lock and unlock the object. This
+ /// function can be called by subclasses that use zero-cost exception
+ /// handling.
+ void EmitAtSynchronizedStmt(CodeGenFunction &CGF,
+ const ObjCAtSynchronizedStmt &S,
+ llvm::Function *syncEnterFn,
+ llvm::Function *syncExitFn);
public:
virtual ~CGObjCRuntime();
@@ -118,7 +137,7 @@ public:
/// accompanying metadata) and a list of protocols.
virtual void GenerateCategory(const ObjCCategoryImplDecl *OCD) = 0;
- /// Generate a class stucture for this class.
+ /// Generate a class structure for this class.
virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0;
/// Generate an Objective-C message send operation.
@@ -230,7 +249,6 @@ public:
//TODO: This should include some way of selecting which runtime to target.
CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM);
CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM);
-CGObjCRuntime *CreateMacNonFragileABIObjCRuntime(CodeGenModule &CGM);
}
}
#endif
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 7ec0ee4b5cab..c73b199e31f7 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "CGObjCRuntime.h"
using namespace clang;
using namespace CodeGen;
@@ -195,7 +196,9 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- assert(false && "Should not see this type here!");
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ llvm_unreachable("asking for RRTI for a placeholder type!");
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
@@ -875,14 +878,16 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// For a non-virtual base, this is the offset in the object of the base
// subobject. For a virtual base, this is the offset in the virtual table of
// the virtual base offset for the virtual base referenced (negative).
+ CharUnits Offset;
if (Base->isVirtual())
- OffsetFlags = CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl);
+ Offset =
+ CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl);
else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- OffsetFlags = Layout.getBaseClassOffsetInBits(BaseDecl) / 8;
+ Offset = Layout.getBaseClassOffset(BaseDecl);
};
- OffsetFlags <<= 8;
+ OffsetFlags = Offset.getQuantity() << 8;
// The low-order byte of __offset_flags contains flags, as given by the
// masks from the enumeration __offset_flags_masks.
@@ -977,6 +982,10 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
return llvm::Constant::getNullValue(Int8PtrTy);
}
+
+ if (ForEH && Ty->isObjCObjectPointerType() && !Features.NeXTRuntime) {
+ return Runtime->GetEHType(Ty);
+ }
return RTTIBuilder(*this).BuildTypeInfo(Ty);
}
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 30da05f421fe..6d9fc0589e93 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -12,6 +12,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/DerivedTypes.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
namespace llvm {
class raw_ostream;
@@ -53,7 +54,7 @@ public:
/// unused as the cleanest IR comes from having a well-constructed LLVM type
/// with proper GEP instructions, but sometimes its use is required, for
/// example if an access is intended to straddle an LLVM field boundary.
- unsigned FieldByteOffset;
+ CharUnits FieldByteOffset;
/// Bit offset in the accessed value to use. The width is implied by \see
/// TargetBitWidth.
@@ -68,7 +69,7 @@ public:
// FIXME: Remove use of 0 to encode default, instead have IRgen do the right
// thing when it generates the code, if avoiding align directives is
// desired.
- unsigned AccessAlignment;
+ CharUnits AccessAlignment;
/// Offset for the target value.
unsigned TargetBitOffset;
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index ceae66f3849e..a4ac390dd98c 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -34,7 +34,7 @@ class CGRecordLayoutBuilder {
public:
/// FieldTypes - Holds the LLVM types that the struct is created from.
///
- std::vector<const llvm::Type *> FieldTypes;
+ llvm::SmallVector<const llvm::Type *, 16> FieldTypes;
/// BaseSubobjectType - Holds the LLVM type for the non-virtual part
/// of the struct. For example, consider:
@@ -77,13 +77,26 @@ public:
/// Packed - Whether the resulting LLVM struct will be packed or not.
bool Packed;
+
+ /// IsMsStruct - Whether ms_struct is in effect or not
+ bool IsMsStruct;
private:
CodeGenTypes &Types;
+ /// LastLaidOutBaseInfo - Contains the offset and non-virtual size of the
+ /// last base laid out. Used so that we can replace the last laid out base
+ /// type with an i8 array if needed.
+ struct LastLaidOutBaseInfo {
+ CharUnits Offset;
+ CharUnits NonVirtualSize;
+
+ bool isValid() const { return !NonVirtualSize.isZero(); }
+ void invalidate() { NonVirtualSize = CharUnits::Zero(); }
+
+ } LastLaidOutBase;
+
/// Alignment - Contains the alignment of the RecordDecl.
- //
- // FIXME: This is not needed and should be removed.
CharUnits Alignment;
/// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
@@ -143,6 +156,12 @@ private:
/// struct size is a multiple of the field alignment.
void AppendPadding(CharUnits fieldOffset, CharUnits fieldAlignment);
+ /// ResizeLastBaseFieldIfNecessary - Fields and bases can be laid out in the
+ /// tail padding of a previous base. If this happens, the type of the previous
+ /// base needs to be changed to an array of i8. Returns true if the last
+ /// laid out base was resized.
+ bool ResizeLastBaseFieldIfNecessary(CharUnits offset);
+
/// getByteArrayType - Returns a byte array type with the given number of
/// elements.
const llvm::Type *getByteArrayType(CharUnits NumBytes);
@@ -152,7 +171,7 @@ private:
/// AppendTailPadding - Append enough tail padding so that the type will have
/// the passed size.
- void AppendTailPadding(uint64_t RecordSize);
+ void AppendTailPadding(CharUnits RecordSize);
CharUnits getTypeAlignment(const llvm::Type *Ty) const;
@@ -168,7 +187,8 @@ public:
CGRecordLayoutBuilder(CodeGenTypes &Types)
: BaseSubobjectType(0),
IsZeroInitializable(true), IsZeroInitializableAsBase(true),
- Packed(false), Types(Types), BitsAvailableInLastField(0) { }
+ Packed(false), IsMsStruct(false),
+ Types(Types), BitsAvailableInLastField(0) { }
/// Layout - Will layout a RecordDecl.
void Layout(const RecordDecl *D);
@@ -179,6 +199,8 @@ public:
void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Alignment = Types.getContext().getASTRecordLayout(D).getAlignment();
Packed = D->hasAttr<PackedAttr>();
+
+ IsMsStruct = D->hasAttr<MsStructAttr>();
if (D->isUnion()) {
LayoutUnion(D);
@@ -190,6 +212,7 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
// We weren't able to layout the struct. Try again with a packed struct
Packed = true;
+ LastLaidOutBase.invalidate();
NextFieldOffset = CharUnits::Zero();
FieldTypes.clear();
Fields.clear();
@@ -242,7 +265,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!");
CGBitFieldInfo::AccessInfo Components[3];
unsigned NumComponents = 0;
- unsigned AccessedTargetBits = 0; // The tumber of target bits accessed.
+ unsigned AccessedTargetBits = 0; // The number of target bits accessed.
unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt.
// Round down from the field offset to find the first access position that is
@@ -292,13 +315,15 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
// 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()) {
- AI.FieldByteOffset = (ContainingTypeSizeInBits - AccessStart - AccessWidth )/8;
+ AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(
+ ContainingTypeSizeInBits - AccessStart - AccessWidth);
} else {
- AI.FieldByteOffset = AccessStart / 8;
+ AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(AccessStart);
}
AI.FieldBitStart = AccessBitsInFieldStart - AccessStart;
AI.AccessWidth = AccessWidth;
- AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8;
+ AI.AccessAlignment = Types.getContext().toCharUnitsFromBits(
+ llvm::MinAlign(ContainingTypeAlign, AccessStart));
AI.TargetBitOffset = AccessedTargetBits;
AI.TargetBitWidth = AccessBitsInFieldSize;
@@ -332,34 +357,51 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
return;
uint64_t nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
- unsigned numBytesToAppend;
+ CharUnits numBytesToAppend;
+ unsigned charAlign = Types.getContext().Target.getCharAlign();
+
+ if (fieldOffset < nextFieldOffsetInBits && !BitsAvailableInLastField) {
+ assert(fieldOffset % charAlign == 0 &&
+ "Field offset not aligned correctly");
+
+ CharUnits fieldOffsetInCharUnits =
+ Types.getContext().toCharUnitsFromBits(fieldOffset);
+
+ // Try to resize the last base field.
+ if (ResizeLastBaseFieldIfNecessary(fieldOffsetInCharUnits))
+ nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
+ }
if (fieldOffset < nextFieldOffsetInBits) {
assert(BitsAvailableInLastField && "Bitfield size mismatch!");
assert(!NextFieldOffset.isZero() && "Must have laid out at least one byte");
// The bitfield begins in the previous bit-field.
- numBytesToAppend =
- llvm::RoundUpToAlignment(fieldSize - BitsAvailableInLastField, 8) / 8;
+ numBytesToAppend = Types.getContext().toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(fieldSize - BitsAvailableInLastField,
+ charAlign));
} else {
- assert(fieldOffset % 8 == 0 && "Field offset not aligned correctly");
+ assert(fieldOffset % charAlign == 0 &&
+ "Field offset not aligned correctly");
// Append padding if necessary.
- AppendPadding(CharUnits::fromQuantity(fieldOffset / 8), CharUnits::One());
+ AppendPadding(Types.getContext().toCharUnitsFromBits(fieldOffset),
+ CharUnits::One());
- numBytesToAppend = llvm::RoundUpToAlignment(fieldSize, 8) / 8;
+ numBytesToAppend = Types.getContext().toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(fieldSize, charAlign));
- assert(numBytesToAppend && "No bytes to append!");
+ assert(!numBytesToAppend.isZero() && "No bytes to append!");
}
// Add the bit field info.
BitFields.insert(std::make_pair(D,
CGBitFieldInfo::MakeInfo(Types, D, fieldOffset, fieldSize)));
- AppendBytes(CharUnits::fromQuantity(numBytesToAppend));
+ AppendBytes(numBytesToAppend);
BitsAvailableInLastField =
- NextFieldOffset.getQuantity() * 8 - (fieldOffset + fieldSize);
+ Types.getContext().toBits(NextFieldOffset) - (fieldOffset + fieldSize);
}
bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
@@ -411,6 +453,14 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
NextFieldOffset.RoundUpToAlignment(typeAlignment);
if (fieldOffsetInBytes < alignedNextFieldOffsetInBytes) {
+ // Try to resize the last base field.
+ if (ResizeLastBaseFieldIfNecessary(fieldOffsetInBytes)) {
+ alignedNextFieldOffsetInBytes =
+ NextFieldOffset.RoundUpToAlignment(typeAlignment);
+ }
+ }
+
+ if (fieldOffsetInBytes < alignedNextFieldOffsetInBytes) {
assert(!Packed && "Could not place field even with packed struct!");
return false;
}
@@ -421,6 +471,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
Fields[D] = FieldTypes.size();
AppendField(fieldOffsetInBytes, Ty);
+ LastLaidOutBase.invalidate();
return true;
}
@@ -436,11 +487,12 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
return 0;
const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
- unsigned NumBytesToAppend =
- llvm::RoundUpToAlignment(FieldSize, 8) / 8;
+ CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(FieldSize,
+ Types.getContext().Target.getCharAlign()));
- if (NumBytesToAppend > 1)
- FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend);
+ if (NumBytesToAppend > CharUnits::One())
+ FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend.getQuantity());
// Add the bit field info.
BitFields.insert(std::make_pair(Field,
@@ -516,11 +568,16 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
const CGRecordLayout &baseLayout,
CharUnits baseOffset) {
+ ResizeLastBaseFieldIfNecessary(baseOffset);
+
AppendPadding(baseOffset, CharUnits::One());
const ASTRecordLayout &baseASTLayout
= Types.getContext().getASTRecordLayout(base);
+ LastLaidOutBase.Offset = NextFieldOffset;
+ LastLaidOutBase.NonVirtualSize = baseASTLayout.getNonVirtualSize();
+
// Fields and bases can be laid out in the tail padding of previous
// bases. If this happens, we need to allocate the base as an i8
// array; otherwise, we can use the subobject type. However,
@@ -529,20 +586,10 @@ void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
// approximation, which is to use the base subobject type if it
// has the same LLVM storage size as the nvsize.
- // The nvsize, i.e. the unpadded size of the base class.
- CharUnits nvsize = baseASTLayout.getNonVirtualSize();
-
-#if 0
const llvm::StructType *subobjectType = baseLayout.getBaseSubobjectLLVMType();
- const llvm::StructLayout *baseLLVMLayout =
- Types.getTargetData().getStructLayout(subobjectType);
- CharUnits stsize = CharUnits::fromQuantity(baseLLVMLayout->getSizeInBytes());
+ AppendField(baseOffset, subobjectType);
- if (nvsize == stsize)
- AppendField(baseOffset, subobjectType);
- else
-#endif
- AppendBytes(nvsize);
+ Types.addBaseSubobjectTypeName(base, baseLayout);
}
void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
@@ -698,9 +745,22 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
LayoutNonVirtualBases(RD, Layout);
unsigned FieldNo = 0;
-
+ const FieldDecl *LastFD = 0;
+
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are
+ // ignored:
+ const FieldDecl *FD = (*Field);
+ if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) ||
+ Types.getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ --FieldNo;
+ continue;
+ }
+ LastFD = FD;
+ }
+
if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) {
assert(!Packed &&
"Could not layout fields even with a packed LLVM struct!");
@@ -724,27 +784,25 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
}
// Append tail padding if necessary.
- AppendTailPadding(Types.getContext().toBits(Layout.getSize()));
+ AppendTailPadding(Layout.getSize());
return true;
}
-void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
- assert(RecordSize % 8 == 0 && "Invalid record size!");
+void CGRecordLayoutBuilder::AppendTailPadding(CharUnits RecordSize) {
+ ResizeLastBaseFieldIfNecessary(RecordSize);
- CharUnits RecordSizeInBytes =
- Types.getContext().toCharUnitsFromBits(RecordSize);
- assert(NextFieldOffset <= RecordSizeInBytes && "Size mismatch!");
+ assert(NextFieldOffset <= RecordSize && "Size mismatch!");
CharUnits AlignedNextFieldOffset =
NextFieldOffset.RoundUpToAlignment(getAlignmentAsLLVMStruct());
- if (AlignedNextFieldOffset == RecordSizeInBytes) {
+ if (AlignedNextFieldOffset == RecordSize) {
// We don't need any padding.
return;
}
- CharUnits NumPadBytes = RecordSizeInBytes - NextFieldOffset;
+ CharUnits NumPadBytes = RecordSize - NextFieldOffset;
AppendBytes(NumPadBytes);
}
@@ -777,6 +835,24 @@ void CGRecordLayoutBuilder::AppendPadding(CharUnits fieldOffset,
}
}
+bool CGRecordLayoutBuilder::ResizeLastBaseFieldIfNecessary(CharUnits offset) {
+ // Check if we have a base to resize.
+ if (!LastLaidOutBase.isValid())
+ return false;
+
+ // This offset does not overlap with the tail padding.
+ if (offset >= NextFieldOffset)
+ return false;
+
+ // Restore the field offset and append an i8 array instead.
+ FieldTypes.pop_back();
+ NextFieldOffset = LastLaidOutBase.Offset;
+ AppendBytes(LastLaidOutBase.NonVirtualSize);
+ LastLaidOutBase.invalidate();
+
+ return true;
+}
+
const llvm::Type *CGRecordLayoutBuilder::getByteArrayType(CharUnits numBytes) {
assert(!numBytes.isZero() && "Empty byte arrays aren't allowed.");
@@ -903,6 +979,8 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D);
RecordDecl::field_iterator it = D->field_begin();
+ const FieldDecl *LastFD = 0;
+ bool IsMsStruct = D->hasAttr<MsStructAttr>();
for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
const FieldDecl *FD = *it;
@@ -912,13 +990,27 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
unsigned FieldNo = RL->getLLVMFieldNo(FD);
assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) &&
"Invalid field offset!");
+ LastFD = FD;
continue;
}
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are
+ // ignored:
+ if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) ||
+ getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ --i;
+ continue;
+ }
+ LastFD = FD;
+ }
+
// Ignore unnamed bit-fields.
- if (!FD->getDeclName())
+ if (!FD->getDeclName()) {
+ LastFD = FD;
continue;
-
+ }
+
const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD);
for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
@@ -926,7 +1018,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
// Verify that every component access is within the structure.
uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex);
uint64_t AccessBitOffset = FieldOffset +
- getContext().toBits(CharUnits::fromQuantity(AI.FieldByteOffset));
+ getContext().toBits(AI.FieldByteOffset);
assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits &&
"Invalid bit-field access (out of range)!");
}
@@ -985,11 +1077,11 @@ void CGBitFieldInfo::print(llvm::raw_ostream &OS) const {
OS.indent(8);
OS << "<AccessInfo"
<< " FieldIndex:" << AI.FieldIndex
- << " FieldByteOffset:" << AI.FieldByteOffset
+ << " FieldByteOffset:" << AI.FieldByteOffset.getQuantity()
<< " FieldBitStart:" << AI.FieldBitStart
<< " AccessWidth:" << AI.AccessWidth << "\n";
OS.indent(8 + strlen("<AccessInfo"));
- OS << " AccessAlignment:" << AI.AccessAlignment
+ OS << " AccessAlignment:" << AI.AccessAlignment.getQuantity()
<< " TargetBitOffset:" << AI.TargetBitOffset
<< " TargetBitWidth:" << AI.TargetBitWidth
<< ">\n";
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index cd238112ed1d..99bc3f49ce92 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -72,6 +72,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
switch (S->getStmtClass()) {
case Stmt::NoStmtClass:
case Stmt::CXXCatchStmtClass:
+ case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHFinallyStmtClass:
llvm_unreachable("invalid statement class to emit generically");
case Stmt::NullStmtClass:
case Stmt::CompoundStmtClass:
@@ -153,6 +155,11 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::CXXTryStmtClass:
EmitCXXTryStmt(cast<CXXTryStmt>(*S));
break;
+ case Stmt::CXXForRangeStmtClass:
+ EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S));
+ case Stmt::SEHTryStmtClass:
+ // FIXME Not yet implemented
+ break;
}
}
@@ -359,10 +366,12 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// If the condition constant folds and can be elided, try to avoid emitting
// the condition and the dead arm of the if/else.
- if (int Cond = ConstantFoldsToSimpleInteger(S.getCond())) {
+ bool CondConstant;
+ if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant)) {
// Figure out which block (then or else) is executed.
- const Stmt *Executed = S.getThen(), *Skipped = S.getElse();
- if (Cond == -1) // Condition false?
+ const Stmt *Executed = S.getThen();
+ const Stmt *Skipped = S.getElse();
+ if (!CondConstant) // Condition false?
std::swap(Executed, Skipped);
// If the skipped block has no labels in it, just emit the executed block.
@@ -395,11 +404,17 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// Emit the 'else' code if present.
if (const Stmt *Else = S.getElse()) {
+ // There is no need to emit line number for unconditional branch.
+ if (getDebugInfo())
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
EmitBlock(ElseBlock);
{
RunCleanupsScope ElseScope(*this);
EmitStmt(Else);
}
+ // There is no need to emit line number for unconditional branch.
+ if (getDebugInfo())
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
EmitBranch(ContBlock);
}
@@ -628,6 +643,80 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
EmitBlock(LoopExit.getBlock(), true);
}
+void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
+ JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
+
+ RunCleanupsScope ForScope(*this);
+
+ CGDebugInfo *DI = getDebugInfo();
+ if (DI) {
+ DI->setLocation(S.getSourceRange().getBegin());
+ DI->EmitRegionStart(Builder);
+ }
+
+ // Evaluate the first pieces before the loop.
+ EmitStmt(S.getRangeStmt());
+ EmitStmt(S.getBeginEndStmt());
+
+ // Start the loop with a block that tests the condition.
+ // If there's an increment, the continue scope will be overwritten
+ // later.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ EmitBlock(CondBlock);
+
+ // If there are any cleanups between here and the loop-exit scope,
+ // create a block to stage a loop exit along.
+ llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
+ if (ForScope.requiresCleanups())
+ ExitBlock = createBasicBlock("for.cond.cleanup");
+
+ // The loop body, consisting of the specified body and the loop variable.
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+
+ // The body is executed if the expression, contextually converted
+ // to bool, is true.
+ llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+ Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock);
+
+ if (ExitBlock != LoopExit.getBlock()) {
+ EmitBlock(ExitBlock);
+ EmitBranchThroughCleanup(LoopExit);
+ }
+
+ EmitBlock(ForBody);
+
+ // Create a block for the increment. In case of a 'continue', we jump there.
+ JumpDest Continue = getJumpDestInCurrentScope("for.inc");
+
+ // Store the blocks to use for break and continue.
+ BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
+
+ {
+ // Create a separate cleanup scope for the loop variable and body.
+ RunCleanupsScope BodyScope(*this);
+ EmitStmt(S.getLoopVarStmt());
+ EmitStmt(S.getBody());
+ }
+
+ // If there is an increment, emit it next.
+ EmitBlock(Continue.getBlock());
+ EmitStmt(S.getInc());
+
+ BreakContinueStack.pop_back();
+
+ EmitBranch(CondBlock);
+
+ ForScope.ForceCleanup();
+
+ if (DI) {
+ DI->setLocation(S.getSourceRange().getEnd());
+ DI->EmitRegionEnd(Builder);
+ }
+
+ // Emit the fall-through block.
+ EmitBlock(LoopExit.getBlock(), true);
+}
+
void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
if (RV.isScalar()) {
Builder.CreateStore(RV.getScalarVal(), ReturnValue);
@@ -745,8 +834,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
// Range is small enough to add multiple switch instruction cases.
for (unsigned i = 0, e = Range.getZExtValue() + 1; i != e; ++i) {
- SwitchInsn->addCase(llvm::ConstantInt::get(getLLVMContext(), LHS),
- CaseDest);
+ SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
LHS++;
}
return;
@@ -767,11 +855,9 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
// Emit range check.
llvm::Value *Diff =
- Builder.CreateSub(SwitchInsn->getCondition(),
- llvm::ConstantInt::get(getLLVMContext(), LHS), "tmp");
+ Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS), "tmp");
llvm::Value *Cond =
- Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(getLLVMContext(), Range),
- "inbounds");
+ Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds");
Builder.CreateCondBr(Cond, CaseDest, FalseDest);
// Restore the appropriate insertion point.
@@ -782,16 +868,37 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
}
void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
+ // Handle case ranges.
if (S.getRHS()) {
EmitCaseStmtRange(S);
return;
}
+ llvm::ConstantInt *CaseVal =
+ Builder.getInt(S.getLHS()->EvaluateAsInt(getContext()));
+
+ // If the body of the case is just a 'break', and if there was no fallthrough,
+ // try to not emit an empty block.
+ if (isa<BreakStmt>(S.getSubStmt())) {
+ JumpDest Block = BreakContinueStack.back().BreakBlock;
+
+ // Only do this optimization if there are no cleanups that need emitting.
+ if (isObviouslyBranchWithoutCleanups(Block)) {
+ SwitchInsn->addCase(CaseVal, Block.getBlock());
+
+ // If there was a fallthrough into this case, make sure to redirect it to
+ // the end of the switch as well.
+ if (Builder.GetInsertBlock()) {
+ Builder.CreateBr(Block.getBlock());
+ Builder.ClearInsertionPoint();
+ }
+ return;
+ }
+ }
+
EmitBlock(createBasicBlock("sw.bb"));
llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
- llvm::APSInt CaseVal = S.getLHS()->EvaluateAsInt(getContext());
- SwitchInsn->addCase(llvm::ConstantInt::get(getLLVMContext(), CaseVal),
- CaseDest);
+ SwitchInsn->addCase(CaseVal, CaseDest);
// Recursively emitting the statement is acceptable, but is not wonderful for
// code where we have many case statements nested together, i.e.:
@@ -805,13 +912,12 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
const CaseStmt *CurCase = &S;
const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt());
- // Otherwise, iteratively add consequtive cases to this switch stmt.
+ // Otherwise, iteratively add consecutive cases to this switch stmt.
while (NextCase && NextCase->getRHS() == 0) {
CurCase = NextCase;
- CaseVal = CurCase->getLHS()->EvaluateAsInt(getContext());
- SwitchInsn->addCase(llvm::ConstantInt::get(getLLVMContext(), CaseVal),
- CaseDest);
-
+ llvm::ConstantInt *CaseVal =
+ Builder.getInt(CurCase->getLHS()->EvaluateAsInt(getContext()));
+ SwitchInsn->addCase(CaseVal, CaseDest);
NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
}
@@ -827,6 +933,207 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {
EmitStmt(S.getSubStmt());
}
+/// CollectStatementsForCase - Given the body of a 'switch' statement and a
+/// constant value that is being switched on, see if we can dead code eliminate
+/// the body of the switch to a simple series of statements to emit. Basically,
+/// on a switch (5) we want to find these statements:
+/// case 5:
+/// printf(...); <--
+/// ++i; <--
+/// break;
+///
+/// and add them to the ResultStmts vector. If it is unsafe to do this
+/// transformation (for example, one of the elided statements contains a label
+/// that might be jumped to), return CSFC_Failure. If we handled it and 'S'
+/// should include statements after it (e.g. the printf() line is a substmt of
+/// the case) then return CSFC_FallThrough. If we handled it and found a break
+/// statement, then return CSFC_Success.
+///
+/// If Case is non-null, then we are looking for the specified case, checking
+/// that nothing we jump over contains labels. If Case is null, then we found
+/// the case and are looking for the break.
+///
+/// If the recursive walk actually finds our Case, then we set FoundCase to
+/// true.
+///
+enum CSFC_Result { CSFC_Failure, CSFC_FallThrough, CSFC_Success };
+static CSFC_Result CollectStatementsForCase(const Stmt *S,
+ const SwitchCase *Case,
+ bool &FoundCase,
+ llvm::SmallVectorImpl<const Stmt*> &ResultStmts) {
+ // If this is a null statement, just succeed.
+ if (S == 0)
+ return Case ? CSFC_Success : CSFC_FallThrough;
+
+ // If this is the switchcase (case 4: or default) that we're looking for, then
+ // we're in business. Just add the substatement.
+ if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) {
+ if (S == Case) {
+ FoundCase = true;
+ return CollectStatementsForCase(SC->getSubStmt(), 0, FoundCase,
+ ResultStmts);
+ }
+
+ // Otherwise, this is some other case or default statement, just ignore it.
+ return CollectStatementsForCase(SC->getSubStmt(), Case, FoundCase,
+ ResultStmts);
+ }
+
+ // If we are in the live part of the code and we found our break statement,
+ // return a success!
+ if (Case == 0 && isa<BreakStmt>(S))
+ return CSFC_Success;
+
+ // If this is a switch statement, then it might contain the SwitchCase, the
+ // break, or neither.
+ if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
+ // Handle this as two cases: we might be looking for the SwitchCase (if so
+ // the skipped statements must be skippable) or we might already have it.
+ CompoundStmt::const_body_iterator I = CS->body_begin(), E = CS->body_end();
+ if (Case) {
+ // Keep track of whether we see a skipped declaration. The code could be
+ // using the declaration even if it is skipped, so we can't optimize out
+ // the decl if the kept statements might refer to it.
+ bool HadSkippedDecl = false;
+
+ // If we're looking for the case, just see if we can skip each of the
+ // substatements.
+ for (; Case && I != E; ++I) {
+ HadSkippedDecl |= isa<DeclStmt>(I);
+
+ switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) {
+ case CSFC_Failure: return CSFC_Failure;
+ case CSFC_Success:
+ // A successful result means that either 1) that the statement doesn't
+ // have the case and is skippable, or 2) does contain the case value
+ // and also contains the break to exit the switch. In the later case,
+ // we just verify the rest of the statements are elidable.
+ if (FoundCase) {
+ // If we found the case and skipped declarations, we can't do the
+ // optimization.
+ if (HadSkippedDecl)
+ return CSFC_Failure;
+
+ for (++I; I != E; ++I)
+ if (CodeGenFunction::ContainsLabel(*I, true))
+ return CSFC_Failure;
+ return CSFC_Success;
+ }
+ break;
+ case CSFC_FallThrough:
+ // If we have a fallthrough condition, then we must have found the
+ // case started to include statements. Consider the rest of the
+ // statements in the compound statement as candidates for inclusion.
+ assert(FoundCase && "Didn't find case but returned fallthrough?");
+ // We recursively found Case, so we're not looking for it anymore.
+ Case = 0;
+
+ // If we found the case and skipped declarations, we can't do the
+ // optimization.
+ if (HadSkippedDecl)
+ return CSFC_Failure;
+ break;
+ }
+ }
+ }
+
+ // If we have statements in our range, then we know that the statements are
+ // live and need to be added to the set of statements we're tracking.
+ for (; I != E; ++I) {
+ switch (CollectStatementsForCase(*I, 0, FoundCase, ResultStmts)) {
+ case CSFC_Failure: return CSFC_Failure;
+ case CSFC_FallThrough:
+ // A fallthrough result means that the statement was simple and just
+ // included in ResultStmt, keep adding them afterwards.
+ break;
+ case CSFC_Success:
+ // A successful result means that we found the break statement and
+ // stopped statement inclusion. We just ensure that any leftover stmts
+ // are skippable and return success ourselves.
+ for (++I; I != E; ++I)
+ if (CodeGenFunction::ContainsLabel(*I, true))
+ return CSFC_Failure;
+ return CSFC_Success;
+ }
+ }
+
+ return Case ? CSFC_Success : CSFC_FallThrough;
+ }
+
+ // Okay, this is some other statement that we don't handle explicitly, like a
+ // for statement or increment etc. If we are skipping over this statement,
+ // just verify it doesn't have labels, which would make it invalid to elide.
+ if (Case) {
+ if (CodeGenFunction::ContainsLabel(S, true))
+ return CSFC_Failure;
+ return CSFC_Success;
+ }
+
+ // Otherwise, we want to include this statement. Everything is cool with that
+ // so long as it doesn't contain a break out of the switch we're in.
+ if (CodeGenFunction::containsBreak(S)) return CSFC_Failure;
+
+ // Otherwise, everything is great. Include the statement and tell the caller
+ // that we fall through and include the next statement as well.
+ ResultStmts.push_back(S);
+ return CSFC_FallThrough;
+}
+
+/// FindCaseStatementsForValue - Find the case statement being jumped to and
+/// then invoke CollectStatementsForCase to find the list of statements to emit
+/// for a switch on constant. See the comment above CollectStatementsForCase
+/// for more details.
+static bool FindCaseStatementsForValue(const SwitchStmt &S,
+ const llvm::APInt &ConstantCondValue,
+ llvm::SmallVectorImpl<const Stmt*> &ResultStmts,
+ ASTContext &C) {
+ // First step, find the switch case that is being branched to. We can do this
+ // efficiently by scanning the SwitchCase list.
+ const SwitchCase *Case = S.getSwitchCaseList();
+ const DefaultStmt *DefaultCase = 0;
+
+ for (; Case; Case = Case->getNextSwitchCase()) {
+ // It's either a default or case. Just remember the default statement in
+ // case we're not jumping to any numbered cases.
+ if (const DefaultStmt *DS = dyn_cast<DefaultStmt>(Case)) {
+ DefaultCase = DS;
+ continue;
+ }
+
+ // Check to see if this case is the one we're looking for.
+ const CaseStmt *CS = cast<CaseStmt>(Case);
+ // Don't handle case ranges yet.
+ if (CS->getRHS()) return false;
+
+ // If we found our case, remember it as 'case'.
+ if (CS->getLHS()->EvaluateAsInt(C) == ConstantCondValue)
+ break;
+ }
+
+ // If we didn't find a matching case, we use a default if it exists, or we
+ // elide the whole switch body!
+ if (Case == 0) {
+ // It is safe to elide the body of the switch if it doesn't contain labels
+ // etc. If it is safe, return successfully with an empty ResultStmts list.
+ if (DefaultCase == 0)
+ return !CodeGenFunction::ContainsLabel(&S);
+ Case = DefaultCase;
+ }
+
+ // Ok, we know which case is being jumped to, try to collect all the
+ // statements that follow it. This can fail for a variety of reasons. Also,
+ // check to see that the recursive walk actually found our case statement.
+ // Insane cases like this can fail to find it in the recursive walk since we
+ // don't handle every stmt kind:
+ // switch (4) {
+ // while (1) {
+ // case 4: ...
+ bool FoundCase = false;
+ return CollectStatementsForCase(S.getBody(), Case, FoundCase,
+ ResultStmts) != CSFC_Failure &&
+ FoundCase;
+}
+
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
@@ -835,6 +1142,23 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
if (S.getConditionVariable())
EmitAutoVarDecl(*S.getConditionVariable());
+ // See if we can constant fold the condition of the switch and therefore only
+ // emit the live case statement (if any) of the switch.
+ llvm::APInt ConstantCondValue;
+ if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) {
+ llvm::SmallVector<const Stmt*, 4> CaseStmts;
+ if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts,
+ getContext())) {
+ RunCleanupsScope ExecutedScope(*this);
+
+ // Okay, we can dead code eliminate everything except this case. Emit the
+ // specified series of statements and we're good.
+ for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i)
+ EmitStmt(CaseStmts[i]);
+ return;
+ }
+ }
+
llvm::Value *CondV = EmitScalarExpr(S.getCond());
// Handle nested switch statements.
@@ -1031,7 +1355,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
}
}
- return llvm::MDNode::get(CGF.getLLVMContext(), Locs.data(), Locs.size());
+ return llvm::MDNode::get(CGF.getLLVMContext(), Locs);
}
void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 78b2dbe2ba22..a6849f8f3d21 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -53,6 +53,10 @@ class VTTBuilder {
/// GenerateDefinition - Whether the VTT builder should generate LLVM IR for
/// the VTT.
bool GenerateDefinition;
+
+ /// The linkage to use for any construction vtables required by this VTT.
+ /// Only required if we're building a definition.
+ llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables;
/// GetAddrOfVTable - Returns the address of the vtable for the base class in
/// the given vtable class.
@@ -109,7 +113,9 @@ class VTTBuilder {
public:
VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass,
- bool GenerateDefinition);
+ bool GenerateDefinition,
+ llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables
+ = (llvm::GlobalVariable::LinkageTypes) -1);
// getVTTComponents - Returns a reference to the VTT components.
const VTTComponentsVectorTy &getVTTComponents() const {
@@ -132,13 +138,19 @@ public:
VTTBuilder::VTTBuilder(CodeGenModule &CGM,
const CXXRecordDecl *MostDerivedClass,
- bool GenerateDefinition)
+ bool GenerateDefinition,
+ llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables)
: CGM(CGM), MostDerivedClass(MostDerivedClass),
MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)),
- GenerateDefinition(GenerateDefinition) {
+ GenerateDefinition(GenerateDefinition),
+ LinkageForConstructionVTables(LinkageForConstructionVTables) {
+ assert(!GenerateDefinition ||
+ LinkageForConstructionVTables
+ != (llvm::GlobalVariable::LinkageTypes) -1);
// Lay out this VTT.
- LayoutVTT(BaseSubobject(MostDerivedClass, 0), /*BaseIsVirtual=*/false);
+ LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
+ /*BaseIsVirtual=*/false);
}
llvm::Constant *
@@ -148,7 +160,7 @@ VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
return 0;
if (Base.getBase() == MostDerivedClass) {
- assert(Base.getBaseOffset() == 0 &&
+ assert(Base.getBaseOffset().isZero() &&
"Most derived class vtable must have a zero offset!");
// This is a regular vtable.
return CGM.getVTables().GetAddrOfVTable(MostDerivedClass);
@@ -156,6 +168,7 @@ VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass,
Base, BaseIsVirtual,
+ LinkageForConstructionVTables,
AddressPoints);
}
@@ -217,8 +230,8 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- uint64_t BaseOffset = Base.getBaseOffset() +
- Layout.getBaseClassOffsetInBits(BaseDecl);
+ CharUnits BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
// Layout the VTT for this base.
LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
@@ -256,19 +269,19 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
bool BaseDeclIsNonVirtualPrimaryBase = false;
- uint64_t BaseOffset;
+ CharUnits BaseOffset;
if (I->isVirtual()) {
// Ignore virtual bases that we've already visited.
if (!VBases.insert(BaseDecl))
continue;
- BaseOffset = MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl);
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
BaseDeclIsMorallyVirtual = true;
} else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- BaseOffset =
- Base.getBaseOffset() + Layout.getBaseClassOffsetInBits(BaseDecl);
+ BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
if (!Layout.isPrimaryBaseVirtual() &&
Layout.getPrimaryBase() == BaseDecl)
@@ -283,8 +296,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
if (!BaseDeclIsNonVirtualPrimaryBase &&
(BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
// Add the vtable pointer.
- AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, VTableClass,
- AddressPoints);
+ AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable,
+ VTableClass, AddressPoints);
}
// And lay out the secondary virtual pointers for the base class.
@@ -316,8 +329,8 @@ void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
if (!VBases.insert(BaseDecl))
continue;
- uint64_t BaseOffset =
- MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl);
+ CharUnits BaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
}
@@ -370,7 +383,7 @@ void
CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
- VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/true);
+ VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/true, Linkage);
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
const llvm::ArrayType *ArrayType =
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 891697f4cd09..581467c53751 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -43,15 +43,16 @@ struct BaseOffset {
/// (Or the offset from the virtual base class to the base class, if the
/// path from the derived class to the base class involves a virtual base
/// class.
- int64_t NonVirtualOffset;
+ CharUnits NonVirtualOffset;
- BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { }
+ BaseOffset() : DerivedClass(0), VirtualBase(0),
+ NonVirtualOffset(CharUnits::Zero()) { }
BaseOffset(const CXXRecordDecl *DerivedClass,
- const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset)
+ const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset)
: DerivedClass(DerivedClass), VirtualBase(VirtualBase),
NonVirtualOffset(NonVirtualOffset) { }
- bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; }
+ bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; }
};
/// FinalOverriders - Contains the final overrider member functions for all
@@ -64,9 +65,9 @@ public:
const CXXMethodDecl *Method;
/// Offset - the base offset of the overrider in the layout class.
- uint64_t Offset;
+ CharUnits Offset;
- OverriderInfo() : Method(0), Offset(0) { }
+ OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { }
};
private:
@@ -77,7 +78,7 @@ private:
/// MostDerivedClassOffset - If we're building final overriders for a
/// construction vtable, this holds the offset from the layout class to the
/// most derived class.
- const uint64_t MostDerivedClassOffset;
+ const CharUnits MostDerivedClassOffset;
/// LayoutClass - The class we're using for layout information. Will be
/// different than the most derived class if the final overriders are for a
@@ -91,7 +92,7 @@ private:
/// MethodBaseOffsetPairTy - Uniquely identifies a member function
/// in a base subobject.
- typedef std::pair<const CXXMethodDecl *, uint64_t> MethodBaseOffsetPairTy;
+ typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy;
typedef llvm::DenseMap<MethodBaseOffsetPairTy,
OverriderInfo> OverridersMapTy;
@@ -104,14 +105,14 @@ private:
/// as a record decl and a subobject number) and its offsets in the most
/// derived class as well as the layout class.
typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>,
- uint64_t> SubobjectOffsetMapTy;
+ CharUnits> SubobjectOffsetMapTy;
typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy;
/// ComputeBaseOffsets - Compute the offsets for all base subobjects of the
/// given base.
void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
- uint64_t OffsetInLayoutClass,
+ CharUnits OffsetInLayoutClass,
SubobjectOffsetMapTy &SubobjectOffsets,
SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
SubobjectCountMapTy &SubobjectCounts);
@@ -125,13 +126,13 @@ private:
public:
FinalOverriders(const CXXRecordDecl *MostDerivedClass,
- uint64_t MostDerivedClassOffset,
+ CharUnits MostDerivedClassOffset,
const CXXRecordDecl *LayoutClass);
/// getOverrider - Get the final overrider for the given method declaration in
/// the subobject with the given base offset.
OverriderInfo getOverrider(const CXXMethodDecl *MD,
- uint64_t BaseOffset) const {
+ CharUnits BaseOffset) const {
assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) &&
"Did not find overrider!");
@@ -141,7 +142,8 @@ public:
/// dump - dump the final overriders.
void dump() {
VisitedVirtualBasesSetTy VisitedVirtualBases;
- dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0), VisitedVirtualBases);
+ dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()),
+ VisitedVirtualBases);
}
};
@@ -149,7 +151,7 @@ public:
#define DUMP_OVERRIDERS 0
FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
- uint64_t MostDerivedClassOffset,
+ CharUnits MostDerivedClassOffset,
const CXXRecordDecl *LayoutClass)
: MostDerivedClass(MostDerivedClass),
MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
@@ -160,9 +162,11 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
SubobjectOffsetMapTy SubobjectOffsets;
SubobjectOffsetMapTy SubobjectLayoutClassOffsets;
SubobjectCountMapTy SubobjectCounts;
- ComputeBaseOffsets(BaseSubobject(MostDerivedClass, 0), /*IsVirtual=*/false,
- MostDerivedClassOffset, SubobjectOffsets,
- SubobjectLayoutClassOffsets, SubobjectCounts);
+ ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
+ /*IsVirtual=*/false,
+ MostDerivedClassOffset,
+ SubobjectOffsets, SubobjectLayoutClassOffsets,
+ SubobjectCounts);
// Get the the final overriders.
CXXFinalOverriderMap FinalOverriders;
@@ -180,7 +184,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
SubobjectNumber)) &&
"Did not find subobject offset!");
- uint64_t BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(),
+ CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(),
SubobjectNumber)];
assert(I->second.size() == 1 && "Final overrider is not unique!");
@@ -190,7 +194,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
assert(SubobjectLayoutClassOffsets.count(
std::make_pair(OverriderRD, Method.Subobject))
&& "Did not find subobject offset!");
- uint64_t OverriderOffset =
+ CharUnits OverriderOffset =
SubobjectLayoutClassOffsets[std::make_pair(OverriderRD,
Method.Subobject)];
@@ -211,7 +215,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
static BaseOffset ComputeBaseOffset(ASTContext &Context,
const CXXRecordDecl *DerivedRD,
const CXXBasePath &Path) {
- int64_t NonVirtualOffset = 0;
+ CharUnits NonVirtualOffset = CharUnits::Zero();
unsigned NonVirtualStart = 0;
const CXXRecordDecl *VirtualBase = 0;
@@ -240,13 +244,13 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
- NonVirtualOffset += Layout.getBaseClassOffsetInBits(Base);
+ NonVirtualOffset += Layout.getBaseClassOffset(Base);
}
// FIXME: This should probably use CharUnits or something. Maybe we should
// even change the base offsets in ASTRecordLayout to be specified in
// CharUnits.
- return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8);
+ return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset);
}
@@ -321,7 +325,7 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
void
FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
- uint64_t OffsetInLayoutClass,
+ CharUnits OffsetInLayoutClass,
SubobjectOffsetMapTy &SubobjectOffsets,
SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
SubobjectCountMapTy &SubobjectCounts) {
@@ -337,8 +341,7 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber))
&& "Subobject offset already exists!");
- SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] =
- Base.getBaseOffset();
+ SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset();
SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
OffsetInLayoutClass;
@@ -348,8 +351,8 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset;
- uint64_t BaseOffsetInLayoutClass;
+ CharUnits BaseOffset;
+ CharUnits BaseOffsetInLayoutClass;
if (I->isVirtual()) {
// Check if we've visited this virtual base before.
if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
@@ -358,20 +361,21 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
const ASTRecordLayout &LayoutClassLayout =
Context.getASTRecordLayout(LayoutClass);
- BaseOffset = MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl);
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
BaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl);
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl);
} else {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- uint64_t Offset = Layout.getBaseClassOffsetInBits(BaseDecl);
+ CharUnits Offset = Layout.getBaseClassOffset(BaseDecl);
BaseOffset = Base.getBaseOffset() + Offset;
BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset;
}
- ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset), I->isVirtual(),
- BaseOffsetInLayoutClass, SubobjectOffsets,
- SubobjectLayoutClassOffsets, SubobjectCounts);
+ ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset),
+ I->isVirtual(), BaseOffsetInLayoutClass,
+ SubobjectOffsets, SubobjectLayoutClassOffsets,
+ SubobjectCounts);
}
}
@@ -389,24 +393,23 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base,
if (!BaseDecl->isPolymorphic())
continue;
- uint64_t BaseOffset;
+ CharUnits BaseOffset;
if (I->isVirtual()) {
if (!VisitedVirtualBases.insert(BaseDecl)) {
// We've visited this base before.
continue;
}
- BaseOffset = MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl);
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
} else {
- BaseOffset = Layout.getBaseClassOffsetInBits(BaseDecl) +
- Base.getBaseOffset();
+ BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
}
dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases);
}
Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", ";
- Out << Base.getBaseOffset() / 8 << ")\n";
+ Out << Base.getBaseOffset().getQuantity() << ")\n";
// Now dump the overriders for this base subobject.
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
@@ -420,7 +423,7 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base,
Out << " " << MD->getQualifiedNameAsString() << " - (";
Out << Overrider.Method->getQualifiedNameAsString();
- Out << ", " << ", " << Overrider.Offset / 8 << ')';
+ Out << ", " << ", " << Overrider.Offset.getQuantity() << ')';
BaseOffset Offset;
if (!Overrider.Method->isPure())
@@ -431,7 +434,7 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base,
if (Offset.VirtualBase)
Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
- Out << Offset.NonVirtualOffset << " nv]";
+ Out << Offset.NonVirtualOffset.getQuantity() << " nv]";
}
Out << "\n";
@@ -460,15 +463,15 @@ public:
CK_UnusedFunctionPointer
};
- static VTableComponent MakeVCallOffset(int64_t Offset) {
+ static VTableComponent MakeVCallOffset(CharUnits Offset) {
return VTableComponent(CK_VCallOffset, Offset);
}
- static VTableComponent MakeVBaseOffset(int64_t Offset) {
+ static VTableComponent MakeVBaseOffset(CharUnits Offset) {
return VTableComponent(CK_VBaseOffset, Offset);
}
- static VTableComponent MakeOffsetToTop(int64_t Offset) {
+ static VTableComponent MakeOffsetToTop(CharUnits Offset) {
return VTableComponent(CK_OffsetToTop, Offset);
}
@@ -510,19 +513,19 @@ public:
return (Kind)(Value & 0x7);
}
- int64_t getVCallOffset() const {
+ CharUnits getVCallOffset() const {
assert(getKind() == CK_VCallOffset && "Invalid component kind!");
return getOffset();
}
- int64_t getVBaseOffset() const {
+ CharUnits getVBaseOffset() const {
assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
return getOffset();
}
- int64_t getOffsetToTop() const {
+ CharUnits getOffsetToTop() const {
assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
return getOffset();
@@ -554,13 +557,13 @@ public:
}
private:
- VTableComponent(Kind ComponentKind, int64_t Offset) {
+ VTableComponent(Kind ComponentKind, CharUnits Offset) {
assert((ComponentKind == CK_VCallOffset ||
ComponentKind == CK_VBaseOffset ||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
- assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!");
+ assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
- Value = ((Offset << 3) | ComponentKind);
+ Value = ((Offset.getQuantity() << 3) | ComponentKind);
}
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
@@ -576,11 +579,11 @@ private:
Value = Ptr | ComponentKind;
}
- int64_t getOffset() const {
+ CharUnits getOffset() const {
assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
getKind() == CK_OffsetToTop) && "Invalid component kind!");
- return Value >> 3;
+ return CharUnits::fromQuantity(Value >> 3);
}
uintptr_t getPointer() const {
@@ -608,7 +611,7 @@ private:
/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable.
struct VCallOffsetMap {
- typedef std::pair<const CXXMethodDecl *, int64_t> MethodAndOffsetPairTy;
+ typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
/// Offsets - Keeps track of methods and their offsets.
// FIXME: This should be a real map and not a vector.
@@ -623,11 +626,11 @@ public:
/// AddVCallOffset - Adds a vcall offset to the map. Returns true if the
/// add was successful, or false if there was already a member function with
/// the same signature in the map.
- bool AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset);
+ bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset);
/// getVCallOffsetOffset - Returns the vcall offset offset (relative to the
/// vtable address point) for the given virtual member function.
- int64_t getVCallOffsetOffset(const CXXMethodDecl *MD);
+ CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD);
// empty - Return whether the offset map is empty or not.
bool empty() const { return Offsets.empty(); }
@@ -677,7 +680,7 @@ bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
}
bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD,
- int64_t OffsetOffset) {
+ CharUnits OffsetOffset) {
// Check if we can reuse an offset.
for (unsigned I = 0, E = Offsets.size(); I != E; ++I) {
if (MethodsCanShareVCallOffset(Offsets[I].first, MD))
@@ -689,7 +692,7 @@ bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD,
return true;
}
-int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) {
+CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) {
// Look for an offset.
for (unsigned I = 0, E = Offsets.size(); I != E; ++I) {
if (MethodsCanShareVCallOffset(Offsets[I].first, MD))
@@ -697,13 +700,13 @@ int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) {
}
assert(false && "Should always find a vcall offset offset!");
- return 0;
+ return CharUnits::Zero();
}
/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets.
class VCallAndVBaseOffsetBuilder {
public:
- typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
VBaseOffsetOffsetsMapTy;
private:
@@ -741,24 +744,25 @@ private:
/// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
/// given base subobject.
void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
- uint64_t RealBaseOffset);
+ CharUnits RealBaseOffset);
/// AddVCallOffsets - Add vcall offsets for the given base subobject.
- void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset);
+ void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset);
/// AddVBaseOffsets - Add vbase offsets for the given class.
- void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass);
+ void AddVBaseOffsets(const CXXRecordDecl *Base,
+ CharUnits OffsetInLayoutClass);
/// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in
- /// bytes, relative to the vtable address point.
- int64_t getCurrentOffsetOffset() const;
+ /// chars, relative to the vtable address point.
+ CharUnits getCurrentOffsetOffset() const;
public:
VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass,
const CXXRecordDecl *LayoutClass,
const FinalOverriders *Overriders,
BaseSubobject Base, bool BaseIsVirtual,
- uint64_t OffsetInLayoutClass)
+ CharUnits OffsetInLayoutClass)
: MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass),
Context(MostDerivedClass->getASTContext()), Overriders(Overriders) {
@@ -780,7 +784,7 @@ public:
void
VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
bool BaseIsVirtual,
- uint64_t RealBaseOffset) {
+ CharUnits RealBaseOffset) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase());
// Itanium C++ ABI 2.5.2:
@@ -795,7 +799,7 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
- uint64_t PrimaryBaseOffset;
+ CharUnits PrimaryBaseOffset;
// Get the base offset of the primary base.
if (PrimaryBaseIsVirtual) {
@@ -806,7 +810,7 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
Context.getASTRecordLayout(MostDerivedClass);
PrimaryBaseOffset =
- MostDerivedClassLayout.getVBaseClassOffsetInBits(PrimaryBase);
+ MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
} else {
assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
"Primary base should have a zero offset!");
@@ -814,8 +818,9 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
PrimaryBaseOffset = Base.getBaseOffset();
}
- AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
- PrimaryBaseIsVirtual, RealBaseOffset);
+ AddVCallAndVBaseOffsets(
+ BaseSubobject(PrimaryBase,PrimaryBaseOffset),
+ PrimaryBaseIsVirtual, RealBaseOffset);
}
AddVBaseOffsets(Base.getBase(), RealBaseOffset);
@@ -825,22 +830,21 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
AddVCallOffsets(Base, RealBaseOffset);
}
-int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
+CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
// OffsetIndex is the index of this vcall or vbase offset, relative to the
// vtable address point. (We subtract 3 to account for the information just
// above the address point, the RTTI info, the offset to top, and the
// vcall offset itself).
int64_t OffsetIndex = -(int64_t)(3 + Components.size());
- // FIXME: We shouldn't use / 8 here.
- int64_t OffsetOffset = OffsetIndex *
- (int64_t)Context.Target.getPointerWidth(0) / 8;
-
+ CharUnits PointerWidth =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ CharUnits OffsetOffset = PointerWidth * OffsetIndex;
return OffsetOffset;
}
void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
- uint64_t VBaseOffset) {
+ CharUnits VBaseOffset) {
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -866,14 +870,14 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
if (!MD->isVirtual())
continue;
- int64_t OffsetOffset = getCurrentOffsetOffset();
+ CharUnits OffsetOffset = getCurrentOffsetOffset();
// Don't add a vcall offset if we already have one for this member function
// signature.
if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
continue;
- int64_t Offset = 0;
+ CharUnits Offset = CharUnits::Zero();
if (Overriders) {
// Get the final overrider.
@@ -882,11 +886,11 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
/// The vcall offset is the offset from the virtual base to the object
/// where the function was overridden.
- // FIXME: We should not use / 8 here.
- Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8;
+ Offset = Overrider.Offset - VBaseOffset;
}
- Components.push_back(VTableComponent::MakeVCallOffset(Offset));
+ Components.push_back(
+ VTableComponent::MakeVCallOffset(Offset));
}
// And iterate over all non-virtual bases (ignoring the primary base).
@@ -902,15 +906,17 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
continue;
// Get the base offset of this base.
- uint64_t BaseOffset = Base.getBaseOffset() +
- Layout.getBaseClassOffsetInBits(BaseDecl);
+ CharUnits BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
- AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset);
+ AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset),
+ VBaseOffset);
}
}
-void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
- uint64_t OffsetInLayoutClass) {
+void
+VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
+ CharUnits OffsetInLayoutClass) {
const ASTRecordLayout &LayoutClassLayout =
Context.getASTRecordLayout(LayoutClass);
@@ -922,19 +928,19 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
// Check if this is a virtual base that we haven't visited before.
if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
- // FIXME: We shouldn't use / 8 here.
- int64_t Offset =
- (int64_t)(LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl) -
- OffsetInLayoutClass) / 8;
+ CharUnits Offset =
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass;
// Add the vbase offset offset.
assert(!VBaseOffsetOffsets.count(BaseDecl) &&
"vbase offset offset already exists!");
- int64_t VBaseOffsetOffset = getCurrentOffsetOffset();
- VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset));
+ CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
+ VBaseOffsetOffsets.insert(
+ std::make_pair(BaseDecl, VBaseOffsetOffset));
- Components.push_back(VTableComponent::MakeVBaseOffset(Offset));
+ Components.push_back(
+ VTableComponent::MakeVBaseOffset(Offset));
}
// Check the base class looking for more vbase offsets.
@@ -950,7 +956,7 @@ public:
typedef llvm::SmallSetVector<const CXXRecordDecl *, 8>
PrimaryBasesSetVectorTy;
- typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
VBaseOffsetOffsetsMapTy;
typedef llvm::DenseMap<BaseSubobject, uint64_t>
@@ -966,7 +972,7 @@ private:
/// MostDerivedClassOffset - If we're building a construction vtable, this
/// holds the offset from the layout class to the most derived class.
- const uint64_t MostDerivedClassOffset;
+ const CharUnits MostDerivedClassOffset;
/// MostDerivedClassIsVirtual - Whether the most derived class is a virtual
/// base. (This only makes sense when building a construction vtable).
@@ -1001,23 +1007,26 @@ private:
/// (Used for computing 'this' pointer adjustment thunks.
struct MethodInfo {
/// BaseOffset - The base offset of this method.
- const uint64_t BaseOffset;
+ const CharUnits BaseOffset;
/// BaseOffsetInLayoutClass - The base offset in the layout class of this
/// method.
- const uint64_t BaseOffsetInLayoutClass;
+ const CharUnits BaseOffsetInLayoutClass;
/// VTableIndex - The index in the vtable that this method has.
/// (For destructors, this is the index of the complete destructor).
const uint64_t VTableIndex;
- MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass,
+ MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass,
uint64_t VTableIndex)
: BaseOffset(BaseOffset),
BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
VTableIndex(VTableIndex) { }
- MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VTableIndex(0) { }
+ MethodInfo()
+ : BaseOffset(CharUnits::Zero()),
+ BaseOffsetInLayoutClass(CharUnits::Zero()),
+ VTableIndex(0) { }
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -1066,7 +1075,7 @@ private:
/// final overrider.
ThisAdjustment
ComputeThisAdjustment(const CXXMethodDecl *MD,
- uint64_t BaseOffsetInLayoutClass,
+ CharUnits BaseOffsetInLayoutClass,
FinalOverriders::OverriderInfo Overrider);
/// AddMethod - Add a single virtual member function to the vtable
@@ -1093,16 +1102,16 @@ private:
/// C-in-D's copy of A's vtable is never referenced, so this is not
/// necessary.
bool IsOverriderUsed(const CXXMethodDecl *Overrider,
- uint64_t BaseOffsetInLayoutClass,
+ CharUnits BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- uint64_t FirstBaseOffsetInLayoutClass) const;
+ CharUnits FirstBaseOffsetInLayoutClass) const;
/// AddMethods - Add the methods of this base subobject and all its
/// primary bases to the vtable components vector.
- void AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
+ void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- uint64_t FirstBaseOffsetInLayoutClass,
+ CharUnits FirstBaseOffsetInLayoutClass,
PrimaryBasesSetVectorTy &PrimaryBases);
// LayoutVTable - Layout the vtable for the given base class, including its
@@ -1120,7 +1129,7 @@ private:
void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
bool BaseIsMorallyVirtual,
bool BaseIsVirtualInLayoutClass,
- uint64_t OffsetInLayoutClass);
+ CharUnits OffsetInLayoutClass);
/// LayoutSecondaryVTables - Layout the secondary vtables for the given base
/// subobject.
@@ -1128,12 +1137,12 @@ private:
/// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
/// or a direct or indirect base of a virtual base.
void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
- uint64_t OffsetInLayoutClass);
+ CharUnits OffsetInLayoutClass);
/// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
/// class hierarchy.
void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
- uint64_t OffsetInLayoutClass,
+ CharUnits OffsetInLayoutClass,
VisitedVirtualBasesSetTy &VBases);
/// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the
@@ -1149,8 +1158,9 @@ private:
public:
VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
- uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual,
- const CXXRecordDecl *LayoutClass)
+ CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual, const
+ CXXRecordDecl *LayoutClass)
: VTables(VTables), MostDerivedClass(MostDerivedClass),
MostDerivedClassOffset(MostDerivedClassOffset),
MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
@@ -1325,15 +1335,15 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
if (Offset.DerivedClass == MostDerivedClass) {
// We can get the offset offset directly from our map.
Adjustment.VBaseOffsetOffset =
- VBaseOffsetOffsets.lookup(Offset.VirtualBase);
+ VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
} else {
Adjustment.VBaseOffsetOffset =
VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
- Offset.VirtualBase);
+ Offset.VirtualBase).getQuantity();
}
}
- Adjustment.NonVirtual = Offset.NonVirtualOffset;
+ Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
}
return Adjustment;
@@ -1360,8 +1370,7 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
I != E; ++I) {
BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I);
- // FIXME: Should not use * 8 here.
- uint64_t OffsetToBaseSubobject = Offset.NonVirtualOffset * 8;
+ CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset;
if (Offset.VirtualBase) {
// If we have a virtual base class, the non-virtual offset is relative
@@ -1372,7 +1381,7 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
/// Get the virtual base offset, relative to the most derived class
/// layout.
OffsetToBaseSubobject +=
- LayoutClassLayout.getVBaseClassOffsetInBits(Offset.VirtualBase);
+ LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase);
} else {
// Otherwise, the non-virtual offset is relative to the derived class
// offset.
@@ -1393,13 +1402,13 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
ThisAdjustment
VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
- uint64_t BaseOffsetInLayoutClass,
+ CharUnits BaseOffsetInLayoutClass,
FinalOverriders::OverriderInfo Overrider) {
// Ignore adjustments for pure virtual member functions.
if (Overrider.Method->isPure())
return ThisAdjustment();
- BaseSubobject OverriddenBaseSubobject(MD->getParent(),
+ BaseSubobject OverriddenBaseSubobject(MD->getParent(),
BaseOffsetInLayoutClass);
BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
@@ -1422,18 +1431,21 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
// build them.
VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
/*FinalOverriders=*/0,
- BaseSubobject(Offset.VirtualBase, 0),
+ BaseSubobject(Offset.VirtualBase,
+ CharUnits::Zero()),
/*BaseIsVirtual=*/true,
- /*OffsetInLayoutClass=*/0);
+ /*OffsetInLayoutClass=*/
+ CharUnits::Zero());
VCallOffsets = Builder.getVCallOffsets();
}
- Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD);
+ Adjustment.VCallOffsetOffset =
+ VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
}
// Set the non-virtual part of the adjustment.
- Adjustment.NonVirtual = Offset.NonVirtualOffset;
+ Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
return Adjustment;
}
@@ -1489,9 +1501,9 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
bool
VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
- uint64_t BaseOffsetInLayoutClass,
+ CharUnits BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- uint64_t FirstBaseOffsetInLayoutClass) const {
+ CharUnits FirstBaseOffsetInLayoutClass) const {
// If the base and the first base in the primary base chain have the same
// offsets, then this overrider will be used.
if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
@@ -1529,7 +1541,7 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
// Now check if this is the primary base that is not a primary base in the
// most derived class.
- if (LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase) !=
+ if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
FirstBaseOffsetInLayoutClass) {
// We found it, stop walking the chain.
break;
@@ -1576,16 +1588,16 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD,
}
void
-VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
+VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- uint64_t FirstBaseOffsetInLayoutClass,
+ CharUnits FirstBaseOffsetInLayoutClass,
PrimaryBasesSetVectorTy &PrimaryBases) {
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
- uint64_t PrimaryBaseOffset;
- uint64_t PrimaryBaseOffsetInLayoutClass;
+ CharUnits PrimaryBaseOffset;
+ CharUnits PrimaryBaseOffsetInLayoutClass;
if (Layout.isPrimaryBaseVirtual()) {
assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 &&
"Primary vbase should have a zero offset!");
@@ -1594,13 +1606,13 @@ VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
Context.getASTRecordLayout(MostDerivedClass);
PrimaryBaseOffset =
- MostDerivedClassLayout.getVBaseClassOffsetInBits(PrimaryBase);
+ MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
const ASTRecordLayout &LayoutClassLayout =
Context.getASTRecordLayout(LayoutClass);
PrimaryBaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase);
+ LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
} else {
assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 &&
"Primary base should have a zero offset!");
@@ -1642,8 +1654,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
"Did not find the overridden method!");
MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
- MethodInfo MethodInfo(Base.getBaseOffset(),
- BaseOffsetInLayoutClass,
+ MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
OverriddenMethodInfo.VTableIndex);
assert(!MethodInfoMap.count(MD) &&
@@ -1716,7 +1727,8 @@ VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
}
void VTableBuilder::LayoutVTable() {
- LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 0),
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
+ CharUnits::Zero()),
/*BaseIsMorallyVirtual=*/false,
MostDerivedClassIsVirtual,
MostDerivedClassOffset);
@@ -1724,7 +1736,7 @@ void VTableBuilder::LayoutVTable() {
VisitedVirtualBasesSetTy VBases;
// Determine the primary virtual bases.
- DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
+ DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
VBases);
VBases.clear();
@@ -1735,7 +1747,7 @@ void
VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
bool BaseIsMorallyVirtual,
bool BaseIsVirtualInLayoutClass,
- uint64_t OffsetInLayoutClass) {
+ CharUnits OffsetInLayoutClass) {
assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
// Add vcall and vbase offsets for this vtable.
@@ -1758,10 +1770,9 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
// Add the offset to top.
- // FIXME: We should not use / 8 here.
- int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass -
- MostDerivedClassOffset) / 8;
- Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
+ CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
+ Components.push_back(
+ VTableComponent::MakeOffsetToTop(OffsetToTop));
// Next, add the RTTI.
Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
@@ -1770,7 +1781,8 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
// Now go through all virtual member functions and add them.
PrimaryBasesSetVectorTy PrimaryBases;
- AddMethods(Base, OffsetInLayoutClass, Base.getBase(), OffsetInLayoutClass,
+ AddMethods(Base, OffsetInLayoutClass,
+ Base.getBase(), OffsetInLayoutClass,
PrimaryBases);
// Compute 'this' pointer adjustments.
@@ -1779,8 +1791,9 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
// Add all address points.
const CXXRecordDecl *RD = Base.getBase();
while (true) {
- AddressPoints.insert(std::make_pair(BaseSubobject(RD, OffsetInLayoutClass),
- AddressPoint));
+ AddressPoints.insert(std::make_pair(
+ BaseSubobject(RD, OffsetInLayoutClass),
+ AddressPoint));
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
@@ -1794,7 +1807,7 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
const ASTRecordLayout &LayoutClassLayout =
Context.getASTRecordLayout(LayoutClass);
- if (LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase) !=
+ if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
OffsetInLayoutClass) {
// We don't want to add this class (or any of its primary bases).
break;
@@ -1810,7 +1823,7 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
bool BaseIsMorallyVirtual,
- uint64_t OffsetInLayoutClass) {
+ CharUnits OffsetInLayoutClass) {
// Itanium C++ ABI 2.5.2:
// Following the primary virtual table of a derived class are secondary
// virtual tables for each of its proper base classes, except any primary
@@ -1844,10 +1857,11 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
}
// Get the base offset of this base.
- uint64_t RelativeBaseOffset = Layout.getBaseClassOffsetInBits(BaseDecl);
- uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
+ CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl);
+ CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
- uint64_t BaseOffsetInLayoutClass = OffsetInLayoutClass + RelativeBaseOffset;
+ CharUnits BaseOffsetInLayoutClass =
+ OffsetInLayoutClass + RelativeBaseOffset;
// Don't emit a secondary vtable for a primary base. We might however want
// to emit secondary vtables for other bases of this base.
@@ -1858,16 +1872,17 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
}
// Layout the primary vtable (and any secondary vtables) for this base.
- LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
- BaseIsMorallyVirtual,
- /*BaseIsVirtualInLayoutClass=*/false,
- BaseOffsetInLayoutClass);
+ LayoutPrimaryAndSecondaryVTables(
+ BaseSubobject(BaseDecl, BaseOffset),
+ BaseIsMorallyVirtual,
+ /*BaseIsVirtualInLayoutClass=*/false,
+ BaseOffsetInLayoutClass);
}
}
void
VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
- uint64_t OffsetInLayoutClass,
+ CharUnits OffsetInLayoutClass,
VisitedVirtualBasesSetTy &VBases) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -1884,8 +1899,8 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
const ASTRecordLayout &LayoutClassLayout =
Context.getASTRecordLayout(LayoutClass);
- uint64_t PrimaryBaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase);
+ CharUnits PrimaryBaseOffsetInLayoutClass =
+ LayoutClassLayout.getVBaseClassOffset(PrimaryBase);
// We know that the base is not a primary base in the layout class if
// the base offsets are different.
@@ -1904,7 +1919,7 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffsetInLayoutClass;
+ CharUnits BaseOffsetInLayoutClass;
if (I->isVirtual()) {
if (!VBases.insert(BaseDecl))
@@ -1914,10 +1929,10 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
Context.getASTRecordLayout(LayoutClass);
BaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl);
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl);
} else {
BaseOffsetInLayoutClass =
- OffsetInLayoutClass + Layout.getBaseClassOffsetInBits(BaseDecl);
+ OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl);
}
DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
@@ -1942,18 +1957,19 @@ VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
!PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) {
const ASTRecordLayout &MostDerivedClassLayout =
Context.getASTRecordLayout(MostDerivedClass);
- uint64_t BaseOffset =
- MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl);
+ CharUnits BaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
const ASTRecordLayout &LayoutClassLayout =
Context.getASTRecordLayout(LayoutClass);
- uint64_t BaseOffsetInLayoutClass =
- LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl);
-
- LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
- /*BaseIsMorallyVirtual=*/true,
- /*BaseIsVirtualInLayoutClass=*/true,
- BaseOffsetInLayoutClass);
+ CharUnits BaseOffsetInLayoutClass =
+ LayoutClassLayout.getVBaseClassOffset(BaseDecl);
+
+ LayoutPrimaryAndSecondaryVTables(
+ BaseSubobject(BaseDecl, BaseOffset),
+ /*BaseIsMorallyVirtual=*/true,
+ /*BaseIsVirtualInLayoutClass=*/true,
+ BaseOffsetInLayoutClass);
}
// We only need to check the base for virtual base vtables if it actually
@@ -1969,8 +1985,7 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
if (isBuildingConstructorVTable()) {
Out << "Construction vtable for ('";
Out << MostDerivedClass->getQualifiedNameAsString() << "', ";
- // FIXME: Don't use / 8 .
- Out << MostDerivedClassOffset / 8 << ") in '";
+ Out << MostDerivedClassOffset.getQuantity() << ") in '";
Out << LayoutClass->getQualifiedNameAsString();
} else {
Out << "Vtable for '";
@@ -2002,15 +2017,21 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
switch (Component.getKind()) {
case VTableComponent::CK_VCallOffset:
- Out << "vcall_offset (" << Component.getVCallOffset() << ")";
+ Out << "vcall_offset ("
+ << Component.getVCallOffset().getQuantity()
+ << ")";
break;
case VTableComponent::CK_VBaseOffset:
- Out << "vbase_offset (" << Component.getVBaseOffset() << ")";
+ Out << "vbase_offset ("
+ << Component.getVBaseOffset().getQuantity()
+ << ")";
break;
case VTableComponent::CK_OffsetToTop:
- Out << "offset_to_top (" << Component.getOffsetToTop() << ")";
+ Out << "offset_to_top ("
+ << Component.getOffsetToTop().getQuantity()
+ << ")";
break;
case VTableComponent::CK_RTTI:
@@ -2116,11 +2137,11 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
const BaseSubobject &Base =
AddressPointsByIndex.find(NextIndex)->second;
- // FIXME: Instead of dividing by 8, we should be using CharUnits.
Out << " -- (" << Base.getBase()->getQualifiedNameAsString();
- Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n";
+ Out << ", " << Base.getBaseOffset().getQuantity();
+ Out << ") vtable address --\n";
} else {
- uint64_t BaseOffset =
+ CharUnits BaseOffset =
AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
// We store the class names in a set to get a stable order.
@@ -2136,9 +2157,8 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
for (std::set<std::string>::const_iterator I = ClassNames.begin(),
E = ClassNames.end(); I != E; ++I) {
- // FIXME: Instead of dividing by 8, we should be using CharUnits.
Out << " -- (" << *I;
- Out << ", " << BaseOffset / 8 << ") vtable address --\n";
+ Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n";
}
}
}
@@ -2153,12 +2173,13 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
// We store the virtual base class names and their offsets in a map to get
// a stable order.
- std::map<std::string, int64_t> ClassNamesAndOffsets;
+ std::map<std::string, CharUnits> ClassNamesAndOffsets;
for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(),
E = VBaseOffsetOffsets.end(); I != E; ++I) {
std::string ClassName = I->first->getQualifiedNameAsString();
- int64_t OffsetOffset = I->second;
- ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
+ CharUnits OffsetOffset = I->second;
+ ClassNamesAndOffsets.insert(
+ std::make_pair(ClassName, OffsetOffset));
}
Out << "Virtual base offset offsets for '";
@@ -2166,10 +2187,10 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << ClassNamesAndOffsets.size();
Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
- for (std::map<std::string, int64_t>::const_iterator I =
+ for (std::map<std::string, CharUnits>::const_iterator I =
ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end();
I != E; ++I)
- Out << " " << I->first << " | " << I->second << '\n';
+ Out << " " << I->first << " | " << I->second.getQuantity() << '\n';
Out << "\n";
}
@@ -2233,9 +2254,51 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
}
Out << '\n';
+ }
+ }
+
+ // Compute the vtable indices for all the member functions.
+ // Store them in a map keyed by the index so we'll get a sorted table.
+ std::map<uint64_t, std::string> IndicesMap;
+
+ for (CXXRecordDecl::method_iterator i = MostDerivedClass->method_begin(),
+ e = MostDerivedClass->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+
+ // We only want virtual member functions.
+ if (!MD->isVirtual())
+ continue;
+
+ std::string MethodName =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ MD);
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] =
+ MethodName + " [complete]";
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] =
+ MethodName + " [deleting]";
+ } else {
+ IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
+ }
+ }
+
+ // Print the vtable indices for all the member functions.
+ if (!IndicesMap.empty()) {
+ Out << "VTable indices for '";
+ Out << MostDerivedClass->getQualifiedNameAsString();
+ Out << "' (" << IndicesMap.size() << " entries).\n";
+ for (std::map<uint64_t, std::string>::const_iterator I = IndicesMap.begin(),
+ E = IndicesMap.end(); I != E; ++I) {
+ uint64_t VTableIndex = I->first;
+ const std::string &MethodName = I->second;
+
+ Out << llvm::format(" %4u | ", VTableIndex) << MethodName << '\n';
}
}
+
+ Out << '\n';
}
}
@@ -2243,14 +2306,16 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
static void
CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) {
- while (RD) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- if (PrimaryBase)
- PrimaryBases.insert(PrimaryBase);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- RD = PrimaryBase;
- }
+ if (!PrimaryBase)
+ return;
+
+ CollectPrimaryBases(PrimaryBase, Context, PrimaryBases);
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ assert(false && "Found a duplicate primary base!");
}
void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
@@ -2410,8 +2475,9 @@ uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) {
return I->second;
}
-int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase) {
+CharUnits
+CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
ClassPairTy ClassPair(RD, VBase);
VirtualBaseClassOffsetOffsetsMapTy::iterator I =
@@ -2420,9 +2486,9 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
return I->second;
VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0,
- BaseSubobject(RD, 0),
+ BaseSubobject(RD, CharUnits::Zero()),
/*BaseIsVirtual=*/false,
- /*OffsetInLayoutClass=*/0);
+ /*OffsetInLayoutClass=*/CharUnits::Zero());
for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
Builder.getVBaseOffsetOffsets().begin(),
@@ -2430,7 +2496,8 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
// Insert all types.
ClassPairTy ClassPair(RD, I->first);
- VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second));
+ VirtualBaseClassOffsetOffsets.insert(
+ std::make_pair(ClassPair, I->second));
}
I = VirtualBaseClassOffsetOffsets.find(ClassPair);
@@ -2531,7 +2598,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
return;
- if (MD->hasAttr<VisibilityAttr>())
+ if (MD->getExplicitVisibility())
return;
switch (MD->getTemplateSpecializationKind()) {
@@ -2559,8 +2626,19 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
}
-void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
- const ThunkInfo &Thunk) {
+#ifndef NDEBUG
+static bool similar(const ABIArgInfo &infoL, CanQualType typeL,
+ const ABIArgInfo &infoR, CanQualType typeR) {
+ return (infoL.getKind() == infoR.getKind() &&
+ (typeL == typeR ||
+ (isa<PointerType>(typeL) && isa<PointerType>(typeR)) ||
+ (isa<ReferenceType>(typeL) && isa<ReferenceType>(typeR))));
+}
+#endif
+
+void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo,
+ GlobalDecl GD, const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
QualType ResultType = FPT->getResultType();
@@ -2580,10 +2658,11 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
E = MD->param_end(); I != E; ++I) {
ParmVarDecl *Param = *I;
- FunctionArgs.push_back(std::make_pair(Param, Param->getType()));
+ FunctionArgs.push_back(Param);
}
- StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation());
+ StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
+ SourceLocation());
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
@@ -2596,16 +2675,13 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
CallArgList CallArgs;
// Add our adjusted 'this' pointer.
- CallArgs.push_back(std::make_pair(RValue::get(AdjustedThisPtr), ThisType));
+ CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
// Add the rest of the parameters.
for (FunctionDecl::param_const_iterator I = MD->param_begin(),
E = MD->param_end(); I != E; ++I) {
- ParmVarDecl *Param = *I;
- QualType ArgType = Param->getType();
- RValue Arg = EmitDelegateCallArg(Param);
-
- CallArgs.push_back(std::make_pair(Arg, ArgType));
+ ParmVarDecl *param = *I;
+ EmitDelegateCallArg(CallArgs, param);
}
// Get our callee.
@@ -2614,9 +2690,20 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
FPT->isVariadic());
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
- const CGFunctionInfo &FnInfo =
- CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
- FPT->getExtInfo());
+#ifndef NDEBUG
+ const CGFunctionInfo &CallFnInfo =
+ CGM.getTypes().getFunctionInfo(ResultType, CallArgs, FPT->getExtInfo());
+ assert(CallFnInfo.getRegParm() == FnInfo.getRegParm() &&
+ CallFnInfo.isNoReturn() == FnInfo.isNoReturn() &&
+ CallFnInfo.getCallingConvention() == FnInfo.getCallingConvention());
+ assert(similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(),
+ FnInfo.getReturnInfo(), FnInfo.getReturnType()));
+ assert(CallFnInfo.arg_size() == FnInfo.arg_size());
+ for (unsigned i = 0, e = FnInfo.arg_size(); i != e; ++i)
+ assert(similar(CallFnInfo.arg_begin()[i].info,
+ CallFnInfo.arg_begin()[i].type,
+ FnInfo.arg_begin()[i].info, FnInfo.arg_begin()[i].type));
+#endif
// Determine whether we have a return value slot to use.
ReturnValueSlot Slot;
@@ -2658,8 +2745,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
Builder.CreateBr(AdjustEnd);
EmitBlock(AdjustEnd);
- llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType());
- PHI->reserveOperandSpace(2);
+ llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType(), 2);
PHI->addIncoming(ReturnValue, AdjustNotNull);
PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
AdjustNull);
@@ -2684,6 +2770,9 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
bool UseAvailableExternallyLinkage)
{
+ const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(GD);
+
+ // FIXME: re-use FnInfo in this computation.
llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);
// Strip off a bitcast if we got one back.
@@ -2735,7 +2824,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
}
// Actually generate the thunk body.
- CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk);
+ CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
if (UseAvailableExternallyLinkage)
ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
@@ -2796,7 +2885,8 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD,
if (Entry.getPointer())
return;
- VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+ VTableBuilder Builder(*this, RD, CharUnits::Zero(),
+ /*MostDerivedClassIsVirtual=*/0, RD);
// Add the VTable layout.
uint64_t NumVTableComponents = Builder.getNumVTableComponents();
@@ -2864,7 +2954,8 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD,
// Insert all types.
ClassPairTy ClassPair(RD, I->first);
- VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second));
+ VirtualBaseClassOffsetOffsets.insert(
+ std::make_pair(ClassPair, I->second));
}
}
@@ -2895,15 +2986,18 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
switch (Component.getKind()) {
case VTableComponent::CK_VCallOffset:
- Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset());
+ Init = llvm::ConstantInt::get(PtrDiffTy,
+ Component.getVCallOffset().getQuantity());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
case VTableComponent::CK_VBaseOffset:
- Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset());
+ Init = llvm::ConstantInt::get(PtrDiffTy,
+ Component.getVBaseOffset().getQuantity());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
case VTableComponent::CK_OffsetToTop:
- Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop());
+ Init = llvm::ConstantInt::get(PtrDiffTy,
+ Component.getOffsetToTop().getQuantity());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
case VTableComponent::CK_RTTI:
@@ -3001,7 +3095,8 @@ CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable,
const CXXRecordDecl *RD) {
// Dump the vtable layout if necessary.
if (CGM.getLangOptions().DumpVTableLayouts) {
- VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+ VTableBuilder Builder(*this, RD, CharUnits::Zero(),
+ /*MostDerivedClassIsVirtual=*/0, RD);
Builder.dumpLayout(llvm::errs());
}
@@ -3028,8 +3123,10 @@ llvm::GlobalVariable *
CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
const BaseSubobject &Base,
bool BaseIsVirtual,
+ llvm::GlobalVariable::LinkageTypes Linkage,
VTableAddressPointsMapTy& AddressPoints) {
- VTableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(),
+ VTableBuilder Builder(*this, Base.getBase(),
+ Base.getBaseOffset(),
/*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD);
// Dump the vtable layout if necessary.
@@ -3044,7 +3141,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
llvm::SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().
- mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, Base.getBase(), Out);
+ mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(), Base.getBase(),
+ Out);
Out.flush();
llvm::StringRef Name = OutName.str();
@@ -3054,8 +3152,11 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
- CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType,
- llvm::GlobalValue::InternalLinkage);
+ CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage);
+ CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForConstructionVTable);
+
+ // V-tables are always unnamed_addr.
+ VTable->setUnnamedAddr(true);
// Add the thunks.
VTableThunksTy VTableThunks;
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index 7c119fa42241..e830e9a6fbcb 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -1,4 +1,4 @@
-//===--- CGVTables.h - Emit LLVM Code for C++ vtables ---------------------===//
+//===--- CGVTables.h - Emit LLVM Code for C++ vtables -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -17,6 +17,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/GlobalVariable.h"
#include "clang/Basic/ABI.h"
+#include "clang/AST/CharUnits.h"
#include "GlobalDecl.h"
namespace clang {
@@ -33,17 +34,17 @@ class BaseSubobject {
const CXXRecordDecl *Base;
/// BaseOffset - The offset from the most derived class to the base class.
- uint64_t BaseOffset;
+ CharUnits BaseOffset;
public:
- BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset)
+ BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset)
: Base(Base), BaseOffset(BaseOffset) { }
/// getBase - Returns the base class declaration.
const CXXRecordDecl *getBase() const { return Base; }
/// getBaseOffset - Returns the base class offset.
- uint64_t getBaseOffset() const { return BaseOffset; }
+ CharUnits getBaseOffset() const { return BaseOffset; }
friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) {
return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset;
@@ -59,19 +60,19 @@ template<> struct DenseMapInfo<clang::CodeGen::BaseSubobject> {
static clang::CodeGen::BaseSubobject getEmptyKey() {
return clang::CodeGen::BaseSubobject(
DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(),
- DenseMapInfo<uint64_t>::getEmptyKey());
+ clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey()));
}
static clang::CodeGen::BaseSubobject getTombstoneKey() {
return clang::CodeGen::BaseSubobject(
DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(),
- DenseMapInfo<uint64_t>::getTombstoneKey());
+ clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey()));
}
static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) {
return
DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
- DenseMapInfo<uint64_t>::getHashValue(Base.getBaseOffset());
+ DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity());
}
static bool isEqual(const clang::CodeGen::BaseSubobject &LHS,
@@ -102,9 +103,9 @@ class CodeGenVTables {
const CXXRecordDecl *> ClassPairTy;
/// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
- /// the address point) in bytes where the offsets for virtual bases of a class
+ /// the address point) in chars where the offsets for virtual bases of a class
/// are stored.
- typedef llvm::DenseMap<ClassPairTy, int64_t>
+ typedef llvm::DenseMap<ClassPairTy, CharUnits>
VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
@@ -234,13 +235,13 @@ public:
/// stored.
uint64_t getMethodVTableIndex(GlobalDecl GD);
- /// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the
+ /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the
/// vtable address point) where the offset of the virtual base that contains
/// the given base is stored, otherwise, if no virtual base contains the given
/// class, return 0. Base must be a virtual base class or an unambigious
/// base.
- int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase);
+ CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase);
/// getAddressPoint - Get the address point of the given subobject in the
/// class decl.
@@ -259,6 +260,7 @@ public:
llvm::GlobalVariable *
GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base,
bool BaseIsVirtual,
+ llvm::GlobalVariable::LinkageTypes Linkage,
VTableAddressPointsMapTy& AddressPoints);
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 8c20f29903aa..80e46d2be704 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
asmparser
bitreader
bitwriter
+ instrumentation
ipo
)
@@ -29,6 +30,7 @@ add_clang_library(clangCodeGen
CGObjC.cpp
CGObjCGNU.cpp
CGObjCMac.cpp
+ CGObjCRuntime.cpp
CGRecordLayoutBuilder.cpp
CGRTTI.cpp
CGStmt.cpp
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index a24bbc480c19..62fa1f9843de 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -216,7 +216,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
return;
}
- // Otherwise, report the backend error as occuring in the generated .s file.
+ // Otherwise, report the backend error as occurring in the generated .s file.
// If Loc is invalid, we still need to report the error, it just gets no
// location info.
Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message);
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f1b72863caca..626c2b09a032 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -33,7 +33,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
BlockInfo(0), BlockPointer(0),
NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
- ExceptionSlot(0), DebugInfo(0), IndirectBranch(0),
+ ExceptionSlot(0), DebugInfo(0), DisableDebugInfo(false), IndirectBranch(0),
SwitchInsn(0), CaseRangeBlock(0),
DidCallStackSave(false), UnreachableBlock(0),
CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
@@ -210,6 +210,7 @@ void CodeGenFunction::EmitMCountInstrumentation() {
void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
SourceLocation StartLoc) {
const Decl *D = GD.getDecl();
@@ -218,6 +219,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
CurCodeDecl = CurFuncDecl = D;
FnRetTy = RetTy;
CurFn = Fn;
+ CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?");
// Pass inline keyword to optimizer if it appears explicitly on any
@@ -239,7 +241,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
CGM.getModule().getOrInsertNamedMetadata("opencl.kernels");
llvm::Value *Op = Fn;
- OpenCLMetadata->addOperand(llvm::MDNode::get(Context, &Op, 1));
+ OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Op));
}
}
@@ -275,11 +277,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (CGM.getCodeGenOpts().InstrumentForProfiling)
EmitMCountInstrumentation();
- // FIXME: Leaked.
- // CC info is ignored, hopefully?
- CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args,
- FunctionType::ExtInfo());
-
if (RetTy->isVoidType()) {
// Void type; nothing to return.
ReturnValue = 0;
@@ -302,7 +299,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// emit the type size.
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) {
- QualType Ty = i->second;
+ QualType Ty = (*i)->getType();
if (Ty->isVariablyModifiedType())
EmitVLASize(Ty);
@@ -332,12 +329,13 @@ static void TryMarkNoThrow(llvm::Function *F) {
F->setDoesNotThrow(true);
}
-void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
+void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
// Check if we should generate debug info for this function.
- if (CGM.getDebugInfo() && !FD->hasAttr<NoDebugAttr>())
- DebugInfo = CGM.getDebugInfo();
+ if (CGM.getModuleDebugInfo() && !FD->hasAttr<NoDebugAttr>())
+ DebugInfo = CGM.getModuleDebugInfo();
FunctionArgList Args;
QualType ResTy = FD->getResultType();
@@ -346,20 +344,15 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
- if (FD->getNumParams()) {
- const FunctionProtoType* FProto = FD->getType()->getAs<FunctionProtoType>();
- assert(FProto && "Function def must have prototype!");
-
+ if (FD->getNumParams())
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
- Args.push_back(std::make_pair(FD->getParamDecl(i),
- FProto->getArgType(i)));
- }
+ Args.push_back(FD->getParamDecl(i));
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
// Emit the standard function prologue.
- StartFunction(GD, ResTy, Fn, Args, BodyRange.getBegin());
+ StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
// Generate the body of the function.
if (isa<CXXDestructorDecl>(FD))
@@ -387,9 +380,12 @@ bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
// If this is a label, we have to emit the code, consider something like:
// if (0) { ... foo: bar(); } goto foo;
+ //
+ // TODO: If anyone cared, we could track __label__'s, since we know that you
+ // can't jump to one from outside their declared region.
if (isa<LabelStmt>(S))
return true;
-
+
// If this is a case/default statement, and we haven't seen a switch, we have
// to emit the code.
if (isa<SwitchCase>(S) && !IgnoreCaseStmts)
@@ -407,26 +403,65 @@ bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
return false;
}
+/// containsBreak - Return true if the statement contains a break out of it.
+/// If the statement (recursively) contains a switch or loop with a break
+/// inside of it, this is fine.
+bool CodeGenFunction::containsBreak(const Stmt *S) {
+ // Null statement, not a label!
+ if (S == 0) return false;
+
+ // If this is a switch or loop that defines its own break scope, then we can
+ // include it and anything inside of it.
+ if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S) ||
+ isa<ForStmt>(S))
+ return false;
+
+ if (isa<BreakStmt>(S))
+ return true;
+
+ // Scan subexpressions for verboten breaks.
+ for (Stmt::const_child_range I = S->children(); I; ++I)
+ if (containsBreak(*I))
+ return true;
+
+ return false;
+}
+
+
+/// ConstantFoldsToSimpleInteger - If the specified expression does not fold
+/// to a constant, or if it does but contains a label, return false. If it
+/// constant folds return true and set the boolean result in Result.
+bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
+ bool &ResultBool) {
+ llvm::APInt ResultInt;
+ if (!ConstantFoldsToSimpleInteger(Cond, ResultInt))
+ return false;
+
+ ResultBool = ResultInt.getBoolValue();
+ return true;
+}
-/// ConstantFoldsToSimpleInteger - If the sepcified expression does not fold to
-/// a constant, or if it does but contains a label, return 0. If it constant
-/// folds to 'true' and does not contain a label, return 1, if it constant folds
-/// to 'false' and does not contain a label, return -1.
-int CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond) {
+/// ConstantFoldsToSimpleInteger - If the specified expression does not fold
+/// to a constant, or if it does but contains a label, return false. If it
+/// constant folds return true and set the folded value.
+bool CodeGenFunction::
+ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APInt &ResultInt) {
// FIXME: Rename and handle conversion of other evaluatable things
// to bool.
Expr::EvalResult Result;
if (!Cond->Evaluate(Result, getContext()) || !Result.Val.isInt() ||
Result.HasSideEffects)
- return 0; // Not foldable, not integer or not fully evaluatable.
-
+ return false; // Not foldable, not integer or not fully evaluatable.
+
if (CodeGenFunction::ContainsLabel(Cond))
- return 0; // Contains a label.
-
- return Result.Val.getInt().getBoolValue() ? 1 : -1;
+ return false; // Contains a label.
+
+ ResultInt = Result.Val.getInt();
+ return true;
}
+
/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if
/// statement) to the specified blocks. Based on the condition, this might try
/// to simplify the codegen of the conditional based on the branch.
@@ -434,22 +469,24 @@ int CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond) {
void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(Cond))
- return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock);
+ Cond = Cond->IgnoreParens();
if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
// Handle X && Y in a condition.
if (CondBOp->getOpcode() == BO_LAnd) {
// If we have "1 && X", simplify the code. "0 && X" would have constant
// folded if the case was simple enough.
- if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == 1) {
+ bool ConstantBool = false;
+ if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
+ ConstantBool) {
// br(1 && X) -> br(X).
return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
}
// If we have "X && 1", simplify the code to use an uncond branch.
// "X && 0" would have been constant folded to 0.
- if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == 1) {
+ if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
+ ConstantBool) {
// br(X && 1) -> br(X).
return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock);
}
@@ -468,17 +505,22 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
eval.end(*this);
return;
- } else if (CondBOp->getOpcode() == BO_LOr) {
+ }
+
+ if (CondBOp->getOpcode() == BO_LOr) {
// If we have "0 || X", simplify the code. "1 || X" would have constant
// folded if the case was simple enough.
- if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == -1) {
+ bool ConstantBool = false;
+ if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
+ !ConstantBool) {
// br(0 || X) -> br(X).
return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
}
// If we have "X || 0", simplify the code to use an uncond branch.
// "X || 1" would have been constant folded to 1.
- if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == -1) {
+ if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
+ !ConstantBool) {
// br(X || 0) -> br(X).
return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock);
}
@@ -575,8 +617,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
// count must be nonzero.
CGF.EmitBlock(loopBB);
- llvm::PHINode *cur = Builder.CreatePHI(i8p, "vla.cur");
- cur->reserveOperandSpace(2);
+ llvm::PHINode *cur = Builder.CreatePHI(i8p, 2, "vla.cur");
cur->addIncoming(begin, originBB);
// memcpy the individual element bit-pattern.
@@ -613,15 +654,16 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
// Get size and alignment info for this aggregate.
- std::pair<uint64_t, unsigned> TypeInfo = getContext().getTypeInfo(Ty);
- uint64_t Size = TypeInfo.first / 8;
- unsigned Align = TypeInfo.second / 8;
+ std::pair<CharUnits, CharUnits> TypeInfo =
+ getContext().getTypeInfoInChars(Ty);
+ CharUnits Size = TypeInfo.first;
+ CharUnits Align = TypeInfo.second;
llvm::Value *SizeVal;
const VariableArrayType *vla;
// Don't bother emitting a zero-byte memset.
- if (Size == 0) {
+ if (Size.isZero()) {
// But note that getTypeInfo returns 0 for a VLA.
if (const VariableArrayType *vlaType =
dyn_cast_or_null<VariableArrayType>(
@@ -632,7 +674,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
return;
}
} else {
- SizeVal = llvm::ConstantInt::get(IntPtrTy, Size);
+ SizeVal = llvm::ConstantInt::get(IntPtrTy, Size.getQuantity());
vla = 0;
}
@@ -657,14 +699,15 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
if (vla) return emitNonZeroVLAInit(*this, Ty, DestPtr, SrcPtr, SizeVal);
// Get and call the appropriate llvm.memcpy overload.
- Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align, false);
+ Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align.getQuantity(), false);
return;
}
// Otherwise, just memset the whole thing to zero. This is legal
// because in LLVM, all default initializers (other than the ones we just
// handled above) are guaranteed to have a bit pattern of all zeros.
- Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, Align, false);
+ Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal,
+ Align.getQuantity(), false);
}
llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
@@ -686,7 +729,8 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto"));
// Create the PHI node that indirect gotos will add entries to.
- llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, "indirect.goto.dest");
+ llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, 0,
+ "indirect.goto.dest");
// Create the indirect branch instruction.
IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal);
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index be646fb29022..169c576f1a0e 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -25,7 +25,6 @@
#include "llvm/Support/ValueHandle.h"
#include "CodeGenModule.h"
#include "CGBuilder.h"
-#include "CGCall.h"
#include "CGValue.h"
namespace llvm {
@@ -43,6 +42,7 @@ namespace clang {
class APValue;
class ASTContext;
class CXXDestructorDecl;
+ class CXXForRangeStmt;
class CXXTryStmt;
class Decl;
class LabelDecl;
@@ -769,6 +769,11 @@ public:
/// block through the normal cleanup handling code (if any) and then
/// on to \arg Dest.
void EmitBranchThroughCleanup(JumpDest Dest);
+
+ /// isObviouslyBranchWithoutCleanups - Return true if a branch to the
+ /// specified destination obviously has no cleanups to run. 'false' is always
+ /// a conservatively correct answer for this method.
+ bool isObviouslyBranchWithoutCleanups(JumpDest Dest) const;
/// EmitBranchThroughEHCleanup - Emit a branch from the current
/// insert block through the EH cleanup handling code (if any) and
@@ -944,6 +949,7 @@ public:
const VarDecl *V);
private:
CGDebugInfo *DebugInfo;
+ bool DisableDebugInfo;
/// IndirectBranch - The first time an indirect goto is seen we create a block
/// with an indirect branch. Every time we see the address of a label taken,
@@ -1030,7 +1036,14 @@ public:
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
ASTContext &getContext() const;
- CGDebugInfo *getDebugInfo() { return DebugInfo; }
+ CGDebugInfo *getDebugInfo() {
+ if (DisableDebugInfo)
+ return NULL;
+ return DebugInfo;
+ }
+ void disableDebugInfo() { DisableDebugInfo = true; }
+ void enableDebugInfo() { DisableDebugInfo = false; }
+
const LangOptions &getLangOptions() const { return CGM.getLangOptions(); }
@@ -1100,15 +1113,13 @@ public:
llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo);
llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo);
- llvm::Constant *GeneratebyrefCopyHelperFunction(const llvm::Type *,
- BlockFieldFlags flags,
- const VarDecl *BD);
- llvm::Constant *GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
- BlockFieldFlags flags,
- const VarDecl *BD);
-
void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags);
+ class AutoVarEmission;
+
+ void emitByrefStructureInit(const AutoVarEmission &emission);
+ void enterByrefCleanup(const AutoVarEmission &emission);
+
llvm::Value *LoadBlockStruct() {
assert(BlockPointer && "no block pointer set!");
return BlockPointer;
@@ -1122,9 +1133,11 @@ public:
llvm::Value *GetAddrOfBlockDecl(const VarDecl *var, bool ByRef);
const llvm::Type *BuildByRefType(const VarDecl *var);
- void GenerateCode(GlobalDecl GD, llvm::Function *Fn);
+ void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo);
void StartFunction(GlobalDecl GD, QualType RetTy,
llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
SourceLocation StartLoc);
@@ -1141,7 +1154,8 @@ public:
void FinishFunction(SourceLocation EndLoc=SourceLocation());
/// GenerateThunk - Generate a thunk for the given method.
- void GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk);
+ void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
+ GlobalDecl GD, const ThunkInfo &Thunk);
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
FunctionArgList &Args);
@@ -1151,14 +1165,14 @@ public:
///
void InitializeVTablePointer(BaseSubobject Base,
const CXXRecordDecl *NearestVBase,
- uint64_t OffsetFromNearestVBase,
+ CharUnits OffsetFromNearestVBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass);
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
void InitializeVTablePointers(BaseSubobject Base,
const CXXRecordDecl *NearestVBase,
- uint64_t OffsetFromNearestVBase,
+ CharUnits OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
@@ -1353,12 +1367,18 @@ public:
/// always be accessible even if no aggregate location is provided.
RValue EmitAnyExprToTemp(const Expr *E);
- /// EmitsAnyExprToMem - Emits the code necessary to evaluate an
+ /// EmitAnyExprToMem - Emits the code necessary to evaluate an
/// arbitrary expression into the given memory location.
void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
bool IsLocationVolatile,
bool IsInitializer);
+ /// EmitExprAsInit - Emits the code necessary to initialize a
+ /// location in memory with the given initializer.
+ void EmitExprAsInit(const Expr *init, const VarDecl *var,
+ llvm::Value *loc, CharUnits alignment,
+ bool capturedByInit);
+
/// EmitAggregateCopy - Emit an aggrate copy.
///
/// \param isVolatile - True iff either the source or the destination is
@@ -1476,6 +1496,12 @@ public:
void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
const FunctionArgList &Args);
+ // It's important not to confuse this and the previous function. Delegating
+ // constructors are the C++0x feature. The constructor delegate optimization
+ // is used to reduce duplication in the base and complete consturctors where
+ // they are substantially the same.
+ void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
+ const FunctionArgList &Args);
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
bool ForVirtualBase, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
@@ -1609,7 +1635,7 @@ public:
llvm::GlobalValue::LinkageTypes Linkage);
/// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
- void EmitParmDecl(const VarDecl &D, llvm::Value *Arg);
+ void EmitParmDecl(const VarDecl &D, llvm::Value *Arg, unsigned ArgNo);
/// protectFromPeepholes - Protect a value that we're intending to
/// store to the side, but which will probably be used later, from
@@ -1680,6 +1706,7 @@ public:
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
void EmitCXXTryStmt(const CXXTryStmt &S);
+ void EmitCXXForRangeStmt(const CXXForRangeStmt &S);
//===--------------------------------------------------------------------===//
// LValue Expression Emission
@@ -1775,7 +1802,7 @@ public:
LValue EmitComplexAssignmentLValue(const BinaryOperator *E);
LValue EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E);
- // Note: only availabe for agg return types
+ // Note: only available for agg return types
LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
LValue EmitCompoundAssignmentLValue(const CompoundAssignOperator *E);
// Note: only available for agg return types
@@ -2022,7 +2049,8 @@ public:
const std::vector<std::pair<llvm::WeakVH,
llvm::Constant*> > &DtorsAndObjects);
- void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D,
+ void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
+ const VarDecl *D,
llvm::GlobalVariable *Addr);
void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest);
@@ -2044,12 +2072,21 @@ public:
/// that we can just remove the code.
static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false);
+ /// containsBreak - Return true if the statement contains a break out of it.
+ /// If the statement (recursively) contains a switch or loop with a break
+ /// inside of it, this is fine.
+ static bool containsBreak(const Stmt *S);
+
/// ConstantFoldsToSimpleInteger - If the specified expression does not fold
- /// to a constant, or if it does but contains a label, return 0. If it
- /// constant folds to 'true' and does not contain a label, return 1, if it
- /// constant folds to 'false' and does not contain a label, return -1.
- int ConstantFoldsToSimpleInteger(const Expr *Cond);
+ /// to a constant, or if it does but contains a label, return false. If it
+ /// constant folds return true and set the boolean result in Result.
+ bool ConstantFoldsToSimpleInteger(const Expr *Cond, bool &Result);
+ /// ConstantFoldsToSimpleInteger - If the specified expression does not fold
+ /// to a constant, or if it does but contains a label, return false. If it
+ /// constant folds return true and set the folded value.
+ bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APInt &Result);
+
/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an
/// if statement) to the specified blocks. Based on the condition, this might
/// try to simplify the codegen of the conditional based on the branch.
@@ -2061,12 +2098,12 @@ public:
llvm::BasicBlock *getTrapBB();
/// EmitCallArg - Emit a single call argument.
- RValue EmitCallArg(const Expr *E, QualType ArgType);
+ void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
/// EmitDelegateCallArg - We are performing a delegate call; that
/// is, the current function is delegating to another one. Produce
/// a r-value suitable for passing the given parameter.
- RValue EmitDelegateCallArg(const VarDecl *Param);
+ void EmitDelegateCallArg(CallArgList &args, const VarDecl *param);
private:
void EmitReturnOfRValue(RValue RV, QualType Ty);
@@ -2131,8 +2168,7 @@ private:
getContext().getCanonicalType(ActualArgType).getTypePtr() &&
"type mismatch in call argument!");
#endif
- Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
- ArgType));
+ EmitCallArg(Args, *Arg, ArgType);
}
// Either we've emitted all the call args, or we have a call to a
@@ -2143,11 +2179,8 @@ private:
}
// If we still have any arguments, emit them using the type of the argument.
- for (; Arg != ArgEnd; ++Arg) {
- QualType ArgType = Arg->getType();
- Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
- ArgType));
- }
+ for (; Arg != ArgEnd; ++Arg)
+ EmitCallArg(Args, *Arg, Arg->getType());
}
const TargetCodeGenInfo &getTargetHooks() const {
@@ -2155,6 +2188,10 @@ private:
}
void EmitDeclMetadata();
+
+ CodeGenModule::ByrefHelpers *
+ buildByrefHelpers(const llvm::StructType &byrefType,
+ const AutoVarEmission &emission);
};
/// 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 a8453c31d54e..83e927fcadbc 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -64,7 +64,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
ABI(createCXXABI(*this)),
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI),
TBAA(0),
- VTables(*this), Runtime(0),
+ VTables(*this), Runtime(0), DebugInfo(0),
CFConstantStringClassRef(0), ConstantStringClassRef(0),
VMContext(M.getContext()),
NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0),
@@ -72,22 +72,19 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
BlockObjectAssignDecl(0), BlockObjectDisposeDecl(0),
BlockObjectAssign(0), BlockObjectDispose(0),
BlockDescriptorType(0), GenericBlockLiteralType(0) {
- if (!Features.ObjC1)
- Runtime = 0;
- else if (!Features.NeXTRuntime)
- Runtime = CreateGNUObjCRuntime(*this);
- else if (Features.ObjCNonFragileABI)
- Runtime = CreateMacNonFragileABIObjCRuntime(*this);
- else
- Runtime = CreateMacObjCRuntime(*this);
+ if (Features.ObjC1)
+ createObjCRuntime();
// Enable TBAA unless it's suppressed.
if (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)
TBAA = new CodeGenTBAA(Context, VMContext, getLangOptions(),
ABI.getMangleContext());
- // If debug info generation is enabled, create the CGDebugInfo object.
- DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0;
+ // If debug info or coverage generation is enabled, create the CGDebugInfo
+ // object.
+ if (CodeGenOpts.DebugInfo || CodeGenOpts.EmitGcovArcs ||
+ CodeGenOpts.EmitGcovNotes)
+ DebugInfo = new CGDebugInfo(*this);
Block.GlobalUniqueCount = 0;
@@ -115,8 +112,6 @@ CodeGenModule::~CodeGenModule() {
void CodeGenModule::createObjCRuntime() {
if (!Features.NeXTRuntime)
Runtime = CreateGNUObjCRuntime(*this);
- else if (Features.ObjCNonFragileABI)
- Runtime = CreateMacNonFragileABIObjCRuntime(*this);
else
Runtime = CreateMacObjCRuntime(*this);
}
@@ -139,6 +134,13 @@ void CodeGenModule::Release() {
EmitDeclMetadata();
}
+void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
+ // Make sure that this type is translated.
+ Types.UpdateCompletedType(TD);
+ if (DebugInfo)
+ DebugInfo->UpdateCompletedType(TD);
+}
+
llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) {
if (!TBAA)
return 0;
@@ -151,7 +153,12 @@ void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
}
bool CodeGenModule::isTargetDarwin() const {
- return getContext().Target.getTriple().getOS() == llvm::Triple::Darwin;
+ return getContext().Target.getTriple().isOSDarwin();
+}
+
+void CodeGenModule::Error(SourceLocation loc, llvm::StringRef error) {
+ unsigned diagID = getDiags().getCustomDiagID(Diagnostic::Error, error);
+ getDiags().Report(Context.getFullLoc(loc), diagID);
}
/// ErrorUnsupported - Print out an error that codegen doesn't support the
@@ -220,7 +227,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
return;
// Don't override an explicit visibility attribute.
- if (RD->hasAttr<VisibilityAttr>())
+ if (RD->getExplicitVisibility())
return;
switch (RD->getTemplateSpecializationKind()) {
@@ -501,6 +508,13 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
llvm::Function *F,
bool IsIncompleteFunction) {
+ 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));
+ return;
+ }
+
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (!IsIncompleteFunction)
@@ -512,7 +526,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
if (FD->hasAttr<DLLImportAttr>()) {
F->setLinkage(llvm::Function::DLLImportLinkage);
} else if (FD->hasAttr<WeakAttr>() ||
- FD->hasAttr<WeakImportAttr>()) {
+ FD->isWeakImported()) {
// "extern_weak" is overloaded in LLVM; we probably should have
// separate linkage types for this.
F->setLinkage(llvm::Function::ExternalWeakLinkage);
@@ -989,7 +1003,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
} else {
if (D->hasAttr<DLLImportAttr>())
GV->setLinkage(llvm::GlobalValue::DLLImportLinkage);
- else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>())
+ else if (D->hasAttr<WeakAttr>() || D->isWeakImported())
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
// Set visibility on a declaration only if it's explicit.
@@ -1055,7 +1069,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
Ty = getTypes().ConvertTypeForMem(ASTTy);
const llvm::PointerType *PTy =
- llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
+ llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy));
llvm::StringRef MangledName = getMangledName(D);
return GetOrCreateLLVMGlobal(MangledName, PTy, D);
@@ -1066,7 +1080,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
llvm::Constant *
CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty,
llvm::StringRef Name) {
- return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0,
+ return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0,
true);
}
@@ -1234,7 +1248,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// from the type of the global (this happens with unions).
if (GV == 0 ||
GV->getType()->getElementType() != InitType ||
- GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) {
+ GV->getType()->getAddressSpace() !=
+ getContext().getTargetAddressSpace(ASTTy)) {
// Move the old entry aside so that we'll create a new one.
Entry->setName(llvm::StringRef());
@@ -1281,7 +1296,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
EmitCXXGlobalVarDeclInitFunc(D, GV);
// Emit global variable debug information.
- if (CGDebugInfo *DI = getDebugInfo()) {
+ if (CGDebugInfo *DI = getModuleDebugInfo()) {
DI->setLocation(D->getLocation());
DI->EmitGlobalVariable(GV, D);
}
@@ -1304,9 +1319,7 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
return llvm::GlobalVariable::WeakAnyLinkage;
} else if (Linkage == GVA_TemplateInstantiation ||
Linkage == GVA_ExplicitTemplateInstantiation)
- // FIXME: It seems like we can provide more specific linkage here
- // (LinkOnceODR, WeakODR).
- return llvm::GlobalVariable::WeakAnyLinkage;
+ return llvm::GlobalVariable::WeakODRLinkage;
else if (!getLangOptions().CPlusPlus &&
((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) ||
D->getAttr<CommonAttr>()) &&
@@ -1391,7 +1404,14 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
- const llvm::FunctionType *Ty = getTypes().GetFunctionType(GD);
+
+ // Compute the function info and LLVM type.
+ const CGFunctionInfo &FI = getTypes().getFunctionInfo(GD);
+ bool variadic = false;
+ if (const FunctionProtoType *fpt = D->getType()->getAs<FunctionProtoType>())
+ variadic = fpt->isVariadic();
+ const llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic, false);
+
// Get or create the prototype for the function.
llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);
@@ -1451,7 +1471,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
// FIXME: this is redundant with part of SetFunctionDefinitionAttributes
setGlobalVisibility(Fn, D);
- CodeGenFunction(*this).GenerateCode(D, Fn);
+ CodeGenFunction(*this).GenerateCode(D, Fn, FI);
SetFunctionDefinitionAttributes(D, Fn);
SetLLVMFunctionAttributesForDefinition(D, Fn);
@@ -1525,7 +1545,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
}
} else if (D->hasAttr<WeakAttr>() ||
D->hasAttr<WeakRefAttr>() ||
- D->hasAttr<WeakImportAttr>()) {
+ D->isWeakImported()) {
GA->setLinkage(llvm::Function::WeakAnyLinkage);
}
@@ -1662,7 +1682,10 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
// does make plain ascii ones writable.
isConstant = true;
} else {
- Linkage = llvm::GlobalValue::PrivateLinkage;
+ // FIXME: With OS X ld 123.2 (xcode 4) and LTO we would get a linker error
+ // when using private linkage. It is not clear if this is a bug in ld
+ // or a reasonable new restriction.
+ Linkage = llvm::GlobalValue::LinkerPrivateLinkage;
isConstant = !Features.WritableStrings;
}
@@ -1673,6 +1696,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
if (isUTF16) {
CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
GV->setAlignment(Align.getQuantity());
+ } else {
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
+ GV->setAlignment(Align.getQuantity());
}
Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
@@ -1765,6 +1791,9 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
if (isUTF16) {
CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
GV->setAlignment(Align.getQuantity());
+ } else {
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
+ GV->setAlignment(Align.getQuantity());
}
Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
@@ -1835,7 +1864,7 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
/// GenerateWritableString -- Creates storage for a string literal.
-static llvm::Constant *GenerateStringLiteral(const std::string &str,
+static llvm::Constant *GenerateStringLiteral(llvm::StringRef str,
bool constant,
CodeGenModule &CGM,
const char *GlobalName) {
@@ -1860,7 +1889,7 @@ static llvm::Constant *GenerateStringLiteral(const std::string &str,
/// Feature.WriteableStrings.
///
/// The result has pointer to array type.
-llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str,
+llvm::Constant *CodeGenModule::GetAddrOfConstantString(llvm::StringRef Str,
const char *GlobalName) {
bool IsConstant = !Features.WritableStrings;
@@ -1870,26 +1899,27 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str,
// Don't share any string literals if strings aren't constant.
if (!IsConstant)
- return GenerateStringLiteral(str, false, *this, GlobalName);
+ return GenerateStringLiteral(Str, false, *this, GlobalName);
llvm::StringMapEntry<llvm::Constant *> &Entry =
- ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]);
+ ConstantStringMap.GetOrCreateValue(Str);
if (Entry.getValue())
return Entry.getValue();
// Create a global variable for this.
- llvm::Constant *C = GenerateStringLiteral(str, true, *this, GlobalName);
+ llvm::Constant *C = GenerateStringLiteral(Str, true, *this, GlobalName);
Entry.setValue(C);
return C;
}
/// GetAddrOfConstantCString - Returns a pointer to a character
-/// array containing the literal and a terminating '\-'
+/// array containing the literal and a terminating '\0'
/// character. The result has pointer to array type.
-llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str,
+llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str,
const char *GlobalName){
- return GetAddrOfConstantString(str + '\0', GlobalName);
+ llvm::StringRef StrWithNull(Str.c_str(), Str.size() + 1);
+ return GetAddrOfConstantString(StrWithNull, GlobalName);
}
/// EmitObjCPropertyImplementations - Emit information for synthesized
@@ -1920,37 +1950,48 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
}
}
+static bool needsDestructMethod(ObjCImplementationDecl *impl) {
+ ObjCInterfaceDecl *iface
+ = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface());
+ for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
+ ivar; ivar = ivar->getNextIvar())
+ if (ivar->getType().isDestructedType())
+ return true;
+
+ return false;
+}
+
/// EmitObjCIvarInitializations - Emit information for ivar initialization
/// for an implementation.
void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
- if (!Features.NeXTRuntime || D->getNumIvarInitializers() == 0)
+ // We might need a .cxx_destruct even if we don't have any ivar initializers.
+ if (needsDestructMethod(D)) {
+ IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
+ Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
+ ObjCMethodDecl *DTORMethod =
+ ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
+ cxxSelector, getContext().VoidTy, 0, D, true,
+ false, true, false, ObjCMethodDecl::Required);
+ D->addInstanceMethod(DTORMethod);
+ CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
+ }
+
+ // If the implementation doesn't have any ivar initializers, we don't need
+ // a .cxx_construct.
+ if (D->getNumIvarInitializers() == 0)
return;
- DeclContext* DC = const_cast<DeclContext*>(dyn_cast<DeclContext>(D));
- assert(DC && "EmitObjCIvarInitializations - null DeclContext");
- IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
- Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
- ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(),
- D->getLocation(),
- D->getLocation(), cxxSelector,
- getContext().VoidTy, 0,
- DC, true, false, true, false,
- ObjCMethodDecl::Required);
- D->addInstanceMethod(DTORMethod);
- CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
- II = &getContext().Idents.get(".cxx_construct");
- cxxSelector = getContext().Selectors.getSelector(0, &II);
+ IdentifierInfo *II = &getContext().Idents.get(".cxx_construct");
+ Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
// The constructor returns 'self'.
ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
D->getLocation(),
D->getLocation(), cxxSelector,
getContext().getObjCIdType(), 0,
- DC, true, false, true, false,
+ D, true, false, true, false,
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
-
-
}
/// EmitNamespace - Emit all declarations in a namespace.
@@ -1990,7 +2031,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::CXXMethod:
case Decl::Function:
// Skip function templates
- if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate())
+ if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
+ cast<FunctionDecl>(D)->isLateTemplateParsed())
return;
EmitGlobal(cast<FunctionDecl>(D));
@@ -2000,6 +2042,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitGlobal(cast<VarDecl>(D));
break;
+ // Indirect fields from global anonymous structs and unions can be
+ // ignored; only the actual variable requires IR gen support.
+ case Decl::IndirectField:
+ break;
+
// C++ Decls
case Decl::Namespace:
EmitNamespace(cast<NamespaceDecl>(D));
@@ -2014,12 +2061,15 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
case Decl::CXXConstructor:
// Skip function templates
- if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate())
+ if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() ||
+ cast<FunctionDecl>(D)->isLateTemplateParsed())
return;
EmitCXXConstructors(cast<CXXConstructorDecl>(D));
break;
case Decl::CXXDestructor:
+ if (cast<FunctionDecl>(D)->isLateTemplateParsed())
+ return;
EmitCXXDestructors(cast<CXXDestructorDecl>(D));
break;
@@ -2035,13 +2085,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::ObjCInterface:
break;
- case Decl::ObjCCategory: {
- ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
- if (CD->IsClassExtension() && CD->hasSynthBitfield())
- Context.ResetObjCLayout(CD->getClassInterface());
- break;
- }
-
+ case Decl::ObjCCategory: {
+ ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
+ if (CD->IsClassExtension() && CD->hasSynthBitfield())
+ Context.ResetObjCLayout(CD->getClassInterface());
+ break;
+ }
case Decl::ObjCProtocol:
Runtime->GenerateProtocol(cast<ObjCProtocolDecl>(D));
@@ -2118,7 +2167,7 @@ static void EmitGlobalDeclMetadata(CodeGenModule &CGM,
Addr,
GetPointerConstant(CGM.getLLVMContext(), D.getDecl())
};
- GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops, 2));
+ GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops));
}
/// Emits metadata nodes associating all the global values in the
@@ -2159,7 +2208,7 @@ void CodeGenFunction::EmitDeclMetadata() {
if (llvm::AllocaInst *Alloca = dyn_cast<llvm::AllocaInst>(Addr)) {
llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D);
- Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, &DAddr, 1));
+ Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, DAddr));
} else if (llvm::GlobalValue *GV = dyn_cast<llvm::GlobalValue>(Addr)) {
GlobalDecl GD = GlobalDecl(cast<VarDecl>(D));
EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 73e6ece14732..99c973cce628 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -20,7 +20,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
-#include "CGCall.h"
#include "CGVTables.h"
#include "CodeGenTypes.h"
#include "GlobalDecl.h"
@@ -69,12 +68,14 @@ namespace clang {
namespace CodeGen {
+ class CallArgList;
class CodeGenFunction;
class CodeGenTBAA;
class CGCXXABI;
class CGDebugInfo;
class CGObjCRuntime;
class BlockFieldFlags;
+ class FunctionArgList;
struct OrderGlobalInits {
unsigned int priority;
@@ -246,9 +247,6 @@ class CodeGenModule : public CodeGenTypeCache {
int GlobalUniqueCount;
} Block;
- llvm::DenseMap<uint64_t, llvm::Constant *> AssignCache;
- llvm::DenseMap<uint64_t, llvm::Constant *> DestroyCache;
-
/// @}
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
@@ -281,7 +279,8 @@ public:
StaticLocalDeclMap[D] = GV;
}
- CGDebugInfo *getDebugInfo() { return DebugInfo; }
+ CGDebugInfo *getModuleDebugInfo() { return DebugInfo; }
+
ASTContext &getContext() const { return Context; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
const LangOptions &getLangOptions() const { return Features; }
@@ -311,6 +310,7 @@ public:
enum TypeVisibilityKind {
TVK_ForVTT,
TVK_ForVTable,
+ TVK_ForConstructionVTable,
TVK_ForRTTI,
TVK_ForRTTIName
};
@@ -358,6 +358,7 @@ public:
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
const llvm::Type *Ty = 0);
+
/// GetAddrOfFunction - Return the address of the given function. If Ty is
/// non-null, then this function will use the specified type if it has to
/// create it.
@@ -382,14 +383,35 @@ public:
CastExpr::path_const_iterator PathBegin,
CastExpr::path_const_iterator PathEnd);
- llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T,
- BlockFieldFlags flags,
- unsigned Align,
- const VarDecl *variable);
- llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T,
- BlockFieldFlags flags,
- unsigned Align,
- const VarDecl *variable);
+ /// A pair of helper functions for a __block variable.
+ class ByrefHelpers : public llvm::FoldingSetNode {
+ public:
+ llvm::Constant *CopyHelper;
+ llvm::Constant *DisposeHelper;
+
+ /// The alignment of the field. This is important because
+ /// different offsets to the field within the byref struct need to
+ /// have different helper functions.
+ CharUnits Alignment;
+
+ ByrefHelpers(CharUnits alignment) : Alignment(alignment) {}
+ virtual ~ByrefHelpers();
+
+ void Profile(llvm::FoldingSetNodeID &id) const {
+ id.AddInteger(Alignment.getQuantity());
+ profileImpl(id);
+ }
+ virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0;
+
+ virtual bool needsCopy() const { return true; }
+ virtual void emitCopy(CodeGenFunction &CGF,
+ llvm::Value *dest, llvm::Value *src) = 0;
+
+ virtual bool needsDispose() const { return true; }
+ virtual void emitDispose(CodeGenFunction &CGF, llvm::Value *field) = 0;
+ };
+
+ llvm::FoldingSet<ByrefHelpers> ByrefHelpersCache;
/// getUniqueBlockCount - Fetches the global unique block count.
int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; }
@@ -437,7 +459,7 @@ public:
///
/// \param GlobalName If provided, the name to use for the global
/// (if one is created).
- llvm::Constant *GetAddrOfConstantString(const std::string& str,
+ llvm::Constant *GetAddrOfConstantString(llvm::StringRef Str,
const char *GlobalName=0);
/// GetAddrOfConstantCString - Returns a pointer to a character array
@@ -451,13 +473,15 @@ public:
/// GetAddrOfCXXConstructor - Return the address of the constructor of the
/// given type.
- llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
- CXXCtorType Type);
+ llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
+ CXXCtorType ctorType,
+ const CGFunctionInfo *fnInfo = 0);
/// GetAddrOfCXXDestructor - Return the address of the constructor of the
/// given type.
- llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
- CXXDtorType Type);
+ llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
+ CXXDtorType dtorType,
+ const CGFunctionInfo *fnInfo = 0);
/// getBuiltinLibFunction - Given a builtin id for a function like
/// "__builtin_fabsf", return a Function* for "fabsf".
@@ -502,10 +526,8 @@ public:
///@}
- void UpdateCompletedType(const TagDecl *TD) {
- // Make sure that this type is translated.
- Types.UpdateCompletedType(TD);
- }
+ // UpdateCompleteType - Make sure that this type is translated.
+ void UpdateCompletedType(const TagDecl *TD);
llvm::Constant *getMemberPointerConstant(const UnaryOperator *e);
@@ -523,6 +545,9 @@ public:
llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
const AnnotateAttr *AA, unsigned LineNo);
+ /// Error - Emit a general error that something can't be done.
+ void Error(SourceLocation loc, llvm::StringRef error);
+
/// ErrorUnsupported - Print out an error that codegen doesn't support the
/// specified stmt yet.
/// \param OmitOnError - If true, then this error should only be emitted if no
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 3f2c6cabf2ae..53e40b2238b3 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -74,7 +74,8 @@ llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(llvm::StringRef NameStr,
};
// Create the mdnode.
- return llvm::MDNode::get(VMContext, Ops, llvm::array_lengthof(Ops) - !Flags);
+ unsigned Len = llvm::array_lengthof(Ops) - !Flags;
+ return llvm::MDNode::get(VMContext, llvm::ArrayRef<llvm::Value*>(Ops, Len));
}
static bool TypeHasMayAlias(QualType QTy) {
@@ -155,7 +156,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
// theoretically implement this by combining information about all the
// members into a single identifying MDNode.
if (!Features.CPlusPlus &&
- ETy->getDecl()->getTypedefForAnonDecl())
+ ETy->getDecl()->getTypedefNameForAnonDecl())
return MetadataCache[Ty] = getChar();
// In C++ mode, types have linkage, so we can rely on the ODR and
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 5254922f13a1..8db6fe518684 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -65,6 +65,36 @@ void CodeGenTypes::HandleLateResolvedPointers() {
}
}
+void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, const llvm::Type *Ty,
+ llvm::StringRef suffix) {
+ llvm::SmallString<256> TypeName;
+ llvm::raw_svector_ostream OS(TypeName);
+ OS << RD->getKindName() << '.';
+
+ // Name the codegen type after the typedef name
+ // if there is no tag type name available
+ if (RD->getIdentifier()) {
+ // FIXME: We should not have to check for a null decl context here.
+ // Right now we do it because the implicit Obj-C decls don't have one.
+ if (RD->getDeclContext())
+ OS << RD->getQualifiedNameAsString();
+ else
+ RD->printName(OS);
+ } else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) {
+ // FIXME: We should not have to check for a null decl context here.
+ // Right now we do it because the implicit Obj-C decls don't have one.
+ if (TDD->getDeclContext())
+ OS << TDD->getQualifiedNameAsString();
+ else
+ TDD->printName(OS);
+ } else
+ OS << "anon";
+
+ if (!suffix.empty())
+ OS << suffix;
+
+ TheModule.addTypeName(OS.str(), Ty);
+}
/// ConvertType - Convert the specified type to its LLVM form.
const llvm::Type *CodeGenTypes::ConvertType(QualType T, bool IsRecursive) {
@@ -199,7 +229,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
- assert(false && "Non-canonical or dependent types aren't possible.");
+ llvm_unreachable("Non-canonical or dependent types aren't possible.");
break;
case Type::Builtin: {
@@ -253,10 +283,12 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- assert(0 && "Unexpected builtin type!");
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ llvm_unreachable("Unexpected placeholder builtin type!");
break;
}
- assert(0 && "Unknown builtin type!");
+ llvm_unreachable("Unknown builtin type!");
break;
}
case Type::Complex: {
@@ -270,14 +302,16 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
QualType ETy = RTy.getPointeeType();
llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
- return llvm::PointerType::get(PointeeType, ETy.getAddressSpace());
+ unsigned AS = Context.getTargetAddressSpace(ETy);
+ return llvm::PointerType::get(PointeeType, AS);
}
case Type::Pointer: {
const PointerType &PTy = cast<PointerType>(Ty);
QualType ETy = PTy.getPointeeType();
llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
- return llvm::PointerType::get(PointeeType, ETy.getAddressSpace());
+ unsigned AS = Context.getTargetAddressSpace(ETy);
+ return llvm::PointerType::get(PointeeType, AS);
}
case Type::VariableArray: {
@@ -371,30 +405,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
const TagDecl *TD = cast<TagType>(Ty).getDecl();
const llvm::Type *Res = ConvertTagDeclType(TD);
- llvm::SmallString<256> TypeName;
- llvm::raw_svector_ostream OS(TypeName);
- OS << TD->getKindName() << '.';
-
- // Name the codegen type after the typedef name
- // if there is no tag type name available
- if (TD->getIdentifier()) {
- // FIXME: We should not have to check for a null decl context here.
- // Right now we do it because the implicit Obj-C decls don't have one.
- if (TD->getDeclContext())
- OS << TD->getQualifiedNameAsString();
- else
- TD->printName(OS);
- } else if (const TypedefDecl *TDD = TD->getTypedefForAnonDecl()) {
- // FIXME: We should not have to check for a null decl context here.
- // Right now we do it because the implicit Obj-C decls don't have one.
- if (TDD->getDeclContext())
- OS << TDD->getQualifiedNameAsString();
- else
- TDD->printName(OS);
- } else
- OS << "anon";
-
- TheModule.addTypeName(OS.str(), Res);
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(TD))
+ addRecordTypeName(RD, Res, llvm::StringRef());
return Res;
}
@@ -402,7 +414,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType();
llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
PointersToResolve.push_back(std::make_pair(FTy, PointeeType));
- return llvm::PointerType::get(PointeeType, FTy.getAddressSpace());
+ unsigned AS = Context.getTargetAddressSpace(FTy);
+ return llvm::PointerType::get(PointeeType, AS);
}
case Type::MemberPointer: {
@@ -500,6 +513,15 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
return *Layout;
}
+void CodeGenTypes::addBaseSubobjectTypeName(const CXXRecordDecl *RD,
+ const CGRecordLayout &layout) {
+ llvm::StringRef suffix;
+ if (layout.getBaseSubobjectLLVMType() != layout.getLLVMType())
+ suffix = ".base";
+
+ addRecordTypeName(RD, layout.getBaseSubobjectLLVMType(), suffix);
+}
+
bool CodeGenTypes::isZeroInitializable(QualType T) {
// No need to check for member pointers when not compiling C++.
if (!Context.getLangOptions().CPlusPlus)
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 41513daf17ca..dc383cb4db5d 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -101,6 +101,11 @@ private:
/// used to handle cyclic structures properly.
void HandleLateResolvedPointers();
+ /// addRecordTypeName - Compute a name from the given record decl with an
+ /// optional suffix and name the given LLVM type using it.
+ void addRecordTypeName(const RecordDecl *RD, const llvm::Type *Ty,
+ llvm::StringRef suffix);
+
public:
CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD,
const ABIInfo &Info, CGCXXABI &CXXABI);
@@ -145,10 +150,19 @@ public:
const CGRecordLayout &getCGRecordLayout(const RecordDecl*);
+ /// addBaseSubobjectTypeName - Add a type name for the base subobject of the
+ /// given record layout.
+ void addBaseSubobjectTypeName(const CXXRecordDecl *RD,
+ const CGRecordLayout &layout);
+
/// UpdateCompletedType - When we find the full definition for a TagDecl,
/// replace the 'opaque' type we previously made for it if applicable.
void UpdateCompletedType(const TagDecl *TD);
+ /// getNullaryFunctionInfo - Get the function info for a void()
+ /// function with standard CC.
+ const CGFunctionInfo &getNullaryFunctionInfo();
+
/// getFunctionInfo - Get the function info for the specified function decl.
const CGFunctionInfo &getFunctionInfo(GlobalDecl GD);
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 95654a33a125..33abf3a4aaf7 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ code generation targetting the Itanium C++ ABI. The class
+// This provides C++ code generation targeting the Itanium C++ ABI. The class
// in this file generates structures that follow the Itanium C++ ABI, which is
// documented at:
// http://www.codesourcery.com/public/cxx-abi/abi.html
@@ -282,8 +282,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
// We're done.
CGF.EmitBlock(FnEnd);
- llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
- Callee->reserveOperandSpace(2);
+ llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo(), 2);
Callee->addIncoming(VirtualFn, FnVirtual);
Callee->addIncoming(NonVirtualFn, FnNonVirtual);
return Callee;
@@ -515,10 +514,10 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
if (MD->isVirtual()) {
uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD);
- // FIXME: We shouldn't use / 8 here.
- uint64_t PointerWidthInBytes =
- getContext().Target.getPointerWidth(0) / 8;
- uint64_t VTableOffset = (Index * PointerWidthInBytes);
+ const ASTContext &Context = getContext();
+ CharUnits PointerWidth =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ uint64_t VTableOffset = (Index * PointerWidth.getQuantity());
if (IsARM) {
// ARM C++ ABI 3.2.1:
@@ -538,20 +537,21 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
}
} else {
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
const llvm::Type *Ty;
// Check whether the function has a computable LLVM signature.
if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
// The function has a computable LLVM signature; use the correct type.
- Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic());
+ Ty = Types.GetFunctionType(Types.getFunctionInfo(MD),
+ FPT->isVariadic());
} else {
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
// function type is incomplete.
Ty = ptrdiff_t;
}
+ llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
- llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty);
- MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t);
+ MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t);
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
}
@@ -651,20 +651,21 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool");
}
- // In Itanium, a member function pointer is null if 'ptr' is null.
+ // In Itanium, a member function pointer is not null if 'ptr' is not null.
llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr");
llvm::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0);
llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool");
- // In ARM, it's that, plus the low bit of 'adj' must be zero.
+ // On ARM, a member function pointer is also non-null if the low bit of 'adj'
+ // (the virtual bit) is set.
if (IsARM) {
llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1);
llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj");
llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit");
- llvm::Value *IsNotVirtual = Builder.CreateICmpEQ(VirtualBit, Zero,
- "memptr.notvirtual");
- Result = Builder.CreateAnd(Result, IsNotVirtual);
+ llvm::Value *IsVirtual = Builder.CreateICmpNE(VirtualBit, Zero,
+ "memptr.isvirtual");
+ Result = Builder.CreateOr(Result, IsVirtual);
}
return Result;
@@ -745,7 +746,7 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
ImplicitParamDecl *VTTDecl
= ImplicitParamDecl::Create(Context, 0, MD->getLocation(),
&Context.Idents.get("vtt"), T);
- Params.push_back(std::make_pair(VTTDecl, VTTDecl->getType()));
+ Params.push_back(VTTDecl);
getVTTDecl(CGF) = VTTDecl;
}
}
@@ -757,7 +758,7 @@ void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
// Return 'this' from certain constructors and destructors.
if (HasThisReturn(CGF.CurGD))
- ResTy = Params[0].second;
+ ResTy = Params[0]->getType();
}
void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
@@ -1064,10 +1065,18 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// global initialization is always single-threaded.
bool ThreadsafeStatics = (getContext().getLangOptions().ThreadsafeStatics &&
D.isLocalVarDecl());
-
- // Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
- const llvm::IntegerType *GuardTy
- = (IsARM ? Builder.getInt32Ty() : Builder.getInt64Ty());
+
+ const llvm::IntegerType *GuardTy;
+
+ // If we have a global variable with internal linkage and thread-safe statics
+ // are disabled, we can just let the guard variable be of type i8.
+ bool UseInt8GuardVariable = !ThreadsafeStatics && GV->hasInternalLinkage();
+ if (UseInt8GuardVariable)
+ GuardTy = Builder.getInt8Ty();
+ else {
+ // Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
+ GuardTy = (IsARM ? Builder.getInt32Ty() : Builder.getInt64Ty());
+ }
const llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo();
// Create the guard variable.
@@ -1098,7 +1107,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// if (__cxa_guard_acquire(&obj_guard))
// ...
// }
- if (IsARM) {
+ if (IsARM && !UseInt8GuardVariable) {
llvm::Value *V = Builder.CreateLoad(GuardVariable);
V = Builder.CreateAnd(V, Builder.getInt32(1));
IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 3a63eba39741..747e5e3222c2 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This provides C++ code generation targetting the Microsoft Visual C++ ABI.
+// This provides C++ code generation targeting the Microsoft Visual C++ ABI.
// The class in this file generates structures that follow the Microsoft
// Visual C++ ABI, which is actually not very well documented at all outside
// of Microsoft.
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 2ffc840b9f92..bc2472cebbeb 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -16,6 +16,7 @@
#include "ABIInfo.h"
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Type.h"
#include "llvm/Target/TargetData.h"
#include "llvm/ADT/Triple.h"
@@ -358,7 +359,7 @@ bool UseX86_MMXType(const llvm::Type *IRType) {
static const llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
llvm::StringRef Constraint,
const llvm::Type* Ty) {
- if (Constraint=="y" && Ty->isVectorTy())
+ if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy())
return llvm::Type::getX86_MMXTy(CGF.getLLVMContext());
return Ty;
}
@@ -864,6 +865,15 @@ class X86_64ABIInfo : public ABIInfo {
unsigned &neededInt,
unsigned &neededSSE) const;
+ /// The 0.98 ABI revision clarified a lot of ambiguities,
+ /// unfortunately in ways that were not always consistent with
+ /// certain previous compilers. In particular, platforms which
+ /// required strict binary compatibility with older versions of GCC
+ /// may need to exempt themselves.
+ bool honorsRevision0_98() const {
+ return !getContext().Target.getTriple().isOSDarwin();
+ }
+
public:
X86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
@@ -1252,15 +1262,24 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
// (a) If one of the classes is MEMORY, the whole argument is
// passed in memory.
//
- // (b) If SSEUP is not preceeded by SSE, it is converted to SSE.
-
- // The first of these conditions is guaranteed by how we implement
- // the merge (just bail).
+ // (b) If X87UP is not preceded by X87, the whole argument is
+ // passed in memory.
+ //
+ // (c) If the size of the aggregate exceeds two eightbytes and the first
+ // eight-byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole
+ // argument is passed in memory.
+ //
+ // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.
+ //
+ // Some of these are enforced by the merging logic. Others can arise
+ // only with unions; for example:
+ // union { _Complex double; unsigned; }
//
- // The second condition occurs in the case of unions; for example
- // union { _Complex double; unsigned; }.
+ // Note that clauses (b) and (c) were added in 0.98.
if (Hi == Memory)
Lo = Memory;
+ if (Hi == X87Up && Lo != X87 && honorsRevision0_98())
+ Lo = Memory;
if (Hi == SSEUp && Lo != SSE)
Hi = SSE;
}
@@ -1689,7 +1708,7 @@ classifyReturnType(QualType RetTy) const {
// AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
// is passed in the upper half of the last used SSE register.
//
- // SSEUP should always be preceeded by SSE, just widen.
+ // SSEUP should always be preceded by SSE, just widen.
case SSEUp:
assert(Lo == SSE && "Unexpected SSEUp classification.");
ResType = Get16ByteVectorType(RetTy);
@@ -1698,9 +1717,9 @@ classifyReturnType(QualType RetTy) const {
// AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
// returned together with the previous X87 value in %st0.
case X87Up:
- // If X87Up is preceeded by X87, we don't need to do
+ // If X87Up is preceded by X87, we don't need to do
// anything. However, in some cases with unions it may not be
- // preceeded by X87. In such situations we follow gcc and pass the
+ // preceded by X87. In such situations we follow gcc and pass the
// extra bits in an SSE reg.
if (Lo != X87) {
HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy),
@@ -1799,7 +1818,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
const llvm::Type *HighPart = 0;
switch (Hi) {
// Memory was handled previously, ComplexX87 and X87 should
- // never occur as hi classes, and X87Up must be preceed by X87,
+ // never occur as hi classes, and X87Up must be preceded by X87,
// which is passed in memory.
case Memory:
case X87:
@@ -2082,9 +2101,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// Return the appropriate result.
CGF.EmitBlock(ContBlock);
- llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(),
+ llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), 2,
"vaarg.addr");
- ResAddr->reserveOperandSpace(2);
ResAddr->addIncoming(RegAddr, InRegBlock);
ResAddr->addIncoming(MemAddr, InMemBlock);
return ResAddr;
@@ -2271,27 +2289,33 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
it != ie; ++it)
it->info = classifyArgumentType(it->type);
- const llvm::Triple &Triple(getContext().Target.getTriple());
+ // Always honor user-specified calling convention.
+ if (FI.getCallingConvention() != llvm::CallingConv::C)
+ return;
+
+ // Calling convention as default by an ABI.
llvm::CallingConv::ID DefaultCC;
- if (Triple.getEnvironmentName() == "gnueabi" ||
- Triple.getEnvironmentName() == "eabi")
+ llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName();
+ if (Env == "gnueabi" || Env == "eabi")
DefaultCC = llvm::CallingConv::ARM_AAPCS;
else
DefaultCC = llvm::CallingConv::ARM_APCS;
+ // If user did not ask for specific calling convention explicitly (e.g. via
+ // pcs attribute), set effective calling convention if it's different than ABI
+ // default.
switch (getABIKind()) {
case APCS:
if (DefaultCC != llvm::CallingConv::ARM_APCS)
FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
break;
-
case AAPCS:
if (DefaultCC != llvm::CallingConv::ARM_AAPCS)
FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
break;
-
case AAPCS_VFP:
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
+ if (DefaultCC != llvm::CallingConv::ARM_AAPCS_VFP)
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
break;
}
}
@@ -2317,22 +2341,26 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
// Otherwise, pass by coercing to a structure of the appropriate size.
//
- // FIXME: This is kind of nasty... but there isn't much choice because the ARM
- // backend doesn't support byval.
// FIXME: This doesn't handle alignment > 64 bits.
const llvm::Type* ElemTy;
unsigned SizeRegs;
- if (getContext().getTypeAlign(Ty) > 32) {
- ElemTy = llvm::Type::getInt64Ty(getVMContext());
- SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64;
- } else {
+ if (getContext().getTypeSizeInChars(Ty) <= CharUnits::fromQuantity(64)) {
ElemTy = llvm::Type::getInt32Ty(getVMContext());
SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+ } else if (getABIKind() == ARMABIInfo::APCS) {
+ // Initial ARM ByVal support is APCS-only.
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/true);
+ } else {
+ // FIXME: This is kind of nasty... but there isn't much choice
+ // because most of the ARM calling conventions don't yet support
+ // byval.
+ ElemTy = llvm::Type::getInt64Ty(getVMContext());
+ SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64;
}
- std::vector<const llvm::Type*> LLVMFields;
- LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs));
- const llvm::Type* STy = llvm::StructType::get(getVMContext(), LLVMFields,
- true);
+
+ const llvm::Type *STy =
+ llvm::StructType::get(getVMContext(),
+ llvm::ArrayType::get(ElemTy, SizeRegs), NULL, NULL);
return ABIArgInfo::getDirect(STy);
}
@@ -2516,6 +2544,74 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
}
//===----------------------------------------------------------------------===//
+// PTX ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class PTXABIInfo : public ABIInfo {
+public:
+ PTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType Ty) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CFG) const;
+};
+
+class PTXTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ PTXTargetCodeGenInfo(CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new PTXABIInfo(CGT)) {}
+};
+
+ABIArgInfo PTXABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+ if (isAggregateTypeForABI(RetTy))
+ return ABIArgInfo::getIndirect(0);
+ return ABIArgInfo::getDirect();
+}
+
+ABIArgInfo PTXABIInfo::classifyArgumentType(QualType Ty) const {
+ if (isAggregateTypeForABI(Ty))
+ return ABIArgInfo::getIndirect(0);
+
+ return ABIArgInfo::getDirect();
+}
+
+void PTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type);
+
+ // Always honor user-specified calling convention.
+ if (FI.getCallingConvention() != llvm::CallingConv::C)
+ return;
+
+ // Calling convention as default by an ABI.
+ llvm::CallingConv::ID DefaultCC;
+ llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName();
+ if (Env == "device")
+ DefaultCC = llvm::CallingConv::PTX_Device;
+ else
+ DefaultCC = llvm::CallingConv::PTX_Kernel;
+
+ FI.setEffectiveCallingConvention(DefaultCC);
+}
+
+llvm::Value *PTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CFG) const {
+ llvm_unreachable("PTX does not support varargs");
+ return 0;
+}
+
+}
+
+//===----------------------------------------------------------------------===//
// SystemZ ABI Implementation
//===----------------------------------------------------------------------===//
@@ -2815,17 +2911,24 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::arm:
case llvm::Triple::thumb:
- // FIXME: We want to know the float calling convention as well.
- if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0)
- return *(TheTargetCodeGenInfo =
- new ARMTargetCodeGenInfo(Types, ARMABIInfo::APCS));
+ {
+ ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS;
- return *(TheTargetCodeGenInfo =
- new ARMTargetCodeGenInfo(Types, ARMABIInfo::AAPCS));
+ if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0)
+ Kind = ARMABIInfo::APCS;
+ else if (CodeGenOpts.FloatABI == "hard")
+ Kind = ARMABIInfo::AAPCS_VFP;
+
+ return *(TheTargetCodeGenInfo = new ARMTargetCodeGenInfo(Types, Kind));
+ }
case llvm::Triple::ppc:
return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
+ case llvm::Triple::ptx32:
+ case llvm::Triple::ptx64:
+ return *(TheTargetCodeGenInfo = new PTXTargetCodeGenInfo(Types));
+
case llvm::Triple::systemz:
return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types));
@@ -2836,10 +2939,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types));
case llvm::Triple::x86:
- switch (Triple.getOS()) {
- case llvm::Triple::Darwin:
+ if (Triple.isOSDarwin())
return *(TheTargetCodeGenInfo =
new X86_32TargetCodeGenInfo(Types, true, true));
+
+ switch (Triple.getOS()) {
case llvm::Triple::Cygwin:
case llvm::Triple::MinGW32:
case llvm::Triple::AuroraUX:
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 5619212d38bb..2657faa0d3a7 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -101,6 +101,12 @@ bool Compilation::CleanupFileList(const ArgStringList &Files,
llvm::sys::Path P(*it);
std::string Error;
+ // Don't try to remove files which we don't have write access to (but may be
+ // able to remove). Underlying tools may have intentionally not overwritten
+ // them.
+ if (!P.canWrite())
+ continue;
+
if (P.eraseFromDisk(false, &Error)) {
// Failure is only failure if the file exists and is "regular". There is
// a race condition here due to the limited interface of
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 5a5986b5bc2b..fc4d86c861c8 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -30,6 +30,7 @@
#include "clang/Basic/Version.h"
#include "llvm/Config/config.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -42,13 +43,6 @@
#include <map>
-#ifdef __CYGWIN__
-#include <cygwin/version.h>
-#if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007
-#define IS_CYGWIN15 1
-#endif
-#endif
-
using namespace clang::driver;
using namespace clang;
@@ -58,15 +52,17 @@ Driver::Driver(llvm::StringRef _ClangExecutable,
bool IsProduction, bool CXXIsProduction,
Diagnostic &_Diags)
: Opts(createDriverOptTable()), Diags(_Diags),
- ClangExecutable(_ClangExecutable), DefaultHostTriple(_DefaultHostTriple),
- DefaultImageName(_DefaultImageName),
+ ClangExecutable(_ClangExecutable), UseStdLib(true),
+ DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName),
DriverTitle("clang \"gcc-compatible\" driver"),
Host(0),
- CCPrintOptionsFilename(0), CCPrintHeadersFilename(0), CCCIsCXX(false),
- CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false),
- CCPrintHeaders(false), CCCGenericGCCName("gcc"),
- CheckInputsExist(true), CCCUseClang(true), CCCUseClangCXX(true),
- CCCUseClangCPP(true), CCCUsePCH(true), SuppressMissingInputWarning(false) {
+ CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
+ CCLogDiagnosticsFilename(0), CCCIsCXX(false),
+ CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false),
+ CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
+ CCCGenericGCCName(""), CheckInputsExist(true), CCCUseClang(true),
+ CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true),
+ SuppressMissingInputWarning(false) {
if (IsProduction) {
// In a "production" build, only use clang on architectures we expect to
// work, and don't use clang C++.
@@ -100,11 +96,10 @@ Driver::~Driver() {
delete Host;
}
-InputArgList *Driver::ParseArgStrings(const char **ArgBegin,
- const char **ArgEnd) {
+InputArgList *Driver::ParseArgStrings(llvm::ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
unsigned MissingArgIndex, MissingArgCount;
- InputArgList *Args = getOpts().ParseArgs(ArgBegin, ArgEnd,
+ InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(),
MissingArgIndex, MissingArgCount);
// Check for missing argument error.
@@ -206,7 +201,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
return DAL;
}
-Compilation *Driver::BuildCompilation(int argc, const char **argv) {
+Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Compilation construction");
// FIXME: Handle environment options which effect driver behavior, somewhere
@@ -218,9 +213,7 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintOptions = false, CCCPrintActions = false;
- const char **Start = argv + 1, **End = argv + argc;
-
- InputArgList *Args = ParseArgStrings(Start, End);
+ InputArgList *Args = ParseArgStrings(ArgList.slice(1));
// -no-canonical-prefixes is used very early in main.
Args->ClaimAllArgs(options::OPT_no_canonical_prefixes);
@@ -238,13 +231,6 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases);
CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings);
CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX;
- if (CCCIsCXX) {
-#ifdef IS_CYGWIN15
- CCCGenericGCCName = "g++-4";
-#else
- CCCGenericGCCName = "g++";
-#endif
- }
CCCEcho = Args->hasArg(options::OPT_ccc_echo);
if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name))
CCCGenericGCCName = A->getValue(*Args);
@@ -287,6 +273,10 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
A->claim();
PrefixDirs.push_back(A->getValue(*Args, 0));
}
+ if (const Arg *A = Args->getLastArg(options::OPT__sysroot_EQ))
+ SysRoot = A->getValue(*Args);
+ if (Args->hasArg(options::OPT_nostdlib))
+ UseStdLib = false;
Host = GetHostInfo(DefaultHostTriple.c_str());
@@ -593,7 +583,7 @@ static bool ContainsCompileAction(const Action *A) {
}
void Driver::BuildUniversalActions(const ToolChain &TC,
- const ArgList &Args,
+ const DerivedArgList &Args,
ActionList &Actions) const {
llvm::PrettyStackTraceString CrashInfo("Building universal build actions");
// Collect the list of architectures. Duplicates are allowed, but should only
@@ -688,7 +678,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
}
}
-void Driver::BuildActions(const ToolChain &TC, const ArgList &Args,
+void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
ActionList &Actions) const {
llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
// Start by constructing the list of inputs and their types.
@@ -721,18 +711,23 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args,
//
// Otherwise emit an error but still use a valid type to avoid
// spurious errors (e.g., no inputs).
- if (!Args.hasArgNoClaim(options::OPT_E))
+ if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP)
Diag(clang::diag::err_drv_unknown_stdin_type);
Ty = types::TY_C;
} else {
- // Otherwise lookup by extension, and fallback to ObjectType if not
- // found. We use a host hook here because Darwin at least has its own
+ // Otherwise lookup by extension.
+ // Fallback is C if invoked as C preprocessor or Object otherwise.
+ // We use a host hook here because Darwin at least has its own
// idea of what .s is.
if (const char *Ext = strrchr(Value, '.'))
Ty = TC.LookupTypeForExtension(Ext + 1);
- if (Ty == types::TY_INVALID)
- Ty = types::TY_Object;
+ if (Ty == types::TY_INVALID) {
+ if (CCCIsCPP)
+ Ty = types::TY_C;
+ else
+ Ty = types::TY_Object;
+ }
// If the driver is invoked as C++ compiler (like clang++ or c++) it
// should autodetect some input files as C++ for g++ compatibility.
@@ -799,6 +794,15 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args,
}
}
+ if (CCCIsCPP && Inputs.empty()) {
+ // If called as standalone preprocessor, stdin is processed
+ // if no other input is present.
+ unsigned Index = Args.getBaseArgs().MakeIndex("-");
+ Arg *A = Opts->ParseOneArg(Args, Index);
+ A->claim();
+ Inputs.push_back(std::make_pair(types::TY_C, A));
+ }
+
if (!SuppressMissingInputWarning && Inputs.empty()) {
Diag(clang::diag::err_drv_no_input_files);
return;
@@ -811,7 +815,8 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args,
phases::ID FinalPhase;
// -{E,M,MM} only run the preprocessor.
- if ((FinalPhaseArg = Args.getLastArg(options::OPT_E)) ||
+ if (CCCIsCPP ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT_E)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT_M, options::OPT_MM))) {
FinalPhase = phases::Preprocess;
@@ -853,6 +858,10 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args,
// Claim here to avoid the more general unused warning.
InputArg->claim();
+ // Suppress all unused style warnings with -Qunused-arguments
+ if (Args.hasArg(options::OPT_Qunused_arguments))
+ continue;
+
// Special case '-E' warning on a previously preprocessed file to make
// more sense.
if (InitialPhase == phases::Compile && FinalPhase == phases::Preprocess &&
@@ -945,7 +954,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
} else if (Args.hasArg(options::OPT_emit_ast)) {
return new CompileJobAction(Input, types::TY_AST);
} else if (Args.hasArg(options::OPT_emit_llvm) ||
- Args.hasArg(options::OPT_flto) || HasO4) {
+ Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false) ||
+ HasO4) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
return new CompileJobAction(Input, Output);
@@ -1064,14 +1074,17 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) ||
C.getArgs().hasArg(options::OPT_static) ||
C.getArgs().hasArg(options::OPT_fapple_kext));
- bool IsIADefault = (TC->IsIntegratedAssemblerDefault() && !HasStatic);
+ bool IsDarwin = TC->getTriple().getOS() == llvm::Triple::Darwin;
+ bool IsIADefault = TC->IsIntegratedAssemblerDefault() &&
+ !(HasStatic && IsDarwin);
if (C.getArgs().hasFlag(options::OPT_integrated_as,
options::OPT_no_integrated_as,
IsIADefault) &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
isa<AssembleJobAction>(JA) &&
Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
- const Tool &Compiler = TC->SelectTool(C,cast<JobAction>(**Inputs->begin()));
+ const Tool &Compiler = TC->SelectTool(
+ C, cast<JobAction>(**Inputs->begin()), (*Inputs)[0]->getInputs());
if (Compiler.hasIntegratedAssembler()) {
Inputs = &(*Inputs)[0]->getInputs();
ToolForJob = &Compiler;
@@ -1080,7 +1093,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
// Otherwise use the tool for the current job.
if (!ToolForJob)
- ToolForJob = &TC->SelectTool(C, *JA);
+ ToolForJob = &TC->SelectTool(C, *JA, *Inputs);
// See if we should use an integrated preprocessor. We do so when we have
// exactly one input, since this is the only use case we care about
@@ -1206,7 +1219,13 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
}
llvm::SmallString<128> BasePath(BaseInput);
- llvm::StringRef BaseName = llvm::sys::path::filename(BasePath);
+ llvm::StringRef BaseName;
+
+ // Dsymutil actions should use the full path.
+ if (isa<DsymutilJobAction>(JA))
+ BaseName = BasePath;
+ else
+ BaseName = llvm::sys::path::filename(BasePath);
// Determine what the derived output name should be.
const char *NamedOutput;
@@ -1243,7 +1262,12 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
// attempting to use this prefix when lokup up program paths.
for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
ie = PrefixDirs.end(); it != ie; ++it) {
- llvm::sys::Path P(*it);
+ std::string Dir(*it);
+ if (Dir.empty())
+ continue;
+ if (Dir[0] == '=')
+ Dir = SysRoot + Dir.substr(1);
+ llvm::sys::Path P(Dir);
P.appendComponent(Name);
bool Exists;
if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
@@ -1253,7 +1277,12 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
const ToolChain::path_list &List = TC.getFilePaths();
for (ToolChain::path_list::const_iterator
it = List.begin(), ie = List.end(); it != ie; ++it) {
- llvm::sys::Path P(*it);
+ std::string Dir(*it);
+ if (Dir.empty())
+ continue;
+ if (Dir[0] == '=')
+ Dir = SysRoot + Dir.substr(1);
+ llvm::sys::Path P(Dir);
P.appendComponent(Name);
bool Exists;
if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
@@ -1323,7 +1352,7 @@ std::string Driver::GetTemporaryPath(const char *Suffix) const {
const HostInfo *Driver::GetHostInfo(const char *TripleStr) const {
llvm::PrettyStackTraceString CrashInfo("Constructing host");
- llvm::Triple Triple(TripleStr);
+ llvm::Triple Triple(llvm::Triple::normalize(TripleStr).c_str());
// TCE is an osless target
if (Triple.getArchName() == "tce")
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index cd413180f77b..198af54c035a 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -113,14 +113,9 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
TCTriple.setArch(Arch);
// If we recognized the arch, match it to the toolchains we support.
- const char *UseNewToolChain = ::getenv("CCC_ENABLE_NEW_DARWIN_TOOLCHAIN");
- if (UseNewToolChain ||
- Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64 ||
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64 ||
Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) {
TC = new toolchains::DarwinClang(*this, TCTriple);
- } else if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
- // We still use the legacy DarwinGCC toolchain on X86.
- TC = new toolchains::DarwinGCC(*this, TCTriple);
} else
TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple);
}
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index c3d3048c12fe..0252b3e5cac5 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -20,9 +20,9 @@ using namespace clang::driver::options;
// Ordering on Info. The ordering is *almost* lexicographic, with two
// exceptions. First, '\0' comes at the end of the alphabet instead of
-// the beginning (thus options preceed any other options which prefix
+// the beginning (thus options precede any other options which prefix
// them). Second, for options with the same name, the less permissive
-// version should come first; a Flag option should preceed a Joined
+// version should come first; a Flag option should precede a Joined
// option, for example.
static int StrCmpOptionName(const char *A, const char *B) {
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index e305683930cf..d9199154104a 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -47,7 +47,7 @@ bool ToolChain::HasNativeLLVMSupport() const {
return false;
}
-/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting.
+/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
//
// FIXME: tblgen this.
static const char *getARMTargetCPU(const ArgList &Args,
@@ -101,6 +101,8 @@ static const char *getARMTargetCPU(const ArgList &Args,
return "iwmmxt";
if (MArch == "xscale")
return "xscale";
+ if (MArch == "armv6m" || MArch == "armv6-m")
+ return "cortex-m0";
// If all else failed, return the most base CPU LLVM supports.
return "arm7tdmi";
@@ -137,6 +139,12 @@ static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) {
if (CPU == "cortex-a8" || CPU == "cortex-a9")
return "v7";
+ if (CPU == "cortex-m3")
+ return "v7m";
+
+ if (CPU == "cortex-m0")
+ return "v6m";
+
return "";
}
@@ -168,10 +176,10 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const {
}
std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args) const {
- // Diagnose use of -mmacosx-version-min and -miphoneos-version-min on
- // non-Darwin.
+ // Diagnose use of Darwin OS deployment target arguments on non-Darwin.
if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ,
- options::OPT_miphoneos_version_min_EQ))
+ options::OPT_miphoneos_version_min_EQ,
+ options::OPT_mios_simulator_version_min_EQ))
getDriver().Diag(clang::diag::err_drv_clang_unsupported)
<< A->getAsString(Args);
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 1c396bd0ed5b..4668d7303fc7 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -101,7 +101,8 @@ static const char *GetArmArchForMCpu(llvm::StringRef Value) {
return "xscale";
if (Value == "arm1136j-s" || Value == "arm1136jf-s" ||
- Value == "arm1176jz-s" || Value == "arm1176jzf-s")
+ Value == "arm1176jz-s" || Value == "arm1176jzf-s" ||
+ Value == "cortex-m0" )
return "armv6";
if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3")
@@ -114,7 +115,8 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
switch (getTriple().getArch()) {
default:
return getArchName();
-
+
+ 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)))
@@ -129,82 +131,6 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
}
}
-DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple)
- : Darwin(Host, Triple)
-{
- // We can only work with 4.2.1 currently.
- GCCVersion[0] = 4;
- GCCVersion[1] = 2;
- GCCVersion[2] = 1;
-
- // Set up the tool chain paths to match gcc.
- ToolChainDir = "i686-apple-darwin";
- ToolChainDir += llvm::utostr(DarwinVersion[0]);
- ToolChainDir += "/";
- ToolChainDir += llvm::utostr(GCCVersion[0]);
- ToolChainDir += '.';
- ToolChainDir += llvm::utostr(GCCVersion[1]);
- ToolChainDir += '.';
- ToolChainDir += llvm::utostr(GCCVersion[2]);
-
- // Try the next major version if that tool chain dir is invalid.
- std::string Tmp = "/usr/lib/gcc/" + ToolChainDir;
- bool Exists;
- if (llvm::sys::fs::exists(Tmp, Exists) || Exists) {
- std::string Next = "i686-apple-darwin";
- Next += llvm::utostr(DarwinVersion[0] + 1);
- Next += "/";
- Next += llvm::utostr(GCCVersion[0]);
- Next += '.';
- Next += llvm::utostr(GCCVersion[1]);
- Next += '.';
- Next += llvm::utostr(GCCVersion[2]);
-
- // Use that if it exists, otherwise hope the user isn't linking.
- //
- // FIXME: Drop dependency on gcc's tool chain.
- Tmp = "/usr/lib/gcc/" + Next;
- if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)
- ToolChainDir = Next;
- }
-
- std::string Path;
- if (getArchName() == "x86_64") {
- Path = getDriver().Dir;
- Path += "/../lib/gcc/";
- Path += ToolChainDir;
- Path += "/x86_64";
- getFilePaths().push_back(Path);
-
- Path = "/usr/lib/gcc/";
- Path += ToolChainDir;
- Path += "/x86_64";
- getFilePaths().push_back(Path);
- }
-
- Path = getDriver().Dir;
- Path += "/../lib/gcc/";
- Path += ToolChainDir;
- getFilePaths().push_back(Path);
-
- Path = "/usr/lib/gcc/";
- Path += ToolChainDir;
- getFilePaths().push_back(Path);
-
- Path = getDriver().Dir;
- Path += "/../libexec/gcc/";
- Path += ToolChainDir;
- getProgramPaths().push_back(Path);
-
- Path = "/usr/libexec/gcc/";
- Path += ToolChainDir;
- getProgramPaths().push_back(Path);
-
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
-}
-
Darwin::~Darwin() {
// Free tool implementations.
for (llvm::DenseMap<unsigned, Tool*>::iterator
@@ -222,33 +148,31 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const {
unsigned Version[3];
getTargetVersion(Version);
-
- // Mangle the target version into the OS triple component. For historical
- // reasons that make little sense, the version passed here is the "darwin"
- // version, which drops the 10 and offsets by 4. See inverse code when
- // setting the OS version preprocessor define.
- if (!isTargetIPhoneOS()) {
- Version[0] = Version[1] + 4;
- Version[1] = Version[2];
- Version[2] = 0;
- } else {
- // Use the environment to communicate that we are targetting iPhoneOS.
- Triple.setEnvironmentName("iphoneos");
- }
-
+
llvm::SmallString<16> Str;
- llvm::raw_svector_ostream(Str) << "darwin" << Version[0]
- << "." << Version[1] << "." << Version[2];
+ llvm::raw_svector_ostream(Str)
+ << (isTargetIPhoneOS() ? "ios" : "macosx")
+ << Version[0] << "." << Version[1] << "." << Version[2];
Triple.setOSName(Str.str());
return Triple.getTriple();
}
-Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
+
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) {
+ // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI.
+ if (Inputs.size() == 1 &&
+ types::isCXX(Inputs[0]->getType()) &&
+ getTriple().getOS() == llvm::Triple::Darwin &&
+ getTriple().getArch() == llvm::Triple::x86 &&
+ C.getArgs().getLastArg(options::OPT_fapple_kext))
+ Key = JA.getKind();
+ else
+ Key = Action::AnalyzeJobClass;
+ } else
Key = JA.getKind();
// FIXME: This doesn't belong here, but ideally we will support static soon
@@ -293,91 +217,12 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
return *T;
}
-void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- std::string Tmp;
-
- // FIXME: Derive these correctly.
- if (getArchName() == "x86_64") {
- CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
- "/x86_64"));
- // Intentionally duplicated for (temporary) gcc bug compatibility.
- CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
- "/x86_64"));
- }
-
- CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir));
-
- Tmp = getDriver().Dir + "/../lib/gcc/" + ToolChainDir;
- bool Exists;
- if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)
- CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
- Tmp = getDriver().Dir + "/../lib/gcc";
- if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)
- CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
- CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
- // Intentionally duplicated for (temporary) gcc bug compatibility.
- CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
- Tmp = getDriver().Dir + "/../lib/" + ToolChainDir;
- if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)
- CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
- Tmp = getDriver().Dir + "/../lib";
- if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)
- CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
- CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
- "/../../../" + ToolChainDir));
- CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
- "/../../.."));
-}
-
-void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Note that this routine is only used for targetting OS X.
-
- // Derived from libgcc and lib specs but refactored.
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-lgcc_static");
- } else {
- if (Args.hasArg(options::OPT_static_libgcc)) {
- CmdArgs.push_back("-lgcc_eh");
- } else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
- // Derived from darwin_iphoneos_libgcc spec.
- if (isTargetIPhoneOS()) {
- CmdArgs.push_back("-lgcc_s.1");
- } else {
- CmdArgs.push_back("-lgcc_s.10.5");
- }
- } else if (Args.hasArg(options::OPT_shared_libgcc) ||
- Args.hasFlag(options::OPT_fexceptions,
- options::OPT_fno_exceptions) ||
- Args.hasArg(options::OPT_fgnu_runtime)) {
- // FIXME: This is probably broken on 10.3?
- if (isMacosxVersionLT(10, 5))
- CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-lgcc_s.10.5");
- } else {
- if (isMacosxVersionLT(10, 3, 9))
- ; // Do nothing.
- else if (isMacosxVersionLT(10, 5))
- CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-lgcc_s.10.5");
- }
-
- if (isTargetIPhoneOS() || isMacosxVersionLT(10, 6)) {
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("-lSystem");
- } else {
- CmdArgs.push_back("-lSystem");
- CmdArgs.push_back("-lgcc");
- }
- }
-}
DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple)
: Darwin(Host, Triple)
{
+ std::string UsrPrefix = "llvm-gcc-4.2/";
+
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
@@ -388,18 +233,18 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple)
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 legiy code that can be removed once
- // fallback is no longer useful.
+ // also add the GCC libexec paths. This is legacy code that can be removed
+ // once fallback is no longer useful.
std::string ToolChainDir = "i686-apple-darwin";
ToolChainDir += llvm::utostr(DarwinVersion[0]);
ToolChainDir += "/4.2.1";
std::string Path = getDriver().Dir;
- Path += "/../libexec/gcc/";
+ Path += "/../" + UsrPrefix + "libexec/gcc/";
Path += ToolChainDir;
getProgramPaths().push_back(Path);
- Path = "/usr/libexec/gcc/";
+ Path = "/usr/" + UsrPrefix + "libexec/gcc/";
Path += ToolChainDir;
getProgramPaths().push_back(Path);
}
@@ -494,12 +339,13 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// Select the dynamic runtime library and the target specific static library.
const char *DarwinStaticLib = 0;
if (isTargetIPhoneOS()) {
- CmdArgs.push_back("-lgcc_s.1");
+ // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1,
+ // it never went into the SDK.
+ if (!isTargetIOSSimulator())
+ CmdArgs.push_back("-lgcc_s.1");
- // We may need some static functions for armv6/thumb which are required to
- // be in the same linkage unit as their caller.
- if (getDarwinArchName(Args) == "armv6")
- DarwinStaticLib = "libclang_rt.armv6.a";
+ // We currently always need a static runtime library for iOS.
+ DarwinStaticLib = "libclang_rt.ios.a";
} else {
// The dynamic runtime library was merged with libSystem for 10.6 and
// beyond; only 10.4 and 10.5 need an additional runtime library.
@@ -509,7 +355,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lgcc_s.10.5");
// For OS X, we thought we would only need a static runtime library when
- // targetting 10.4, to provide versions of the static functions which were
+ // targeting 10.4, to provide versions of the static functions which were
// omitted from 10.4.dylib.
//
// Unfortunately, that turned out to not be true, because Darwin system
@@ -543,46 +389,69 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
const OptTable &Opts = getDriver().getOpts();
Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
- Arg *iPhoneVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
- if (OSXVersion && iPhoneVersion) {
+ Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
+ Arg *iOSSimVersion = Args.getLastArg(
+ options::OPT_mios_simulator_version_min_EQ);
+ if (OSXVersion && (iOSVersion || iOSSimVersion)) {
getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
- << iPhoneVersion->getAsString(Args);
- iPhoneVersion = 0;
- } else if (!OSXVersion && !iPhoneVersion) {
- // If neither OS X nor iPhoneOS targets were specified, check for
+ << (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args);
+ iOSVersion = iOSSimVersion = 0;
+ } else if (iOSVersion && iOSSimVersion) {
+ getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << iOSVersion->getAsString(Args)
+ << iOSSimVersion->getAsString(Args);
+ iOSSimVersion = 0;
+ } else if (!OSXVersion && !iOSVersion && !iOSSimVersion) {
+ // If not deployment target was specified on the command line, check for
// environment defines.
const char *OSXTarget = ::getenv("MACOSX_DEPLOYMENT_TARGET");
- const char *iPhoneOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET");
+ const char *iOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET");
+ const char *iOSSimTarget = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET");
// Ignore empty strings.
if (OSXTarget && OSXTarget[0] == '\0')
OSXTarget = 0;
- if (iPhoneOSTarget && iPhoneOSTarget[0] == '\0')
- iPhoneOSTarget = 0;
+ if (iOSTarget && iOSTarget[0] == '\0')
+ iOSTarget = 0;
+ if (iOSSimTarget && iOSSimTarget[0] == '\0')
+ iOSSimTarget = 0;
- // Diagnose conflicting deployment targets, and choose default platform
- // based on the tool chain.
+ // Handle conflicting deployment targets
//
// FIXME: Don't hardcode default here.
- if (OSXTarget && iPhoneOSTarget) {
- // FIXME: We should see if we can get away with warning or erroring on
- // this. Perhaps put under -pedantic?
+
+ // Do not allow conflicts with the iOS simulator target.
+ if (iOSSimTarget && (OSXTarget || iOSTarget)) {
+ getDriver().Diag(clang::diag::err_drv_conflicting_deployment_targets)
+ << "IOS_SIMULATOR_DEPLOYMENT_TARGET"
+ << (OSXTarget ? "MACOSX_DEPLOYMENT_TARGET" :
+ "IPHONEOS_DEPLOYMENT_TARGET");
+ }
+
+ // Allow conflicts among OSX and iOS for historical reasons, but choose the
+ // default platform.
+ if (OSXTarget && iOSTarget) {
if (getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::thumb)
OSXTarget = 0;
else
- iPhoneOSTarget = 0;
+ iOSTarget = 0;
}
if (OSXTarget) {
const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget);
Args.append(OSXVersion);
- } else if (iPhoneOSTarget) {
+ } else if (iOSTarget) {
const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
- iPhoneVersion = Args.MakeJoinedArg(0, O, iPhoneOSTarget);
- Args.append(iPhoneVersion);
+ iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget);
+ Args.append(iOSVersion);
+ } else if (iOSSimTarget) {
+ 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);
@@ -591,25 +460,44 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
}
+ // Reject invalid architecture combinations.
+ if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 &&
+ getTriple().getArch() != llvm::Triple::x86_64)) {
+ getDriver().Diag(clang::diag::err_drv_invalid_arch_for_deployment_target)
+ << getTriple().getArchName() << iOSSimVersion->getAsString(Args);
+ }
+
// Set the tool chain target information.
unsigned Major, Minor, Micro;
bool HadExtra;
if (OSXVersion) {
- assert(!iPhoneVersion && "Unknown target platform!");
+ assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!");
if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor,
Micro, HadExtra) || HadExtra ||
- Major != 10 || Minor >= 10 || Micro >= 10)
+ Major != 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(clang::diag::err_drv_invalid_version_number)
<< OSXVersion->getAsString(Args);
} else {
- assert(iPhoneVersion && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(iPhoneVersion->getValue(Args), Major, Minor,
+ const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion;
+ assert(Version && "Unknown target platform!");
+ if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major >= 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(clang::diag::err_drv_invalid_version_number)
- << iPhoneVersion->getAsString(Args);
+ << Version->getAsString(Args);
}
- setTarget(iPhoneVersion, Major, Minor, Micro);
+
+ bool IsIOSSim = bool(iOSSimVersion);
+
+ // In GCC, the simulator historically was treated as being OS X in some
+ // contexts, like determining the link logic, despite generally being called
+ // with an iOS deployment target. For compatibility, we detect the
+ // simulator as iOS + x86, and treat it differently in a few contexts.
+ if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64))
+ IsIOSSim = true;
+
+ setTarget(/*IsIPhoneOS=*/ !OSXVersion, Major, Minor, Micro, IsIOSSim);
}
void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
@@ -712,9 +600,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// driver behavior; that isn't going to work in our model. We
// use isDriverOption() as an approximation, although things
// like -O4 are going to slip through.
- if (!XarchArg || Index > Prev + 1 ||
- XarchArg->getOption().isDriverOption()) {
- getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument)
+ if (!XarchArg || Index > Prev + 1) {
+ getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_with_args)
+ << A->getAsString(Args);
+ continue;
+ } else if (XarchArg->getOption().isDriverOption()) {
+ getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_isdriver)
<< A->getAsString(Args);
continue;
}
@@ -918,6 +809,11 @@ const char *Darwin::GetForcedPicModel() const {
return 0;
}
+bool Darwin::SupportsProfiling() const {
+ // Profiling instrumentation is only supported on x86.
+ return getArchName() == "i386" || getArchName() == "x86_64";
+}
+
bool Darwin::SupportsObjCGC() const {
// Garbage collection is supported everywhere except on iPhone OS.
return !isTargetIPhoneOS();
@@ -935,7 +831,7 @@ Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args) const {
Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
: ToolChain(Host, Triple) {
getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir.c_str())
+ if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
}
@@ -947,7 +843,8 @@ Generic_GCC::~Generic_GCC() {
}
Tool &Generic_GCC::SelectTool(const Compilation &C,
- const JobAction &JA) const {
+ const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1035,7 +932,8 @@ const char *TCEToolChain::GetForcedPicModel() const {
}
Tool &TCEToolChain::SelectTool(const Compilation &C,
- const JobAction &JA) const {
+ const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
Key = Action::AnalyzeJobClass;
@@ -1061,7 +959,8 @@ OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple)
getFilePaths().push_back("/usr/lib");
}
-Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1085,7 +984,7 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::LinkJobClass:
T = new tools::openbsd::Link(*this); break;
default:
- T = &Generic_GCC::SelectTool(C, JA);
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
}
@@ -1104,18 +1003,15 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple)
llvm::Triple::x86_64)
Lib32 = true;
- getProgramPaths().push_back(getDriver().Dir + "/../libexec");
- getProgramPaths().push_back("/usr/libexec");
if (Lib32) {
- getFilePaths().push_back(getDriver().Dir + "/../lib32");
getFilePaths().push_back("/usr/lib32");
} else {
- getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
}
}
-Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1138,7 +1034,7 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::LinkJobClass:
T = new tools::freebsd::Link(*this); break;
default:
- T = &Generic_GCC::SelectTool(C, JA);
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
}
@@ -1157,16 +1053,16 @@ NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple)
llvm::Triple::x86_64)
Lib32 = true;
- getProgramPaths().push_back(getDriver().Dir + "/../libexec");
- getProgramPaths().push_back("/usr/libexec");
- if (Lib32) {
- getFilePaths().push_back("/usr/lib/i386");
- } else {
- getFilePaths().push_back("/usr/lib");
+ if (getDriver().UseStdLib) {
+ if (Lib32)
+ getFilePaths().push_back("=/usr/lib/i386");
+ else
+ getFilePaths().push_back("=/usr/lib");
}
}
-Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1189,7 +1085,7 @@ Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::LinkJobClass:
T = new tools::netbsd::Link(*this); break;
default:
- T = &Generic_GCC::SelectTool(C, JA);
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
}
@@ -1206,7 +1102,8 @@ Minix::Minix(const HostInfo &Host, const llvm::Triple& Triple)
getFilePaths().push_back("/usr/gnu/lib/gcc/i686-pc-minix/4.4.3");
}
-Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1221,7 +1118,7 @@ Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::LinkJobClass:
T = new tools::minix::Link(*this); break;
default:
- T = &Generic_GCC::SelectTool(C, JA);
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
}
@@ -1234,7 +1131,7 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {
getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir.c_str())
+ if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getFilePaths().push_back(getDriver().Dir + "/../lib");
@@ -1245,7 +1142,8 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple)
}
-Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1260,7 +1158,7 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::LinkJobClass:
T = new tools::auroraux::Link(*this); break;
default:
- T = &Generic_GCC::SelectTool(C, JA);
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
}
@@ -1277,16 +1175,22 @@ enum LinuxDistro {
Exherbo,
Fedora13,
Fedora14,
+ Fedora15,
+ FedoraRawhide,
OpenSuse11_3,
+ UbuntuHardy,
+ UbuntuIntrepid,
UbuntuJaunty,
UbuntuKarmic,
UbuntuLucid,
UbuntuMaverick,
+ UbuntuNatty,
UnknownDistro
};
static bool IsFedora(enum LinuxDistro Distro) {
- return Distro == Fedora13 || Distro == Fedora14;
+ return Distro == Fedora13 || Distro == Fedora14 ||
+ Distro == Fedora15 || Distro == FedoraRawhide;
}
static bool IsOpenSuse(enum LinuxDistro Distro) {
@@ -1298,8 +1202,10 @@ static bool IsDebian(enum LinuxDistro Distro) {
}
static bool IsUbuntu(enum LinuxDistro Distro) {
- return Distro == UbuntuLucid || Distro == UbuntuMaverick ||
- Distro == UbuntuJaunty || Distro == UbuntuKarmic;
+ return Distro == UbuntuHardy || Distro == UbuntuIntrepid ||
+ Distro == UbuntuLucid || Distro == UbuntuMaverick ||
+ Distro == UbuntuJaunty || Distro == UbuntuKarmic ||
+ Distro == UbuntuNatty;
}
static bool IsDebianBased(enum LinuxDistro Distro) {
@@ -1315,7 +1221,9 @@ static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) {
return true;
}
- if (Arch == llvm::Triple::x86 && IsDebianBased(Distro))
+ if (Arch == llvm::Triple::ppc64)
+ return true;
+ if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && IsDebianBased(Distro))
return true;
return false;
}
@@ -1327,24 +1235,35 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
llvm::SmallVector<llvm::StringRef, 8> Lines;
Data.split(Lines, "\n");
for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) {
- if (Lines[i] == "DISTRIB_CODENAME=maverick")
- return UbuntuMaverick;
- else if (Lines[i] == "DISTRIB_CODENAME=lucid")
- return UbuntuLucid;
+ if (Lines[i] == "DISTRIB_CODENAME=hardy")
+ return UbuntuHardy;
+ else if (Lines[i] == "DISTRIB_CODENAME=intrepid")
+ return UbuntuIntrepid;
else if (Lines[i] == "DISTRIB_CODENAME=jaunty")
return UbuntuJaunty;
else if (Lines[i] == "DISTRIB_CODENAME=karmic")
return UbuntuKarmic;
+ else if (Lines[i] == "DISTRIB_CODENAME=lucid")
+ return UbuntuLucid;
+ else if (Lines[i] == "DISTRIB_CODENAME=maverick")
+ return UbuntuMaverick;
+ else if (Lines[i] == "DISTRIB_CODENAME=natty")
+ return UbuntuNatty;
}
return UnknownDistro;
}
if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) {
llvm::StringRef Data = File.get()->getBuffer();
- if (Data.startswith("Fedora release 14 (Laughlin)"))
+ if (Data.startswith("Fedora release 15"))
+ return Fedora15;
+ else if (Data.startswith("Fedora release 14"))
return Fedora14;
- else if (Data.startswith("Fedora release 13 (Goddard)"))
+ else if (Data.startswith("Fedora release 13"))
return Fedora13;
+ else if (Data.startswith("Fedora release") &&
+ Data.find("Rawhide") != llvm::StringRef::npos)
+ return FedoraRawhide;
return UnknownDistro;
}
@@ -1384,7 +1303,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
Suffix32 = "/32";
std::string Suffix64 = "";
- if (Arch == llvm::Triple::x86)
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
Suffix64 = "/64";
std::string Lib32 = "lib";
@@ -1400,7 +1319,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
Lib64 = "lib64";
std::string GccTriple = "";
- if (Arch == llvm::Triple::arm) {
+ if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) {
if (!llvm::sys::fs::exists("/usr/lib/gcc/arm-linux-gnueabi", Exists) &&
Exists)
GccTriple = "arm-linux-gnueabi";
@@ -1423,6 +1342,9 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-manbo-linux-gnu",
Exists) && Exists)
GccTriple = "x86_64-manbo-linux-gnu";
+ else if (!llvm::sys::fs::exists("/usr/lib/x86_64-linux-gnu/gcc",
+ Exists) && Exists)
+ GccTriple = "x86_64-linux-gnu";
} else if (Arch == llvm::Triple::x86) {
if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-linux-gnu", Exists) && Exists)
GccTriple = "i686-linux-gnu";
@@ -1438,11 +1360,26 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
else if (!llvm::sys::fs::exists("/usr/lib/gcc/i586-suse-linux", Exists) &&
Exists)
GccTriple = "i586-suse-linux";
+ else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-slackware-linux", Exists)
+ && Exists)
+ GccTriple = "i486-slackware-linux";
+ } else if (Arch == llvm::Triple::ppc) {
+ if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists)
+ GccTriple = "powerpc-linux-gnu";
+ else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu", Exists) && Exists)
+ GccTriple = "powerpc-unknown-linux-gnu";
+ } else if (Arch == llvm::Triple::ppc64) {
+ if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists)
+ GccTriple = "powerpc64-unknown-linux-gnu";
+ else if (!llvm::sys::fs::exists("/usr/lib64/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists)
+ GccTriple = "powerpc64-unknown-linux-gnu";
}
- const char* GccVersions[] = {"4.5.2", "4.5.1", "4.5", "4.4.5", "4.4.4",
- "4.4.3", "4.4", "4.3.4", "4.3.3", "4.3.2",
- "4.3"};
+ const char* GccVersions[] = {"4.6.0",
+ "4.5.2", "4.5.1", "4.5",
+ "4.4.5", "4.4.4", "4.4.3", "4.4",
+ "4.3.4", "4.3.3", "4.3.2", "4.3",
+ "4.2.4", "4.2.3", "4.2.2", "4.2.1", "4.2"};
std::string Base = "";
for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
std::string Suffix = GccTriple + "/" + GccVersions[i];
@@ -1456,10 +1393,15 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
Base = t2;
break;
}
+ std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix;
+ if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists) {
+ Base = t3;
+ break;
+ }
}
path_list &Paths = getFilePaths();
- bool Is32Bits = getArch() == llvm::Triple::x86;
+ bool Is32Bits = (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::ppc);
std::string Suffix;
std::string Lib;
@@ -1485,10 +1427,10 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
ExtraOpts.push_back("relro");
}
- if (Arch == llvm::Triple::arm)
+ if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
ExtraOpts.push_back("-X");
- if (IsFedora(Distro) || Distro == UbuntuMaverick)
+ if (IsFedora(Distro) || Distro == UbuntuMaverick || Distro == UbuntuNatty)
ExtraOpts.push_back("--hash-style=gnu");
if (IsDebian(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty ||
@@ -1500,7 +1442,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (Distro == DebianSqueeze || IsOpenSuse(Distro) ||
IsFedora(Distro) || Distro == UbuntuLucid || Distro == UbuntuMaverick ||
- Distro == UbuntuKarmic)
+ Distro == UbuntuKarmic || Distro == UbuntuNatty)
ExtraOpts.push_back("--build-id");
if (Distro == ArchLinux)
@@ -1527,7 +1469,8 @@ bool Linux::HasNativeLLVMSupport() const {
return true;
}
-Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1550,7 +1493,7 @@ Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::LinkJobClass:
T = new tools::linuxtools::Link(*this); break;
default:
- T = &Generic_GCC::SelectTool(C, JA);
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
}
@@ -1564,7 +1507,7 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
// Path mangling to find libexec
getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir.c_str())
+ if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
getFilePaths().push_back(getDriver().Dir + "/../lib");
@@ -1572,7 +1515,8 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
getFilePaths().push_back("/usr/lib/gcc41");
}
-Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
@@ -1587,7 +1531,7 @@ Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const {
case Action::LinkJobClass:
T = new tools::dragonfly::Link(*this); break;
default:
- T = &Generic_GCC::SelectTool(C, JA);
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
}
@@ -1598,7 +1542,8 @@ Windows::Windows(const HostInfo &Host, const llvm::Triple& Triple)
: ToolChain(Host, Triple) {
}
-Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA) const {
+Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
Action::ActionClass Key;
if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
Key = Action::AnalyzeJobClass;
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 0e3645cb8f7e..7a1a05025296 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -33,7 +33,8 @@ public:
Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple);
~Generic_GCC();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
virtual bool IsUnwindTablesDefault() const;
virtual const char *GetDefaultRelocationModel() const;
@@ -56,10 +57,13 @@ private:
// the argument translation business.
mutable bool TargetInitialized;
- /// Whether we are targetting iPhoneOS target.
+ /// Whether we are targeting iPhoneOS target.
mutable bool TargetIsIPhoneOS;
- /// The OS version we are targetting.
+ /// Whether we are targeting the iPhoneOS simulator target.
+ mutable bool TargetIsIPhoneOSSimulator;
+
+ /// The OS version we are targeting.
mutable unsigned TargetVersion[3];
/// The default macosx-version-min of this tool chain; empty until
@@ -80,18 +84,22 @@ public:
// FIXME: Eliminate these ...Target functions and derive separate tool chains
// for these targets and put version in constructor.
- void setTarget(bool isIPhoneOS, unsigned Major, unsigned Minor,
- unsigned Micro) const {
+ void setTarget(bool IsIPhoneOS, unsigned Major, unsigned Minor,
+ unsigned Micro, bool IsIOSSim) const {
+ assert((!IsIOSSim || IsIPhoneOS) && "Unexpected deployment target!");
+
// FIXME: For now, allow reinitialization as long as values don't
// change. This will go away when we move away from argument translation.
- if (TargetInitialized && TargetIsIPhoneOS == isIPhoneOS &&
+ if (TargetInitialized && TargetIsIPhoneOS == IsIPhoneOS &&
+ TargetIsIPhoneOSSimulator == IsIOSSim &&
TargetVersion[0] == Major && TargetVersion[1] == Minor &&
TargetVersion[2] == Micro)
return;
assert(!TargetInitialized && "Target already initialized!");
TargetInitialized = true;
- TargetIsIPhoneOS = isIPhoneOS;
+ TargetIsIPhoneOS = IsIPhoneOS;
+ TargetIsIPhoneOSSimulator = IsIOSSim;
TargetVersion[0] = Major;
TargetVersion[1] = Minor;
TargetVersion[2] = Micro;
@@ -102,6 +110,11 @@ public:
return TargetIsIPhoneOS;
}
+ bool isTargetIOSSimulator() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetIsIPhoneOSSimulator;
+ }
+
bool isTargetInitialized() const { return TargetInitialized; }
void getTargetVersion(unsigned (&Res)[3]) const {
@@ -160,7 +173,8 @@ public:
virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
const char *BoundArch) const;
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
virtual bool IsBlocksDefault() const {
// Always allow blocks on Darwin; users interested in versioning are
@@ -212,6 +226,8 @@ public:
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
+ virtual bool SupportsProfiling() const;
+
virtual bool SupportsObjCGC() const;
virtual bool UseDwarfDebugFlags() const;
@@ -244,29 +260,6 @@ public:
/// }
};
-/// DarwinGCC - The Darwin toolchain used by GCC.
-class LLVM_LIBRARY_VISIBILITY DarwinGCC : public Darwin {
- /// GCC version to use.
- unsigned GCCVersion[3];
-
- /// The directory suffix for this tool chain.
- std::string ToolChainDir;
-
-public:
- DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple);
-
- /// @name Darwin ToolChain Implementation
- /// {
-
- virtual void AddLinkSearchPathArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
-
- virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const;
-
- /// }
-};
-
/// Darwin_Generic_GCC - Generic Darwin tool chain using gcc.
class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC {
public:
@@ -294,42 +287,48 @@ class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
public:
AuroraUX(const HostInfo &Host, const llvm::Triple& Triple);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
public:
OpenBSD(const HostInfo &Host, const llvm::Triple& Triple);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
public:
FreeBSD(const HostInfo &Host, const llvm::Triple& Triple);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
public:
NetBSD(const HostInfo &Host, const llvm::Triple& Triple);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY Minix : public Generic_GCC {
public:
Minix(const HostInfo &Host, const llvm::Triple& Triple);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
public:
DragonFly(const HostInfo &Host, const llvm::Triple& Triple);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
@@ -338,7 +337,8 @@ public:
virtual bool HasNativeLLVMSupport() const;
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
std::string Linker;
std::vector<std::string> ExtraOpts;
@@ -352,7 +352,8 @@ public:
TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple);
~TCEToolChain();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
bool IsMathErrnoDefault() const;
bool IsUnwindTablesDefault() const;
const char* GetDefaultRelocationModel() const;
@@ -369,7 +370,8 @@ class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
public:
Windows(const HostInfo &Host, const llvm::Triple& Triple);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
virtual bool IsIntegratedAssemblerDefault() const;
virtual bool IsUnwindTablesDefault() const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 9f4a0bc162e3..60803ddf93c8 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -34,14 +34,32 @@
#include "InputInfo.h"
#include "ToolChains.h"
+#ifdef __CYGWIN__
+#include <cygwin/version.h>
+#if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007
+#define IS_CYGWIN15 1
+#endif
+#endif
+
using namespace clang::driver;
using namespace clang::driver::tools;
+/// FindTargetProgramPath - Return path of the target specific version of
+/// ProgName. If it doesn't exist, return path of ProgName itself.
+static std::string FindTargetProgramPath(const ToolChain &TheToolChain,
+ const char *ProgName) {
+ std::string Executable(TheToolChain.getTripleString() + "-" + ProgName);
+ std::string Path(TheToolChain.GetProgramPath(Executable.c_str()));
+ if (Path != Executable)
+ return Path;
+ return TheToolChain.GetProgramPath(ProgName);
+}
+
/// CheckPreprocessingOptions - Perform some validation of preprocessing
/// arguments that is shared with gcc.
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC))
- if (!Args.hasArg(options::OPT_E))
+ if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP)
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-E";
}
@@ -309,7 +327,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
}
}
-/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting.
+/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
//
// FIXME: tblgen this.
static const char *getARMTargetCPU(const ArgList &Args,
@@ -363,6 +381,8 @@ static const char *getARMTargetCPU(const ArgList &Args,
return "iwmmxt";
if (MArch == "xscale")
return "xscale";
+ if (MArch == "armv6m" || MArch == "armv6-m")
+ return "cortex-m0";
// If all else failed, return the most base CPU LLVM supports.
return "arm7tdmi";
@@ -420,10 +440,17 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
}
void Clang::AddARMTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+ ArgStringList &CmdArgs,
+ bool KernelOrKext) const {
const Driver &D = getToolChain().getDriver();
llvm::Triple Triple = getToolChain().getTriple();
+ // Disable movt generation, if requested.
+#ifdef DISABLE_ARM_DARWIN_USE_MOVT
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-darwin-use-movt=0");
+#endif
+
// Select the ABI to use.
//
// FIXME: Support -meabi.
@@ -577,6 +604,28 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
} else
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
+
+ // Setting -msoft-float effectively disables NEON because of the GCC
+ // implementation, although the same isn't true of VFP or VFP3.
+ if (FloatABI == "soft") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
+ }
+
+ // Kernel code has more strict alignment requirements.
+ if (KernelOrKext) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-long-calls");
+
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-strict-align");
+
+ // The kext linker doesn't know how to deal with movw/movt.
+#ifndef DISABLE_ARM_DARWIN_USE_MOVT
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-darwin-use-movt=0");
+#endif
+ }
}
void Clang::AddMIPSTargetArgs(const ArgList &Args,
@@ -726,6 +775,11 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
CPUName = "x86-64";
else if (getToolChain().getArchName() == "i386")
CPUName = "i486";
+ } else if (getToolChain().getOS().startswith("freebsd")) {
+ if (getToolChain().getArchName() == "x86_64")
+ CPUName = "x86-64";
+ else if (getToolChain().getArchName() == "i386")
+ CPUName = "i486";
} else if (getToolChain().getOS().startswith("netbsd")) {
if (getToolChain().getArchName() == "x86_64")
CPUName = "x86-64";
@@ -762,34 +816,112 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
}
-static bool needsExceptions(const ArgList &Args, types::ID InputType,
- const llvm::Triple &Triple) {
- // Handle -fno-exceptions.
+static bool
+shouldUseExceptionTablesForObjCExceptions(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ // We use the zero-cost exception tables for Objective-C if the non-fragile
+ // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and
+ // later.
+
+ if (Args.hasArg(options::OPT_fobjc_nonfragile_abi))
+ return true;
+
+ if (Triple.getOS() != llvm::Triple::Darwin)
+ return false;
+
+ return (Triple.getDarwinMajorNumber() >= 9 &&
+ (Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::arm));
+}
+
+/// addExceptionArgs - Adds exception related arguments to the driver command
+/// arguments. There's a master flag, -fexceptions and also language specific
+/// flags to enable/disable C++ and Objective-C exceptions.
+/// This makes it possible to for example disable C++ exceptions but enable
+/// Objective-C exceptions.
+static void addExceptionArgs(const ArgList &Args, types::ID InputType,
+ const llvm::Triple &Triple,
+ bool KernelOrKext, bool IsRewriter,
+ ArgStringList &CmdArgs) {
+ if (KernelOrKext)
+ return;
+
+ // Exceptions are enabled by default.
+ bool ExceptionsEnabled = true;
+
+ // This keeps track of whether exceptions were explicitly turned on or off.
+ bool DidHaveExplicitExceptionFlag = false;
+
if (Arg *A = Args.getLastArg(options::OPT_fexceptions,
options::OPT_fno_exceptions)) {
if (A->getOption().matches(options::OPT_fexceptions))
- return true;
- else
- return false;
+ ExceptionsEnabled = true;
+ else
+ ExceptionsEnabled = false;
+
+ DidHaveExplicitExceptionFlag = true;
}
- // Otherwise, C++ inputs use exceptions.
- if (types::isCXX(InputType))
- return true;
+ bool ShouldUseExceptionTables = false;
- // As do Objective-C non-fragile ABI inputs and all Objective-C inputs on
- // x86_64 and ARM after SnowLeopard.
- if (types::isObjC(InputType)) {
- if (Args.hasArg(options::OPT_fobjc_nonfragile_abi))
- return true;
- if (Triple.getOS() != llvm::Triple::Darwin)
- return false;
- return (Triple.getDarwinMajorNumber() >= 9 &&
- (Triple.getArch() == llvm::Triple::x86_64 ||
- Triple.getArch() == llvm::Triple::arm));
+ // Exception tables and cleanups can be enabled with -fexceptions even if the
+ // language itself doesn't support exceptions.
+ if (ExceptionsEnabled && DidHaveExplicitExceptionFlag)
+ ShouldUseExceptionTables = true;
+
+ // Obj-C exceptions are enabled by default, regardless of -fexceptions. This
+ // is not necessarily sensible, but follows GCC.
+ if (types::isObjC(InputType) &&
+ Args.hasFlag(options::OPT_fobjc_exceptions,
+ options::OPT_fno_objc_exceptions,
+ true)) {
+ CmdArgs.push_back("-fobjc-exceptions");
+
+ ShouldUseExceptionTables |=
+ shouldUseExceptionTablesForObjCExceptions(Args, Triple);
}
- return false;
+ if (types::isCXX(InputType)) {
+ bool CXXExceptionsEnabled = ExceptionsEnabled;
+
+ if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions,
+ options::OPT_fno_cxx_exceptions,
+ options::OPT_fexceptions,
+ options::OPT_fno_exceptions)) {
+ if (A->getOption().matches(options::OPT_fcxx_exceptions))
+ CXXExceptionsEnabled = true;
+ else if (A->getOption().matches(options::OPT_fno_cxx_exceptions))
+ CXXExceptionsEnabled = false;
+ }
+
+ if (CXXExceptionsEnabled) {
+ CmdArgs.push_back("-fcxx-exceptions");
+
+ ShouldUseExceptionTables = true;
+ }
+ }
+
+ if (ShouldUseExceptionTables)
+ CmdArgs.push_back("-fexceptions");
+}
+
+static bool ShouldDisableCFI(const ArgList &Args,
+ const ToolChain &TC) {
+
+ // FIXME: Duplicated code with ToolChains.cpp
+ // FIXME: This doesn't belong here, but ideally we will support static soon
+ // anyway.
+ bool HasStatic = (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_fapple_kext));
+ bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic;
+ bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIADefault);
+ bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
+ options::OPT_fno_dwarf2_cfi_asm,
+ UseIntegratedAs);
+ return !UseCFI;
}
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
@@ -832,8 +964,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *A = Args.getLastArg(options::OPT_O_Group))
IsOpt = !A->getOption().matches(options::OPT_O0);
if (Args.hasFlag(options::OPT_mrelax_all,
- options::OPT_mno_relax_all,
- !IsOpt))
+ options::OPT_mno_relax_all,
+ !IsOpt))
CmdArgs.push_back("-mrelax-all");
// When using an integrated assembler, translate -Wa, and -Xassembler
@@ -850,10 +982,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Value == "-force_cpusubtype_ALL") {
// Do nothing, this is the default and we don't support anything else.
} else if (Value == "-L") {
- // We don't support -L yet, but it isn't important enough to error
- // on. No one should really be using it for a semantic change.
- D.Diag(clang::diag::warn_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ CmdArgs.push_back("-msave-temp-labels");
} else {
D.Diag(clang::diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
@@ -920,29 +1049,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Treat blocks as analysis entry points.
CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks");
+ CmdArgs.push_back("-analyzer-eagerly-assume");
+
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
- types::ID InputType = Inputs[0].getType();
-
- // Checks to perform for all language types.
-
CmdArgs.push_back("-analyzer-checker=core");
+ CmdArgs.push_back("-analyzer-checker=deadcode");
+ CmdArgs.push_back("-analyzer-checker=security");
+
if (getToolChain().getTriple().getOS() != llvm::Triple::Win32)
CmdArgs.push_back("-analyzer-checker=unix");
- if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
- CmdArgs.push_back("-analyzer-checker=macosx");
-
- // Checks to perform for Objective-C/Objective-C++.
- if (types::isObjC(InputType)) {
- // Enable all checkers in 'cocoa' package.
- CmdArgs.push_back("-analyzer-checker=cocoa");
- }
- // NOTE: Leaving -analyzer-check-objc-mem here is intentional.
- // It also checks C code.
- CmdArgs.push_back("-analyzer-check-objc-mem");
-
- CmdArgs.push_back("-analyzer-eagerly-assume");
+ if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
+ CmdArgs.push_back("-analyzer-checker=osx");
}
// Set the output format. The default is plist, for (lame) historical
@@ -1006,7 +1125,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (!Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants))
- CmdArgs.push_back("-no-merge-all-constants");
+ CmdArgs.push_back("-fno-merge-all-constants");
// LLVM Code Generator Options.
@@ -1015,6 +1134,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
+ CmdArgs.push_back("-mrtd");
+
// FIXME: Set --enable-unsafe-fp-math.
if (Args.hasFlag(options::OPT_fno_omit_frame_pointer,
options::OPT_fomit_frame_pointer))
@@ -1049,6 +1171,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getTriple().getOS() != llvm::Triple::Darwin)
CmdArgs.push_back("-mconstructor-aliases");
+ // Darwin's kernel doesn't support guard variables; just die if we
+ // try to use them.
+ if (KernelOrKext &&
+ getToolChain().getTriple().getOS() == llvm::Triple::Darwin)
+ CmdArgs.push_back("-fforbid-guard-variables");
+
if (Args.hasArg(options::OPT_mms_bitfields)) {
CmdArgs.push_back("-mms-bitfields");
}
@@ -1085,7 +1213,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::arm:
case llvm::Triple::thumb:
- AddARMTargetArgs(Args, CmdArgs);
+ AddARMTargetArgs(Args, CmdArgs, KernelOrKext);
break;
case llvm::Triple::mips:
@@ -1150,6 +1278,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_P);
Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
+ if (D.CCLogDiagnostics) {
+ CmdArgs.push_back("-diagnostic-log-file");
+ CmdArgs.push_back(D.CCLogDiagnosticsFilename ?
+ D.CCLogDiagnosticsFilename : "-");
+ }
+
// Special case debug options to only pass -g to clang. This is
// wrong.
Args.ClaimAllArgs(options::OPT_g_Group);
@@ -1162,6 +1296,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions);
+ if (Args.hasArg(options::OPT_ftest_coverage) ||
+ Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back("-femit-coverage-notes");
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back("-femit-coverage-data");
+
Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
@@ -1187,10 +1328,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else if (A->getOption().matches(options::OPT_O) &&
A->getValue(Args)[0] == '\0')
CmdArgs.push_back("-O2");
- else if (A->getOption().matches(options::OPT_O) &&
- A->getValue(Args)[0] == 'z' &&
- A->getValue(Args)[1] == '\0')
- CmdArgs.push_back("-Os");
else
A->render(Args, CmdArgs);
}
@@ -1231,6 +1368,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
}
+ // Map the bizarre '-Wwrite-strings' flag to a more sensible
+ // '-fconst-strings'; this better indicates its actual behavior.
+ if (Args.hasFlag(options::OPT_Wwrite_strings, options::OPT_Wno_write_strings,
+ false)) {
+ // For perfect compatibility with GCC, we do this even in the presence of
+ // '-w'. This flag names something other than a warning for GCC.
+ CmdArgs.push_back("-fconst-strings");
+ }
+
+ // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active
+ // during C++ compilation, which it is by default. GCC keeps this define even
+ // in the presence of '-w', match this behavior bug-for-bug.
+ if (types::isCXX(InputType) &&
+ Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated,
+ true)) {
+ CmdArgs.push_back("-fdeprecated-macro");
+ }
+
// Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
if (Asm->getOption().matches(options::OPT_fasm))
@@ -1239,6 +1394,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-gnu-keywords");
}
+ if (ShouldDisableCFI(Args, getToolChain()))
+ CmdArgs.push_back("-fno-dwarf2-cfi-asm");
+
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_)) {
CmdArgs.push_back("-ftemplate-depth");
CmdArgs.push_back(A->getValue(Args));
@@ -1311,7 +1469,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
- Args.AddLastArg(CmdArgs, options::OPT_pg);
+ if (getToolChain().SupportsProfiling())
+ Args.AddLastArg(CmdArgs, options::OPT_pg);
// -flax-vector-conversions is default.
if (!Args.hasFlag(options::OPT_flax_vector_conversions,
@@ -1348,7 +1507,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
- Args.AddLastArg(CmdArgs, options::OPT_fwrapv);
+ // Forward -ftrap_function= options to the backend.
+ if (Arg *A = Args.getLastArg(options::OPT_ftrap_function_EQ)) {
+ llvm::StringRef FuncName = A->getValue(Args);
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back(Args.MakeArgString("-trap-func=" + FuncName));
+ }
+
+ // -fno-strict-overflow implies -fwrapv if it isn't disabled, but
+ // -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
+ if (Arg *A = Args.getLastArg(options::OPT_fwrapv,
+ options::OPT_fno_wrapv)) {
+ if (A->getOption().matches(options::OPT_fwrapv))
+ CmdArgs.push_back("-fwrapv");
+ } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
+ options::OPT_fno_strict_overflow)) {
+ if (A->getOption().matches(options::OPT_fno_strict_overflow))
+ CmdArgs.push_back("-fwrapv");
+ }
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
Args.AddLastArg(CmdArgs, options::OPT_funroll_loops);
@@ -1389,7 +1565,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fblocks=0 is default.
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
- getToolChain().IsBlocksDefault())) {
+ getToolChain().IsBlocksDefault()) ||
+ (Args.hasArg(options::OPT_fgnu_runtime) &&
+ Args.hasArg(options::OPT_fobjc_nonfragile_abi) &&
+ !Args.hasArg(options::OPT_fno_blocks))) {
CmdArgs.push_back("-fblocks");
}
@@ -1405,10 +1584,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fno-elide-constructors");
- // -fexceptions=0 is default.
- if (!KernelOrKext &&
- needsExceptions(Args, InputType, getToolChain().getTriple()))
- CmdArgs.push_back("-fexceptions");
+ // Add exception args.
+ addExceptionArgs(Args, InputType, getToolChain().getTriple(),
+ KernelOrKext, IsRewriter, CmdArgs);
if (getToolChain().UseSjLjExceptions())
CmdArgs.push_back("-fsjlj-exceptions");
@@ -1463,6 +1641,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_borland_extensions, false))
CmdArgs.push_back("-fborland-extensions");
+ // -fno-delayed-template-parsing is default.
+ if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
+ options::OPT_fno_delayed_template_parsing,
+ false))
+ CmdArgs.push_back("-fdelayed-template-parsing");
+
// -fgnu-keywords default varies depending on language; only pass if
// specified.
if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,
@@ -1539,17 +1723,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ // FIXME: Don't expose -fobjc-default-synthesize-properties as a top-level
+ // driver flag yet. This feature is still under active development
+ // and shouldn't be exposed as a user visible feature (which may change).
+ // Clang still supports this as a -cc1 option for development and testing.
+#if 0
// -fobjc-default-synthesize-properties=0 is default.
if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties,
options::OPT_fno_objc_default_synthesize_properties,
getToolChain().IsObjCDefaultSynthPropertiesDefault())) {
CmdArgs.push_back("-fobjc-default-synthesize-properties");
}
-
- // -fno-objc-exceptions is default.
- if (IsRewriter || Args.hasFlag(options::OPT_fobjc_exceptions,
- options::OPT_fno_objc_exceptions))
- CmdArgs.push_back("-fobjc-exceptions");
+#endif
}
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
@@ -1613,6 +1798,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
options::OPT_fno_diagnostics_fixit_info))
CmdArgs.push_back("-fno-diagnostics-fixit-info");
+
+ // Enable -fdiagnostics-show-name by default.
+ if (Args.hasFlag(options::OPT_fdiagnostics_show_name,
+ options::OPT_fno_diagnostics_show_name, false))
+ CmdArgs.push_back("-fdiagnostics-show-name");
// Enable -fdiagnostics-show-option by default.
if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
@@ -1625,6 +1815,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (Arg *A = Args.getLastArg(
+ options::OPT_fdiagnostics_show_note_include_stack,
+ options::OPT_fno_diagnostics_show_note_include_stack)) {
+ if (A->getOption().matches(
+ options::OPT_fdiagnostics_show_note_include_stack))
+ CmdArgs.push_back("-fdiagnostics-show-note-include-stack");
+ else
+ CmdArgs.push_back("-fno-diagnostics-show-note-include-stack");
+ }
+
// Color diagnostics are the default, unless the terminal doesn't support
// them.
if (Args.hasFlag(options::OPT_fcolor_diagnostics,
@@ -1680,9 +1880,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
#endif
+ // Only allow -traditional or -traditional-cpp outside in preprocessing modes.
if (Arg *A = Args.getLastArg(options::OPT_traditional,
- options::OPT_traditional_cpp))
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ options::OPT_traditional_cpp)) {
+ if (isa<PreprocessJobAction>(JA))
+ CmdArgs.push_back("-traditional-cpp");
+ else
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ }
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
@@ -1762,6 +1967,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// care to warn the user about.
Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
+
+ // Disable warnings for clang -E -use-gold-plugin -emit-llvm foo.c
+ Args.ClaimAllArgs(options::OPT_use_gold_plugin);
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
}
void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
@@ -1776,6 +1985,10 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// Don't warn about "clang -w -c foo.s"
Args.ClaimAllArgs(options::OPT_w);
+ // and "clang -emit-llvm -c foo.s"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and "clang -use-gold-plugin -c foo.s"
+ Args.ClaimAllArgs(options::OPT_use_gold_plugin);
// Invoke ourselves in -cc1as mode.
//
@@ -1801,7 +2014,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
!IsOpt))
CmdArgs.push_back("-relax-all");
- // FIXME: Add -force_cpusubtype_ALL support, once we have it.
+ // Ignore explicit -force_cpusubtype_ALL option.
+ (void) Args.hasArg(options::OPT_force__cpusubtype__ALL);
// FIXME: Add -g support, once we have it.
@@ -1809,6 +2023,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
+ Args.AddAllArgs(CmdArgs, options::OPT_mllvm);
assert(Output.isFilename() && "Unexpected lipo output.");
CmdArgs.push_back("-o");
@@ -1924,7 +2139,20 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- const char *GCCName = getToolChain().getDriver().getCCCGenericGCCName().c_str();
+ const std::string customGCCName = D.getCCCGenericGCCName();
+ const char *GCCName;
+ if (!customGCCName.empty())
+ GCCName = customGCCName.c_str();
+ else if (D.CCCIsCXX) {
+#ifdef IS_CYGWIN15
+ // FIXME: Detect the version of Cygwin at runtime?
+ GCCName = "g++-4";
+#else
+ GCCName = "g++";
+#endif
+ } else
+ GCCName = "gcc";
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -2038,10 +2266,6 @@ void darwin::CC1::AddCC1Args(const ArgList &Args,
CmdArgs.push_back("-fno-builtin-strcpy");
}
- // gcc has some code here to deal with when no -mmacosx-version-min
- // and no -miphoneos-version-min is present, but this never happens
- // due to tool chain specific argument translation.
-
if (Args.hasArg(options::OPT_g_Flag) &&
!Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols))
CmdArgs.push_back("-feliminate-unused-debug-symbols");
@@ -2105,7 +2329,8 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
if (Args.hasArg(options::OPT_v))
CmdArgs.push_back("-version");
- if (Args.hasArg(options::OPT_pg))
+ if (Args.hasArg(options::OPT_pg) &&
+ getToolChain().SupportsProfiling())
CmdArgs.push_back("-p");
Args.AddLastArg(CmdArgs, options::OPT_p);
@@ -2128,6 +2353,9 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
} else
Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
+ // Claim Clang only -f options, they aren't worth warning about.
+ Args.ClaimAllArgs(options::OPT_f_clang_Group);
+
Args.AddAllArgs(CmdArgs, options::OPT_undef);
if (Args.hasArg(options::OPT_Qn))
CmdArgs.push_back("-fno-ident");
@@ -2185,6 +2413,9 @@ void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
// The driver treats -fsyntax-only specially.
Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
+ // Claim Clang only -f options, they aren't worth warning about.
+ Args.ClaimAllArgs(options::OPT_f_clang_Group);
+
if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) &&
!Args.hasArg(options::OPT_fno_working_directory))
CmdArgs.push_back("-fworking-directory");
@@ -2316,7 +2547,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
OutputArgs.push_back("-o");
OutputArgs.push_back(Output.getFilename());
- if (Args.hasArg(options::OPT_E)) {
+ if (Args.hasArg(options::OPT_E) || getToolChain().getDriver().CCCIsCPP) {
AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
} else {
AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
@@ -2436,11 +2667,16 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
assert(Inputs.size() == 1 && "Unexpected number of inputs.");
const InputInfo &Input = Inputs[0];
- // Bit of a hack, this is only used for original inputs.
- //
- // FIXME: This is broken for preprocessed .s inputs.
- if (Input.isFilename() &&
- strcmp(Input.getFilename(), Input.getBaseInput()) == 0) {
+ // Determine the original source input.
+ const Action *SourceAction = &JA;
+ while (SourceAction->getKind() != Action::InputClass) {
+ assert(!SourceAction->getInputs().empty() && "unexpected root action!");
+ SourceAction = SourceAction->getInputs()[0];
+ }
+
+ // Forward -g, assuming we are dealing with an actual assembly file.
+ if (SourceAction->getType() == types::TY_Asm ||
+ SourceAction->getType() == types::TY_PP_Asm) {
if (Args.hasArg(options::OPT_gstabs))
CmdArgs.push_back("--gstabs");
else if (Args.hasArg(options::OPT_g_Group))
@@ -2496,6 +2732,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
const ArgList &Args,
ArgStringList &CmdArgs) 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)) {
@@ -2515,7 +2752,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
// will match the linker version detected at configure time. We need the
// universal driver.
if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle) &&
- !getDarwinToolChain().isTargetIPhoneOS()) {
+ !DarwinTC.isTargetIPhoneOS()) {
// Don't pass -demangle to ld_classic.
//
// FIXME: This is a temporary workaround, ld should be handling this.
@@ -2590,7 +2827,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddLastArg(CmdArgs, options::OPT_all__load);
Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
- if (getDarwinToolChain().isTargetIPhoneOS())
+ if (DarwinTC.isTargetIPhoneOS())
Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal);
Args.AddLastArg(CmdArgs, options::OPT_dead__strip);
Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms);
@@ -2602,15 +2839,27 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddAllArgs(CmdArgs, options::OPT_image__base);
Args.AddAllArgs(CmdArgs, options::OPT_init);
- // Adding all arguments doesn't make sense here but this is what gcc does. One
- // of this should always be present thanks to argument translation.
- assert((Args.hasArg(options::OPT_mmacosx_version_min_EQ) ||
- Args.hasArg(options::OPT_miphoneos_version_min_EQ)) &&
- "Missing version argument (lost in translation)?");
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ,
- "-macosx_version_min");
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ,
- "-iphoneos_version_min");
+ // Add the deployment target.
+ unsigned TargetVersion[3];
+ DarwinTC.getTargetVersion(TargetVersion);
+
+ // If we had an explicit -mios-simulator-version-min argument, honor that,
+ // otherwise use the traditional deployment targets. We can't just check the
+ // is-sim attribute because existing code follows this path, and the linker
+ // may not handle the argument.
+ //
+ // FIXME: We may be able to remove this, once we can verify no one depends on
+ // it.
+ if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ))
+ CmdArgs.push_back("-ios_simulator_version_min");
+ else if (DarwinTC.isTargetIPhoneOS())
+ CmdArgs.push_back("-iphoneos_version_min");
+ else
+ CmdArgs.push_back("-macosx_version_min");
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine(TargetVersion[0]) + "." +
+ llvm::Twine(TargetVersion[1]) + "." +
+ llvm::Twine(TargetVersion[2])));
+
Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
Args.AddLastArg(CmdArgs, options::OPT_multi__module);
Args.AddLastArg(CmdArgs, options::OPT_single__module);
@@ -2716,7 +2965,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Derived from startfile spec.
if (Args.hasArg(options::OPT_dynamiclib)) {
// Derived from darwin_dylib1 spec.
- if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isTargetIOSSimulator()) {
+ // The simulator doesn't have a versioned crt1 file.
+ CmdArgs.push_back("-ldylib1.o");
+ } else if (getDarwinToolChain().isTargetIPhoneOS()) {
if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
CmdArgs.push_back("-ldylib1.o");
} else {
@@ -2729,7 +2981,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_bundle)) {
if (!Args.hasArg(options::OPT_static)) {
// Derived from darwin_bundle1 spec.
- if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isTargetIOSSimulator()) {
+ // The simulator doesn't have a versioned crt1 file.
+ CmdArgs.push_back("-lbundle1.o");
+ } else if (getDarwinToolChain().isTargetIPhoneOS()) {
if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
CmdArgs.push_back("-lbundle1.o");
} else {
@@ -2738,7 +2993,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
} else {
- if (Args.hasArg(options::OPT_pg)) {
+ if (Args.hasArg(options::OPT_pg) &&
+ getToolChain().SupportsProfiling()) {
if (Args.hasArg(options::OPT_static) ||
Args.hasArg(options::OPT_object) ||
Args.hasArg(options::OPT_preload)) {
@@ -2755,7 +3011,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lcrt0.o");
} else {
// Derived from darwin_crt1 spec.
- if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isTargetIOSSimulator()) {
+ // The simulator doesn't have a versioned crt1 file.
+ CmdArgs.push_back("-lcrt1.o");
+ } else if (getDarwinToolChain().isTargetIPhoneOS()) {
if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
CmdArgs.push_back("-lcrt1.o");
else
@@ -3150,6 +3409,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
@@ -3200,7 +3462,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
- CmdArgs.push_back("-L/usr/lib");
+ const ToolChain::path_list Paths = getToolChain().getFilePaths();
+ for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
+ i != e; ++i)
+ CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i));
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
Args.AddAllArgs(CmdArgs, options::OPT_s);
@@ -3312,8 +3577,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
}
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
+ "as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3325,6 +3590,9 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
@@ -3423,8 +3691,8 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
+ "ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3476,14 +3744,14 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Silence warning for "clang -g foo.o -o foo"
Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
// and for "clang -g foo.o -o foo". Other warning options are already
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
- if (Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) {
- CmdArgs.push_back("--sysroot");
- CmdArgs.push_back(A->getValue(Args));
- }
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
if (Args.hasArg(options::OPT_pie))
CmdArgs.push_back("-pie");
@@ -3506,13 +3774,19 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-m");
if (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("elf_i386");
- else if (ToolChain.getArch() == llvm::Triple::arm)
+ else if (ToolChain.getArch() == llvm::Triple::arm
+ || ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("armelf_linux_eabi");
+ else if (ToolChain.getArch() == llvm::Triple::ppc)
+ CmdArgs.push_back("elf32ppclinux");
+ else if (ToolChain.getArch() == llvm::Triple::ppc64)
+ CmdArgs.push_back("elf64ppc");
else
CmdArgs.push_back("elf_x86_64");
if (Args.hasArg(options::OPT_static)) {
- if (ToolChain.getArch() == llvm::Triple::arm)
+ if (ToolChain.getArch() == llvm::Triple::arm
+ || ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("-Bstatic");
else
CmdArgs.push_back("-static");
@@ -3521,13 +3795,19 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
if (ToolChain.getArch() == llvm::Triple::arm ||
+ ToolChain.getArch() == llvm::Triple::thumb ||
(!Args.hasArg(options::OPT_static) &&
!Args.hasArg(options::OPT_shared))) {
CmdArgs.push_back("-dynamic-linker");
if (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("/lib/ld-linux.so.2");
- else if (ToolChain.getArch() == llvm::Triple::arm)
+ else if (ToolChain.getArch() == llvm::Triple::arm ||
+ ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("/lib/ld-linux.so.3");
+ else if (ToolChain.getArch() == llvm::Triple::ppc)
+ CmdArgs.push_back("/lib/ld.so.1");
+ else if (ToolChain.getArch() == llvm::Triple::ppc64)
+ CmdArgs.push_back("/lib64/ld64.so.1");
else
CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2");
}
@@ -3563,12 +3843,9 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const ToolChain::path_list Paths = ToolChain.getFilePaths();
- for (ToolChain::path_list::const_iterator i = Paths.begin(),
- e = Paths.end();
- i != e; ++i) {
- const std::string &s = *i;
- CmdArgs.push_back(Args.MakeArgString(std::string("-L") + s));
- }
+ for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
+ i != e; ++i)
+ CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i));
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
@@ -3763,6 +4040,9 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 10c883900933..93abf75722eb 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -34,7 +34,8 @@ namespace tools {
const InputInfo &Output,
const InputInfoList &Inputs) const;
- void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ bool KernelOrKext) const;
void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 92fb1e8cbeb0..ecd6ef442aea 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/Frontend/DocumentXML.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
@@ -51,39 +50,6 @@ ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
return new ASTPrinter(out);
}
-//===----------------------------------------------------------------------===//
-/// ASTPrinterXML - XML-printer of ASTs
-
-namespace {
- class ASTPrinterXML : public ASTConsumer {
- DocumentXML Doc;
-
- public:
- ASTPrinterXML(llvm::raw_ostream& o) : Doc("CLANG_XML", o) {}
-
- void Initialize(ASTContext &Context) {
- Doc.initialize(Context);
- }
-
- virtual void HandleTranslationUnit(ASTContext &Ctx) {
- Doc.addSubNode("TranslationUnit");
- for (DeclContext::decl_iterator
- D = Ctx.getTranslationUnitDecl()->decls_begin(),
- DEnd = Ctx.getTranslationUnitDecl()->decls_end();
- D != DEnd;
- ++D)
- Doc.PrintDecl(*D);
- Doc.toParent();
- Doc.finalize();
- }
- };
-} // end anonymous namespace
-
-
-ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) {
- return new ASTPrinterXML(out ? *out : llvm::outs());
-}
-
ASTConsumer *clang::CreateASTDumper() {
return new ASTPrinter(0, true);
}
@@ -369,8 +335,9 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<field> " << FD << '\n';
break;
}
- case Decl::Typedef: {
- TypedefDecl* TD = cast<TypedefDecl>(*I);
+ case Decl::Typedef:
+ case Decl::TypeAlias: {
+ TypedefNameDecl* TD = cast<TypedefNameDecl>(*I);
Out << "<typedef> " << TD << '\n';
break;
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index a7942e6090c8..2a1244841e3b 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -20,6 +20,8 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
@@ -34,6 +36,7 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Atomic.h"
@@ -42,6 +45,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdlib>
#include <cstdio>
#include <sys/stat.h>
@@ -90,8 +94,10 @@ const unsigned DefaultPreambleRebuildInterval = 5;
static llvm::sys::cas_flag ActiveASTUnitObjects;
ASTUnit::ASTUnit(bool _MainFileIsAST)
- : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
+ : OnlyLocalDecls(false), CaptureDiagnostics(false),
+ MainFileIsAST(_MainFileIsAST),
CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")),
+ OwnsRemappedFileBuffers(true),
NumStoredDiagnosticsFromDriver(0),
ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
@@ -116,7 +122,7 @@ ASTUnit::~ASTUnit() {
// perform this operation here because we explicitly request that the
// compiler instance *not* free these buffers for each invocation of the
// parser.
- if (Invocation.get()) {
+ if (Invocation.getPtr() && OwnsRemappedFileBuffers) {
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
for (PreprocessorOptions::remapped_file_buffer_iterator
FB = PPOpts.remapped_file_buffer_begin(),
@@ -496,33 +502,69 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
unsigned NumRemappedFiles,
bool CaptureDiagnostics) {
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
+ ASTUnitCleanup(AST.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
+ llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ DiagCleanup(Diags.getPtr());
+
ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
- AST->FileMgr.reset(new FileManager(FileSystemOpts));
- AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics(),
- AST->getFileManager()));
+ AST->FileMgr = new FileManager(FileSystemOpts);
+ AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
+ AST->getFileManager());
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
- // Create the file entry for the file that we're mapping from.
- const FileEntry *FromFile
- = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
- RemappedFiles[I].second->getBufferSize(),
- 0);
- if (!FromFile) {
- AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
- << RemappedFiles[I].first;
- delete RemappedFiles[I].second;
- continue;
+ FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
+ if (const llvm::MemoryBuffer *
+ memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile
+ = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
+ memBuf->getBufferSize(),
+ 0);
+ if (!FromFile) {
+ AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
+ << RemappedFiles[I].first;
+ delete memBuf;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ AST->getSourceManager().overrideFileContents(FromFile, memBuf);
+
+ } else {
+ const char *fname = fileOrBuf.get<const char *>();
+ const FileEntry *ToFile = AST->FileMgr->getFile(fname);
+ if (!ToFile) {
+ AST->getDiagnostics().Report(diag::err_fe_remap_missing_to_file)
+ << RemappedFiles[I].first << fname;
+ continue;
+ }
+
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile
+ = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
+ ToFile->getSize(),
+ 0);
+ if (!FromFile) {
+ AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
+ << RemappedFiles[I].first;
+ delete memBuf;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ AST->getSourceManager().overrideFileContents(FromFile, ToFile);
}
-
- // Override the contents of the "from" file with the contents of
- // the "to" file.
- AST->getSourceManager().overrideFileContents(FromFile,
- RemappedFiles[I].second);
}
// Gather Info for preprocessor construction later on.
@@ -563,12 +605,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
TargetOpts.CPU = "";
TargetOpts.Features.clear();
TargetOpts.Triple = TargetTriple;
- AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
- TargetOpts));
- AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
- *AST->Target.get(),
- AST->getSourceManager(), HeaderInfo));
- Preprocessor &PP = *AST->PP.get();
+ AST->Target = TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
+ TargetOpts);
+ AST->PP = new Preprocessor(AST->getDiagnostics(), LangInfo, *AST->Target,
+ AST->getSourceManager(), HeaderInfo);
+ Preprocessor &PP = *AST->PP;
PP.setPredefines(Reader->getSuggestedPredefines());
PP.setCounterValue(Counter);
@@ -576,14 +617,14 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Create and initialize the ASTContext.
- AST->Ctx.reset(new ASTContext(LangInfo,
- AST->getSourceManager(),
- *AST->Target.get(),
- PP.getIdentifierTable(),
- PP.getSelectorTable(),
- PP.getBuiltinInfo(),
- /* size_reserve = */0));
- ASTContext &Context = *AST->Ctx.get();
+ AST->Ctx = new ASTContext(LangInfo,
+ AST->getSourceManager(),
+ *AST->Target,
+ PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ PP.getBuiltinInfo(),
+ /* size_reserve = */0);
+ ASTContext &Context = *AST->Ctx;
Reader->InitializeContext(Context);
@@ -803,25 +844,30 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
delete SavedMainFileBuffer;
SavedMainFileBuffer = 0;
- if (!Invocation.get()) {
+ if (!Invocation) {
delete OverrideMainBuffer;
return true;
}
// Create the compiler instance to use for building the AST.
- CompilerInstance Clang;
- Clang.setInvocation(Invocation.take());
- OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
+ llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
+ CICleanup(Clang.get());
+
+ Clang->setInvocation(&*Invocation);
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
- Clang.setDiagnostics(&getDiagnostics());
+ Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang.getTargetOpts().Features = TargetFeatures;
- Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
- Clang.getTargetOpts()));
- if (!Clang.hasTarget()) {
+ Clang->getTargetOpts().Features = TargetFeatures;
+ Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
+ Clang->getTargetOpts()));
+ if (!Clang->hasTarget()) {
delete OverrideMainBuffer;
return true;
}
@@ -830,23 +876,23 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+ Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
- assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
// FIXME: Should we retain the previous file manager?
- FileSystemOpts = Clang.getFileSystemOpts();
- FileMgr.reset(new FileManager(Clang.getFileSystemOpts()));
- SourceMgr.reset(new SourceManager(getDiagnostics(), *FileMgr));
+ FileSystemOpts = Clang->getFileSystemOpts();
+ FileMgr = new FileManager(FileSystemOpts);
+ SourceMgr = new SourceManager(getDiagnostics(), *FileMgr);
TheSema.reset();
- Ctx.reset();
- PP.reset();
+ Ctx = 0;
+ PP = 0;
// Clear out old caches and data.
TopLevelDecls.clear();
@@ -863,14 +909,14 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
}
// Create a file manager object to provide access to and cache the filesystem.
- Clang.setFileManager(&getFileManager());
+ Clang->setFileManager(&getFileManager());
// Create the source manager.
- Clang.setSourceManager(&getSourceManager());
+ Clang->setSourceManager(&getSourceManager());
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts();
+ PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
std::string PriorImplicitPCHInclude;
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
@@ -901,23 +947,27 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
}
- llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
- Act.reset(new TopLevelDeclTrackerAction(*this));
- if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
- Clang.getFrontendOpts().Inputs[0].first))
+ llvm::OwningPtr<TopLevelDeclTrackerAction> Act(
+ new TopLevelDeclTrackerAction(*this));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
+ ActCleanup(Act.get());
+
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
+ Clang->getFrontendOpts().Inputs[0].first))
goto error;
Act->Execute();
- // Steal the created target, context, and preprocessor, and take back the
- // source and file managers.
- TheSema.reset(Clang.takeSema());
- Consumer.reset(Clang.takeASTConsumer());
- Ctx.reset(Clang.takeASTContext());
- PP.reset(Clang.takePreprocessor());
- Clang.takeSourceManager();
- Clang.takeFileManager();
- Target.reset(Clang.takeTarget());
+ // Steal the created target, context, and preprocessor.
+ TheSema.reset(Clang->takeSema());
+ Consumer.reset(Clang->takeASTConsumer());
+ Ctx = &Clang->getASTContext();
+ PP = &Clang->getPreprocessor();
+ Clang->setSourceManager(0);
+ Clang->setFileManager(0);
+ Target = &Clang->getTarget();
Act->EndSourceFile();
@@ -928,9 +978,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
}
- Invocation.reset(Clang.takeInvocation());
return false;
-
+
error:
// Remove the overridden buffer we used for the preamble.
if (OverrideMainBuffer) {
@@ -942,9 +991,6 @@ error:
}
StoredDiagnostics.clear();
- Clang.takeSourceManager();
- Clang.takeFileManager();
- Invocation.reset(Clang.takeInvocation());
return true;
}
@@ -1146,7 +1192,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
!AnyFileChanged && R != REnd;
++R) {
struct stat StatBuf;
- if (stat(R->second.c_str(), &StatBuf)) {
+ if (FileMgr->getNoncachedStatValue(R->second, StatBuf)) {
// If we can't stat the file we're remapping to, assume that something
// horrible happened.
AnyFileChanged = true;
@@ -1184,7 +1230,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// The file was not remapped; check whether it has changed on disk.
struct stat StatBuf;
- if (stat(F->first(), &StatBuf)) {
+ if (FileMgr->getNoncachedStatValue(F->first(), StatBuf)) {
// If we can't stat the file, assume that something horrible happened.
AnyFileChanged = true;
} else if (StatBuf.st_size != F->second.first ||
@@ -1292,18 +1338,23 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
// Create the compiler instance to use for building the precompiled preamble.
- CompilerInstance Clang;
- Clang.setInvocation(&PreambleInvocation);
- OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
+ llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
+ CICleanup(Clang.get());
+
+ Clang->setInvocation(&PreambleInvocation);
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
// Set up diagnostics, capturing all of the diagnostics produced.
- Clang.setDiagnostics(&getDiagnostics());
+ Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang.getTargetOpts().Features = TargetFeatures;
- Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
- Clang.getTargetOpts()));
- if (!Clang.hasTarget()) {
+ Clang->getTargetOpts().Features = TargetFeatures;
+ Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
+ Clang->getTargetOpts()));
+ if (!Clang->hasTarget()) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
@@ -1316,18 +1367,18 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+ Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
- assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
"IR inputs not support here!");
// Clear out old caches and data.
getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(), Clang.getDiagnosticOpts());
+ ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts());
StoredDiagnostics.erase(
StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
StoredDiagnostics.end());
@@ -1337,17 +1388,16 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
PreprocessedEntitiesInPreamble.clear();
// Create a file manager object to provide access to and cache the filesystem.
- Clang.setFileManager(new FileManager(Clang.getFileSystemOpts()));
+ Clang->setFileManager(new FileManager(Clang->getFileSystemOpts()));
// Create the source manager.
- Clang.setSourceManager(new SourceManager(getDiagnostics(),
- Clang.getFileManager()));
+ Clang->setSourceManager(new SourceManager(getDiagnostics(),
+ Clang->getFileManager()));
llvm::OwningPtr<PrecompilePreambleAction> Act;
Act.reset(new PrecompilePreambleAction(*this));
- if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
- Clang.getFrontendOpts().Inputs[0].first)) {
- Clang.takeInvocation();
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
+ Clang->getFrontendOpts().Inputs[0].first)) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
@@ -1358,8 +1408,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Act->Execute();
Act->EndSourceFile();
- Clang.takeInvocation();
-
+
if (Diagnostics->hasErrorOccurred()) {
// There were errors parsing the preamble, so no precompiled header was
// generated. Forget that we even tried.
@@ -1383,14 +1432,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Keep track of all of the files that the source manager knows about,
// so we can verify whether they have changed or not.
FilesInPreamble.clear();
- SourceManager &SourceMgr = Clang.getSourceManager();
+ SourceManager &SourceMgr = Clang->getSourceManager();
const llvm::MemoryBuffer *MainFileBuffer
= SourceMgr.getBuffer(SourceMgr.getMainFileID());
for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
FEnd = SourceMgr.fileinfo_end();
F != FEnd;
++F) {
- const FileEntry *File = F->second->Entry;
+ const FileEntry *File = F->second->OrigEntry;
if (!File || F->second->getRawBuffer() == MainFileBuffer)
continue;
@@ -1491,6 +1540,20 @@ llvm::StringRef ASTUnit::getMainFileName() const {
return Invocation->getFrontendOpts().Inputs[0].second;
}
+ASTUnit *ASTUnit::create(CompilerInvocation *CI,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags) {
+ llvm::OwningPtr<ASTUnit> AST;
+ AST.reset(new ASTUnit(false));
+ ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics=*/false);
+ AST->Diagnostics = Diags;
+ AST->Invocation = CI;
+ AST->FileSystemOpts = CI->getFileSystemOpts();
+ AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ AST->SourceMgr = new SourceManager(*Diags, *AST->FileMgr);
+
+ return AST.take();
+}
+
bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
if (!Invocation)
return true;
@@ -1513,6 +1576,10 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
SimpleTimer ParsingTimer(WantTiming);
ParsingTimer.setOutput("Parsing " + getMainFileName());
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
+ MemBufferCleanup(OverrideMainBuffer);
+
return Parse(OverrideMainBuffer);
}
@@ -1532,8 +1599,15 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
- AST->Invocation.reset(CI);
+ AST->Invocation = CI;
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
+ ASTUnitCleanup(AST.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
+ llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ DiagCleanup(Diags.getPtr());
+
return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
}
@@ -1545,6 +1619,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
bool CaptureDiagnostics,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
+ bool RemappedFilesKeepOriginalName,
bool PrecompilePreamble,
bool CompleteTranslationUnit,
bool CacheCodeCompletionResults,
@@ -1557,63 +1632,35 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin,
ArgBegin);
}
-
- llvm::SmallVector<const char *, 16> Args;
- Args.push_back("<clang>"); // FIXME: Remove dummy argument.
- Args.insert(Args.end(), ArgBegin, ArgEnd);
-
- // FIXME: Find a cleaner way to force the driver into restricted modes. We
- // also want to force it to use clang.
- Args.push_back("-fsyntax-only");
llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
- llvm::OwningPtr<CompilerInvocation> CI;
+ llvm::IntrusiveRefCntPtr<CompilerInvocation> CI;
{
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
StoredDiagnostics);
- // FIXME: We shouldn't have to pass in the path info.
- driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
- "a.out", false, false, *Diags);
-
- // Don't check that inputs exist, they have been remapped.
- TheDriver.setCheckInputsExist(false);
-
- llvm::OwningPtr<driver::Compilation> C(
- TheDriver.BuildCompilation(Args.size(), Args.data()));
-
- // We expect to get back exactly one command job, if we didn't something
- // failed.
- const driver::JobList &Jobs = C->getJobs();
- if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
- llvm::SmallString<256> Msg;
- llvm::raw_svector_ostream OS(Msg);
- C->PrintJob(OS, C->getJobs(), "; ", true);
- Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
+ CI = clang::createInvocationFromCommandLine(
+ llvm::ArrayRef<const char *>(ArgBegin, ArgEnd-ArgBegin),
+ Diags);
+ if (!CI)
return 0;
- }
-
- const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
- Diags->Report(diag::err_fe_expected_clang_command);
- return 0;
- }
-
- const driver::ArgStringList &CCArgs = Cmd->getArguments();
- CI.reset(new CompilerInvocation);
- CompilerInvocation::CreateFromArgs(*CI,
- const_cast<const char **>(CCArgs.data()),
- const_cast<const char **>(CCArgs.data()) +
- CCArgs.size(),
- *Diags);
}
// Override any files that need remapping
- for (unsigned I = 0; I != NumRemappedFiles; ++I)
- CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
- RemappedFiles[I].second);
+ for (unsigned I = 0; I != NumRemappedFiles; ++I) {
+ FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
+ if (const llvm::MemoryBuffer *
+ memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
+ CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, memBuf);
+ } else {
+ const char *fname = fileOrBuf.get<const char *>();
+ CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname);
+ }
+ }
+ CI->getPreprocessorOpts().RemappedFilesKeepOriginalName =
+ RemappedFilesKeepOriginalName;
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
@@ -1633,8 +1680,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST.reset(new ASTUnit(false));
ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
-
- AST->FileMgr.reset(new FileManager(FileSystemOptions()));
+
+ AST->FileSystemOpts = CI->getFileSystemOpts();
+ AST->FileMgr = new FileManager(AST->FileSystemOpts);
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->CompleteTranslationUnit = CompleteTranslationUnit;
@@ -1642,12 +1690,23 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
- AST->Invocation.reset(CI.take());
+ AST->Invocation = CI;
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
+ ASTUnitCleanup(AST.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation,
+ llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> >
+ CICleanup(CI.getPtr());
+ llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
+ llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ DiagCleanup(Diags.getPtr());
+
return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take();
}
bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
- if (!Invocation.get())
+ if (!Invocation)
return true;
SimpleTimer ParsingTimer(WantTiming);
@@ -1664,9 +1723,18 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
delete R->second;
}
Invocation->getPreprocessorOpts().clearRemappedFiles();
- for (unsigned I = 0; I != NumRemappedFiles; ++I)
- Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
- RemappedFiles[I].second);
+ for (unsigned I = 0; I != NumRemappedFiles; ++I) {
+ FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
+ if (const llvm::MemoryBuffer *
+ memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
+ Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ memBuf);
+ } else {
+ const char *fname = fileOrBuf.get<const char *>();
+ Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ fname);
+ }
+ }
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
@@ -1934,16 +2002,18 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
SourceManager &SourceMgr, FileManager &FileMgr,
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) {
- if (!Invocation.get())
+ if (!Invocation)
return;
SimpleTimer CompletionTimer(WantTiming);
CompletionTimer.setOutput("Code completion @ " + File + ":" +
llvm::Twine(Line) + ":" + llvm::Twine(Column));
- CompilerInvocation CCInvocation(*Invocation);
- FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts = CCInvocation.getPreprocessorOpts();
+ llvm::IntrusiveRefCntPtr<CompilerInvocation>
+ CCInvocation(new CompilerInvocation(*Invocation));
+
+ FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts();
+ PreprocessorOptions &PreprocessorOpts = CCInvocation->getPreprocessorOpts();
FrontendOpts.ShowMacrosInCodeCompletion
= IncludeMacros && CachedCompletionResults.empty();
@@ -1955,25 +2025,30 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
FrontendOpts.CodeCompletionAt.Column = Column;
// Set the language options appropriately.
- LangOpts = CCInvocation.getLangOpts();
+ LangOpts = CCInvocation->getLangOpts();
- CompilerInstance Clang;
- Clang.setInvocation(&CCInvocation);
- OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
+ llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
+ CICleanup(Clang.get());
+
+ Clang->setInvocation(&*CCInvocation);
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
// Set up diagnostics, capturing any diagnostics produced.
- Clang.setDiagnostics(&Diag);
- ProcessWarningOptions(Diag, CCInvocation.getDiagnosticOpts());
+ Clang->setDiagnostics(&Diag);
+ ProcessWarningOptions(Diag, CCInvocation->getDiagnosticOpts());
CaptureDroppedDiagnostics Capture(true,
- Clang.getDiagnostics(),
+ Clang->getDiagnostics(),
StoredDiagnostics);
// Create the target instance.
- Clang.getTargetOpts().Features = TargetFeatures;
- Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
- Clang.getTargetOpts()));
- if (!Clang.hasTarget()) {
- Clang.takeInvocation();
+ Clang->getTargetOpts().Features = TargetFeatures;
+ Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
+ Clang->getTargetOpts()));
+ if (!Clang->hasTarget()) {
+ Clang->setInvocation(0);
return;
}
@@ -1981,27 +2056,33 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+ Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
- assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
"IR inputs not support here!");
// Use the source and file managers that we were given.
- Clang.setFileManager(&FileMgr);
- Clang.setSourceManager(&SourceMgr);
+ Clang->setFileManager(&FileMgr);
+ Clang->setSourceManager(&SourceMgr);
// Remap files.
PreprocessorOpts.clearRemappedFiles();
PreprocessorOpts.RetainRemappedFileBuffers = true;
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
- PreprocessorOpts.addRemappedFile(RemappedFiles[I].first,
- RemappedFiles[I].second);
- OwnedBuffers.push_back(RemappedFiles[I].second);
+ FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
+ if (const llvm::MemoryBuffer *
+ memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
+ PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, memBuf);
+ OwnedBuffers.push_back(memBuf);
+ } else {
+ const char *fname = fileOrBuf.get<const char *>();
+ PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, fname);
+ }
}
// Use the code completion consumer we were given, but adding any cached
@@ -2011,7 +2092,7 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
FrontendOpts.ShowMacrosInCodeCompletion,
FrontendOpts.ShowCodePatternsInCodeCompletion,
FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
- Clang.setCodeCompletionConsumer(AugmentedConsumer);
+ Clang->setCodeCompletionConsumer(AugmentedConsumer);
// 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
@@ -2026,7 +2107,7 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
if (const FileStatus *MainStatus = MainPath.getFileStatus())
if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID())
OverrideMainBuffer
- = getMainBufferWithPrecompiledPreamble(CCInvocation, false,
+ = getMainBufferWithPrecompiledPreamble(*CCInvocation, false,
Line - 1);
}
@@ -2063,16 +2144,11 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
llvm::OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
- if (Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
- Clang.getFrontendOpts().Inputs[0].first)) {
+ if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
+ Clang->getFrontendOpts().Inputs[0].first)) {
Act->Execute();
Act->EndSourceFile();
}
-
- // Steal back our resources.
- Clang.takeFileManager();
- Clang.takeSourceManager();
- Clang.takeInvocation();
}
bool ASTUnit::Save(llvm::StringRef File) {
@@ -2086,7 +2162,16 @@ bool ASTUnit::Save(llvm::StringRef File) {
llvm::raw_fd_ostream::F_Binary);
if (!ErrorInfo.empty() || Out.has_error())
return true;
-
+
+ serialize(Out);
+ Out.close();
+ return Out.has_error();
+}
+
+bool ASTUnit::serialize(llvm::raw_ostream &OS) {
+ if (getDiagnostics().hasErrorOccurred())
+ return true;
+
std::vector<unsigned char> Buffer;
llvm::BitstreamWriter Stream(Buffer);
ASTWriter Writer(Stream);
@@ -2094,7 +2179,7 @@ bool ASTUnit::Save(llvm::StringRef File) {
// Write the generated bitstream to "Out".
if (!Buffer.empty())
- Out.write((char *)&Buffer.front(), Buffer.size());
- Out.close();
- return Out.has_error();
+ OS.write((char *)&Buffer.front(), Buffer.size());
+
+ return false;
}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 9f197b4f8762..9d49e9039d91 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -16,10 +16,9 @@ add_clang_library(clangFrontend
CacheTokens.cpp
CompilerInstance.cpp
CompilerInvocation.cpp
- DeclXML.cpp
+ CreateInvocationFromCommandLine.cpp
DependencyFile.cpp
DiagChecker.cpp
- DocumentXML.cpp
FrontendAction.cpp
FrontendActions.cpp
FrontendOptions.cpp
@@ -27,12 +26,11 @@ add_clang_library(clangFrontend
InitHeaderSearch.cpp
InitPreprocessor.cpp
LangStandards.cpp
+ LogDiagnosticPrinter.cpp
MultiplexConsumer.cpp
PrintPreprocessedOutput.cpp
- StmtXML.cpp
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
- TypeXML.cpp
VerifyDiagnosticsClient.cpp
Warnings.cpp
)
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index ee3fdd834334..06a1fd29838b 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -288,12 +288,12 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) &&
ParsingPreprocessorDirective) {
- // Insert an eom token into the token cache. It has the same
+ // Insert an eod token into the token cache. It has the same
// position as the next token that is not on the same line as the
// preprocessor directive. Observe that we continue processing
// 'Tok' when we exit this branch.
Token Tmp = Tok;
- Tmp.setKind(tok::eom);
+ Tmp.setKind(tok::eod);
Tmp.clearFlag(Token::StartOfLine);
Tmp.setIdentifierInfo(0);
EmitToken(Tmp);
@@ -473,7 +473,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
E = SM.fileinfo_end(); I != E; ++I) {
const SrcMgr::ContentCache &C = *I->second;
- const FileEntry *FE = C.Entry;
+ const FileEntry *FE = C.OrigEntry;
// FIXME: Handle files with non-absolute paths.
if (llvm::sys::path::is_relative(FE->getName()))
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index fd593de560c0..ace3c5adb100 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -22,6 +22,7 @@
#include "clang/Frontend/ChainedDiagnosticClient.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/LogDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/VerifyDiagnosticsClient.h"
#include "clang/Frontend/Utils.h"
@@ -47,7 +48,7 @@ CompilerInstance::~CompilerInstance() {
}
void CompilerInstance::setInvocation(CompilerInvocation *Value) {
- Invocation.reset(Value);
+ Invocation = Value;
}
void CompilerInstance::setDiagnostics(Diagnostic *Value) {
@@ -55,24 +56,20 @@ void CompilerInstance::setDiagnostics(Diagnostic *Value) {
}
void CompilerInstance::setTarget(TargetInfo *Value) {
- Target.reset(Value);
+ Target = Value;
}
void CompilerInstance::setFileManager(FileManager *Value) {
- FileMgr.reset(Value);
+ FileMgr = Value;
}
-void CompilerInstance::setSourceManager(SourceManager *Value) {
- SourceMgr.reset(Value);
+void CompilerInstance::setSourceManager(SourceManager *Value) {
+ SourceMgr = Value;
}
-void CompilerInstance::setPreprocessor(Preprocessor *Value) {
- PP.reset(Value);
-}
+void CompilerInstance::setPreprocessor(Preprocessor *Value) { PP = Value; }
-void CompilerInstance::setASTContext(ASTContext *Value) {
- Context.reset(Value);
-}
+void CompilerInstance::setASTContext(ASTContext *Value) { Context = Value; }
void CompilerInstance::setSema(Sema *S) {
TheSema.reset(S);
@@ -110,15 +107,47 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
}
+static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
+ const CodeGenOptions *CodeGenOpts,
+ Diagnostic &Diags) {
+ std::string ErrorInfo;
+ bool OwnsStream = false;
+ llvm::raw_ostream *OS = &llvm::errs();
+ if (DiagOpts.DiagnosticLogFile != "-") {
+ // Create the output stream.
+ llvm::raw_fd_ostream *FileOS(
+ new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(),
+ ErrorInfo, llvm::raw_fd_ostream::F_Append));
+ if (!ErrorInfo.empty()) {
+ Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
+ << DiagOpts.DumpBuildInformation << ErrorInfo;
+ } else {
+ FileOS->SetUnbuffered();
+ FileOS->SetUseAtomicWrites(true);
+ OS = FileOS;
+ OwnsStream = true;
+ }
+ }
+
+ // Chain in the diagnostic client which will log the diagnostics.
+ LogDiagnosticPrinter *Logger = new LogDiagnosticPrinter(*OS, DiagOpts,
+ OwnsStream);
+ if (CodeGenOpts)
+ Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
+ Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
+}
+
void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
DiagnosticClient *Client) {
- Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client);
+ Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client,
+ &getCodeGenOpts());
}
llvm::IntrusiveRefCntPtr<Diagnostic>
CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
int Argc, const char* const *Argv,
- DiagnosticClient *Client) {
+ DiagnosticClient *Client,
+ const CodeGenOptions *CodeGenOpts) {
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID));
@@ -133,6 +162,10 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
if (Opts.VerifyDiagnostics)
Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient()));
+ // Chain in -diagnostic-log-file dumper, if requested.
+ if (!Opts.DiagnosticLogFile.empty())
+ SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
+
if (!Opts.DumpBuildInformation.empty())
SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
@@ -145,23 +178,23 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
// File Manager
void CompilerInstance::createFileManager() {
- FileMgr.reset(new FileManager(getFileSystemOpts()));
+ FileMgr = new FileManager(getFileSystemOpts());
}
// Source Manager
void CompilerInstance::createSourceManager(FileManager &FileMgr) {
- SourceMgr.reset(new SourceManager(getDiagnostics(), FileMgr));
+ SourceMgr = new SourceManager(getDiagnostics(), FileMgr);
}
// Preprocessor
void CompilerInstance::createPreprocessor() {
- PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
- getPreprocessorOpts(), getHeaderSearchOpts(),
- getDependencyOutputOpts(), getTarget(),
- getFrontendOpts(), getSourceManager(),
- getFileManager()));
+ PP = createPreprocessor(getDiagnostics(), getLangOpts(),
+ getPreprocessorOpts(), getHeaderSearchOpts(),
+ getDependencyOutputOpts(), getTarget(),
+ getFrontendOpts(), getSourceManager(),
+ getFileManager());
}
Preprocessor *
@@ -209,7 +242,8 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile;
if (OutputPath == "-")
OutputPath = "";
- AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath);
+ AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath,
+ /*ShowDepth=*/false);
}
return PP;
@@ -219,10 +253,10 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
void CompilerInstance::createASTContext() {
Preprocessor &PP = getPreprocessor();
- Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(),
- getTarget(), PP.getIdentifierTable(),
- PP.getSelectorTable(), PP.getBuiltinInfo(),
- /*size_reserve=*/ 0));
+ Context = new ASTContext(getLangOpts(), PP.getSourceManager(),
+ getTarget(), PP.getIdentifierTable(),
+ PP.getSelectorTable(), PP.getBuiltinInfo(),
+ /*size_reserve=*/ 0);
}
// ExternalASTSource
@@ -362,19 +396,22 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
delete it->OS;
if (!it->TempFilename.empty()) {
- llvm::sys::Path TempPath(it->TempFilename);
- if (EraseFiles)
- TempPath.eraseFromDisk();
- else {
- std::string Error;
- llvm::sys::Path NewOutFile(it->Filename);
+ if (EraseFiles) {
+ bool existed;
+ llvm::sys::fs::remove(it->TempFilename, existed);
+ } else {
+ llvm::SmallString<128> NewOutFile(it->Filename);
+
// If '-working-directory' was passed, the output filename should be
// relative to that.
- FileManager::FixupRelativePath(NewOutFile, getFileSystemOpts());
- if (TempPath.renamePathOnDisk(NewOutFile, &Error)) {
+ FileMgr->FixupRelativePath(NewOutFile);
+ if (llvm::error_code ec = llvm::sys::fs::rename(it->TempFilename,
+ NewOutFile.str())) {
getDiagnostics().Report(diag::err_fe_unable_to_rename_temp)
- << it->TempFilename << it->Filename << Error;
- TempPath.eraseFromDisk();
+ << it->TempFilename << it->Filename << ec.message();
+
+ bool existed;
+ llvm::sys::fs::remove(it->TempFilename, existed);
}
}
} else if (!it->Filename.empty() && EraseFiles)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b9d15ad01ab1..1d4cd15ac480 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -30,16 +30,6 @@
#include "llvm/Support/Path.h"
using namespace clang;
-static const char *getAnalysisName(Analyses Kind) {
- switch (Kind) {
- default:
- llvm_unreachable("Unknown analysis kind!");
-#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
- case NAME: return "-" CMDFLAG;
-#include "clang/Frontend/Analyses.def"
- }
-}
-
static const char *getAnalysisStoreName(AnalysisStores Kind) {
switch (Kind) {
default:
@@ -76,8 +66,6 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
std::vector<std::string> &Res) {
- for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i)
- Res.push_back(getAnalysisName(Opts.AnalysisList[i]));
if (Opts.ShowCheckerHelp)
Res.push_back("-analyzer-checker-help");
if (Opts.AnalysisStoreOpt != BasicStoreModel) {
@@ -102,8 +90,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-display-progress");
if (Opts.AnalyzeNestedBlocks)
Res.push_back("-analyzer-opt-analyze-nested-blocks");
- if (Opts.AnalyzerStats)
- Res.push_back("-analyzer-stats");
if (Opts.EagerlyAssume)
Res.push_back("-analyzer-eagerly-assume");
if (!Opts.PurgeDead)
@@ -112,12 +98,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-trim-egraph");
if (Opts.VisualizeEGDot)
Res.push_back("-analyzer-viz-egraph-graphviz");
- if (Opts.VisualizeEGDot)
+ if (Opts.VisualizeEGUbi)
Res.push_back("-analyzer-viz-egraph-ubigraph");
- if (Opts.EnableExperimentalChecks)
- Res.push_back("-analyzer-experimental-checks");
- if (Opts.BufferOverflows)
- Res.push_back("-analyzer-check-buffer-overflows");
for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) {
const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i];
@@ -141,17 +123,23 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-dwarf-debug-flags");
Res.push_back(Opts.DwarfDebugFlags);
}
+ if (Opts.EmitGcovArcs)
+ Res.push_back("-femit-coverage-data");
+ if (Opts.EmitGcovNotes)
+ Res.push_back("-femit-coverage-notes");
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.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!");
- Res.push_back("-Os");
+ 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()) {
@@ -213,6 +201,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
}
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.SoftFloat)
Res.push_back("-msoft-float");
if (Opts.UnwindTables)
@@ -223,6 +215,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
}
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");
+ Res.push_back(Opts.BackendOptions[i]);
+ }
}
static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
@@ -273,6 +269,8 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fcolor-diagnostics");
if (Opts.VerifyDiagnostics)
Res.push_back("-verify");
+ if (Opts.ShowNames)
+ Res.push_back("-fdiagnostics-show-name");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
if (Opts.ShowCategories == 1)
@@ -283,6 +281,10 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-ferror-limit");
Res.push_back(llvm::utostr(Opts.ErrorLimit));
}
+ if (!Opts.DiagnosticLogFile.empty()) {
+ Res.push_back("-diagnostic-log-file");
+ Res.push_back(Opts.DiagnosticLogFile);
+ }
if (Opts.MacroBacktraceLimit
!= DiagnosticOptions::DefaultMacroBacktraceLimit) {
Res.push_back("-fmacro-backtrace-limit");
@@ -340,7 +342,6 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::ASTDump: return "-ast-dump";
case frontend::ASTDumpXML: return "-ast-dump-xml";
case frontend::ASTPrint: return "-ast-print";
- case frontend::ASTPrintXML: return "-ast-print-xml";
case frontend::ASTView: return "-ast-view";
case frontend::BoostCon: return "-boostcon";
case frontend::CreateModule: return "-create-module";
@@ -578,7 +579,7 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.WritableStrings)
Res.push_back("-fwritable-strings");
if (Opts.ConstStrings)
- Res.push_back("-Wwrite-strings");
+ Res.push_back("-fconst-strings");
if (!Opts.LaxVectorConversions)
Res.push_back("-fno-lax-vector-conversions");
if (Opts.AltiVec)
@@ -591,6 +592,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
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)
@@ -687,6 +690,14 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fconstant-string-class");
Res.push_back(Opts.ObjCConstantStringClass);
}
+ if (Opts.FakeAddressSpaceMap)
+ Res.push_back("-ffake-address-space-map");
+ if (Opts.ParseUnknownAnytype)
+ Res.push_back("-funknown-anytype");
+ if (Opts.DelayedTemplateParsing)
+ Res.push_back("-fdelayed-template-parsing");
+ if (Opts.Deprecated)
+ Res.push_back("-fdeprecated-macro");
}
static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
@@ -723,6 +734,10 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
assert(Opts.ImplicitPTHInclude == Opts.TokenCache &&
"Unsupported option combination!");
}
+ for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i) {
+ Res.push_back("-chain-include");
+ Res.push_back(Opts.ChainedIncludes[i]);
+ }
for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) {
Res.push_back("-remap-file");
Res.push_back(Opts.RemappedFiles[i].first + ";" +
@@ -802,8 +817,8 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
unsigned DefaultOpt = 0;
if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable))
DefaultOpt = 2;
- // -Os implies -O2
- return Args.hasArg(OPT_Os) ? 2 :
+ // -Os/-Oz implies -O2
+ return (Args.hasArg(OPT_Os) || Args.hasArg (OPT_Oz)) ? 2 :
Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags);
}
@@ -811,11 +826,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Diagnostic &Diags) {
using namespace cc1options;
- Opts.AnalysisList.clear();
-#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) \
- if (Args.hasArg(OPT_analysis_##NAME)) Opts.AnalysisList.push_back(NAME);
-#include "clang/Frontend/Analyses.def"
-
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
llvm::StringRef Name = A->getValue(Args);
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
@@ -868,20 +878,17 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
Opts.AnalyzeNestedBlocks =
Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
- Opts.AnalyzerStats = Args.hasArg(OPT_analysis_AnalyzerStats);
Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
Opts.EagerlyAssume = 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.CFGAddInitializers = Args.hasArg(OPT_analysis_CFGAddInitializers);
- Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks);
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.InlineCall = Args.hasArg(OPT_analyzer_inline_call);
- Opts.BufferOverflows = Args.hasArg(OPT_analysis_WarnBufferOverflows);
Opts.CheckersControlList.clear();
for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker,
@@ -919,12 +926,14 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.LimitDebugInfo = Args.hasArg(OPT_flimit_debug_info);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
+ Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
Opts.OptimizeSize = Args.hasArg(OPT_Os);
+ Opts.OptimizeSize = Args.hasArg(OPT_Oz) ? 2 : Opts.OptimizeSize;
Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) ||
Args.hasArg(OPT_ffreestanding));
Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) ||
@@ -943,9 +952,12 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NoInfsFPMath = Opts.NoNaNsFPMath = Args.hasArg(OPT_cl_finite_math_only)||
Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
+ Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option);
Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
+ Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
+ Opts.NoDwarf2CFIAsm = Args.hasArg(OPT_fno_dwarf2_cfi_asm);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnsafeFPMath = Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
@@ -960,6 +972,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
+ Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
llvm::StringRef Name = A->getValue(Args);
@@ -989,6 +1003,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Diagnostic &Diags) {
using namespace cc1options;
+ Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file);
Opts.IgnoreWarnings = Args.hasArg(OPT_w);
Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros);
Opts.Pedantic = Args.hasArg(OPT_pedantic);
@@ -998,8 +1013,16 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column);
Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info);
Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
+ Opts.ShowNames = Args.hasArg(OPT_fdiagnostics_show_name);
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
+ // Default behavior is to not to show note include stacks.
+ Opts.ShowNoteIncludeStack = false;
+ if (Arg *A = Args.getLastArg(OPT_fdiagnostics_show_note_include_stack,
+ OPT_fno_diagnostics_show_note_include_stack))
+ if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack))
+ Opts.ShowNoteIncludeStack = true;
+
llvm::StringRef ShowOverloads =
Args.getLastArgValue(OPT_fshow_overloads_EQ, "all");
if (ShowOverloads == "best")
@@ -1065,8 +1088,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::ASTDumpXML; break;
case OPT_ast_print:
Opts.ProgramAction = frontend::ASTPrint; break;
- case OPT_ast_print_xml:
- Opts.ProgramAction = frontend::ASTPrintXML; break;
case OPT_ast_view:
Opts.ProgramAction = frontend::ASTView; break;
case OPT_boostcon:
@@ -1177,8 +1198,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))
.Case("c", IK_C)
.Case("cl", IK_OpenCL)
- .Case("c", IK_C)
- .Case("cl", IK_OpenCL)
.Case("cuda", IK_CUDA)
.Case("c++", IK_CXX)
.Case("objective-c", IK_ObjC)
@@ -1187,6 +1206,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Case("assembler-with-cpp", IK_Asm)
.Case("c++-cpp-output", IK_PreprocessedCXX)
.Case("objective-c-cpp-output", IK_PreprocessedObjC)
+ .Case("objc-cpp-output", IK_PreprocessedObjC)
.Case("objective-c++-cpp-output", IK_PreprocessedObjCXX)
.Case("c-header", IK_C)
.Case("objective-c-header", IK_ObjC)
@@ -1286,7 +1306,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
LangStandard::Kind LangStd) {
- // Set some properties which depend soley on the input kind; it would be nice
+ // Set some properties which depend solely on the input kind; it would be nice
// to move these to the language standard, and have the driver resolve the
// input kind + language standard.
if (IK == IK_Asm) {
@@ -1330,6 +1350,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
Opts.BCPLComment = Std.hasBCPLComments();
Opts.C99 = Std.isC99();
+ Opts.C1X = Std.isC1X();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus0x = Std.isCPlusPlus0x();
Opts.Digraphs = Std.hasDigraphs();
@@ -1421,6 +1442,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_pthread))
Opts.POSIXThreads = 1;
+ if (Args.hasArg(OPT_fdelayed_template_parsing))
+ Opts.DelayedTemplateParsing = 1;
+
llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
if (Vis == "default")
Opts.setVisibilityMode(DefaultVisibility);
@@ -1455,7 +1479,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
- Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings);
+ Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings,
+ Opts.ConstStrings);
if (Args.hasArg(OPT_fno_lax_vector_conversions))
Opts.LaxVectorConversions = 0;
if (Args.hasArg(OPT_fno_threadsafe_statics))
@@ -1464,6 +1489,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions);
Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions);
Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
+ Opts.TraditionalCPP = Args.hasArg(OPT_traditional_cpp);
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
@@ -1479,6 +1505,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024,
Diags);
+ Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy,
0, Diags);
Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields);
@@ -1501,6 +1528,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant);
Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.OptimizeSize = 0;
+ Opts.MRTD = Args.hasArg(OPT_mrtd);
+ Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map);
+ Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype);
+
+ // Record whether the __DEPRECATED define was requested.
+ Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro,
+ OPT_fno_deprecated_macro,
+ Opts.Deprecated);
// FIXME: Eliminate this dependency.
unsigned Opt = getOptimizationLevel(Args, IK, Diags);
@@ -1590,6 +1625,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.Includes.push_back(A->getValue(Args));
}
+ 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));
+ }
+
// Include 'altivec.h' if -faltivec option present
if (Args.hasArg(OPT_faltivec))
Opts.Includes.push_back("altivec.h");
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
new file mode 100644
index 000000000000..0005f910d214
--- /dev/null
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -0,0 +1,90 @@
+//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Construct a compiler invocation object for command line driver arguments
+//
+//===----------------------------------------------------------------------===//
+
+#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"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/Tool.h"
+#include "llvm/Support/Host.h"
+using namespace clang;
+
+/// createInvocationFromCommandLine - Construct a compiler invocation object for
+/// a command line argument vector.
+///
+/// \return A CompilerInvocation, or 0 if none was built for the given
+/// argument vector.
+CompilerInvocation *
+clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags) {
+ 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(),
+ ArgList.begin());
+ }
+
+ llvm::SmallVector<const char *, 16> Args;
+ Args.push_back("<clang>"); // FIXME: Remove dummy argument.
+ Args.insert(Args.end(), ArgList.begin(), ArgList.end());
+
+ // FIXME: Find a cleaner way to force the driver into restricted modes. We
+ // also want to force it to use clang.
+ Args.push_back("-fsyntax-only");
+
+ // FIXME: We shouldn't have to pass in the path info.
+ driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
+ "a.out", false, false, *Diags);
+
+ // Don't check that inputs exist, they may have been remapped.
+ TheDriver.setCheckInputsExist(false);
+
+ llvm::OwningPtr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
+
+ // Just print the cc1 options if -### was present.
+ if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
+ C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
+ return 0;
+ }
+
+ // We expect to get back exactly one command job, if we didn't something
+ // failed.
+ const driver::JobList &Jobs = C->getJobs();
+ if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+ llvm::SmallString<256> Msg;
+ llvm::raw_svector_ostream OS(Msg);
+ C->PrintJob(OS, C->getJobs(), "; ", true);
+ Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
+ return 0;
+ }
+
+ const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
+ if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+ Diags->Report(diag::err_fe_expected_clang_command);
+ return 0;
+ }
+
+ const driver::ArgStringList &CCArgs = Cmd->getArguments();
+ CompilerInvocation *CI = new CompilerInvocation();
+ CompilerInvocation::CreateFromArgs(*CI,
+ const_cast<const char **>(CCArgs.data()),
+ const_cast<const char **>(CCArgs.data()) +
+ CCArgs.size(),
+ *Diags);
+ return CI;
+}
diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp
deleted file mode 100644
index 8d3d225a4b38..000000000000
--- a/lib/Frontend/DeclXML.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-//===--- DeclXML.cpp - XML implementation for Decl ASTs -------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the XML document class, which provides the means to
-// dump out the AST in a XML form that exposes type details and other fields.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/DocumentXML.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/Expr.h"
-
-namespace clang {
-
-//---------------------------------------------------------
-class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> {
- DocumentXML& Doc;
-
- void addSubNodes(FunctionDecl* FD) {
- for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
- Visit(FD->getParamDecl(i));
- Doc.toParent();
- }
- }
-
- void addFunctionBody(FunctionDecl* FD) {
- if (FD->isThisDeclarationADefinition()) {
- Doc.addSubNode("Body");
- Doc.PrintStmt(FD->getBody());
- Doc.toParent();
- }
- }
-
- void addSubNodes(RecordDecl* RD) {
- for (RecordDecl::decl_iterator i = RD->decls_begin(),
- e = RD->decls_end(); i != e; ++i) {
- if (!(*i)->isImplicit()) {
- Visit(*i);
- Doc.toParent();
- }
- }
- }
-
- void addSubNodes(CXXRecordDecl* RD) {
- addSubNodes(cast<RecordDecl>(RD));
-
- if (RD->isDefinition()) {
- // FIXME: This breaks XML generation
- //Doc.addAttribute("num_bases", RD->getNumBases());
-
- for (CXXRecordDecl::base_class_iterator
- base = RD->bases_begin(),
- bend = RD->bases_end();
- base != bend;
- ++base) {
- Doc.addSubNode("Base");
- Doc.addAttribute("id", base->getType());
- AccessSpecifier as = base->getAccessSpecifierAsWritten();
- const char* as_name = "";
- switch(as) {
- case AS_none: as_name = ""; break;
- case AS_public: as_name = "public"; break;
- case AS_protected: as_name = "protected"; break;
- case AS_private: as_name = "private"; break;
- }
- Doc.addAttributeOptional("access", as_name);
- Doc.addAttribute("is_virtual", base->isVirtual());
- Doc.toParent();
- }
- }
- }
-
- void addSubNodes(EnumDecl* ED) {
- for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(),
- e = ED->enumerator_end(); i != e; ++i) {
- Visit(*i);
- Doc.toParent();
- }
- }
-
- void addSubNodes(EnumConstantDecl* ECD) {
- if (ECD->getInitExpr())
- Doc.PrintStmt(ECD->getInitExpr());
- }
-
- void addSubNodes(FieldDecl* FdD) {
- if (FdD->isBitField())
- Doc.PrintStmt(FdD->getBitWidth());
- }
-
- void addSubNodes(VarDecl* V) {
- if (V->getInit())
- Doc.PrintStmt(V->getInit());
- }
-
- void addSubNodes(ParmVarDecl* argDecl) {
- if (argDecl->getDefaultArg())
- Doc.PrintStmt(argDecl->getDefaultArg());
- }
-
- void addSubNodes(DeclContext* ns) {
-
- for (DeclContext::decl_iterator
- d = ns->decls_begin(),
- dend = ns->decls_end();
- d != dend;
- ++d) {
- Visit(*d);
- Doc.toParent();
- }
- }
-
- void addSpecialAttribute(const char* pName, EnumDecl* ED) {
- const QualType& enumType = ED->getIntegerType();
- if (!enumType.isNull())
- Doc.addAttribute(pName, enumType);
- }
-
- void addIdAttribute(LinkageSpecDecl* ED) {
- Doc.addAttribute("id", ED);
- }
-
- void addIdAttribute(NamedDecl* ND) {
- Doc.addAttribute("id", ND);
- }
-
-public:
- DeclPrinter(DocumentXML& doc) : Doc(doc) {}
-
-#define NODE_XML( CLASS, NAME ) \
- void Visit##CLASS(CLASS* T) \
- { \
- Doc.addSubNode(NAME);
-
-#define ID_ATTRIBUTE_XML addIdAttribute(T);
-#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
-#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
-#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocation(T->getLocation());
-#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, T);
-
-#define ATTRIBUTE_ENUM_XML( FN, NAME ) \
- { \
- const char* pAttributeName = NAME; \
- const bool optional = false; \
- switch (T->FN) { \
- default: assert(0 && "unknown enum value");
-
-#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
- { \
- const char* pAttributeName = NAME; \
- const bool optional = true; \
- switch (T->FN) { \
- default: assert(0 && "unknown enum value");
-
-#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
-#define END_ENUM_XML } }
-#define END_NODE_XML }
-
-#define SUB_NODE_XML( CLASS ) addSubNodes(T);
-#define SUB_NODE_SEQUENCE_XML( CLASS ) addSubNodes(T);
-#define SUB_NODE_OPT_XML( CLASS ) addSubNodes(T);
-
-#define SUB_NODE_FN_BODY_XML addFunctionBody(T);
-
-#include "clang/Frontend/DeclXML.def"
-};
-
-
-//---------------------------------------------------------
-void DocumentXML::writeDeclToXML(Decl *D) {
- DeclPrinter(*this).Visit(D);
- toParent();
-}
-
-//---------------------------------------------------------
-} // NS clang
-
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index bc5a55df0860..5c3a23128a14 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -171,7 +171,7 @@ void DependencyFileCallback::OutputDependencyFile() {
*OS << '\n';
// Create phony targets if requested.
- if (PhonyTarget) {
+ if (PhonyTarget && !Files.empty()) {
// Skip the first entry, this is always the input file itself.
for (std::vector<std::string>::iterator I = Files.begin() + 1,
E = Files.end(); I != E; ++I) {
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
deleted file mode 100644
index a09db0be473e..000000000000
--- a/lib/Frontend/DocumentXML.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the XML document class, which provides the means to
-// dump out the AST in a XML form that exposes type details and other fields.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/DocumentXML.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/config.h"
-#include <cstdio>
-
-namespace clang {
-
-//---------------------------------------------------------
-DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
- Out(out),
- Ctx(0),
- HasCurrentNodeSubNodes(false) {
- NodeStack.push(rootName);
- Out << "<?xml version=\"1.0\"?>\n<" << rootName;
-}
-
-//---------------------------------------------------------
-DocumentXML& DocumentXML::addSubNode(const std::string& name) {
- if (!HasCurrentNodeSubNodes)
- Out << ">\n";
- NodeStack.push(name);
- HasCurrentNodeSubNodes = false;
- Indent();
- Out << "<" << NodeStack.top();
- return *this;
-}
-
-//---------------------------------------------------------
-void DocumentXML::Indent() {
- for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
- Out << ' ';
-}
-
-//---------------------------------------------------------
-DocumentXML& DocumentXML::toParent() {
- assert(NodeStack.size() > 1 && "too much backtracking");
-
- if (HasCurrentNodeSubNodes) {
- Indent();
- Out << "</" << NodeStack.top() << ">\n";
- } else
- Out << "/>\n";
- NodeStack.pop();
- HasCurrentNodeSubNodes = true;
- return *this;
-}
-
-//---------------------------------------------------------
-namespace {
-
-enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
-
-unsigned getNewId(tIdType idType) {
- static unsigned int idCounts[ID_LAST] = { 0 };
- return ++idCounts[idType];
-}
-
-//---------------------------------------------------------
-inline std::string getPrefixedId(unsigned uId, tIdType idType) {
- static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
- char buffer[20];
- char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
- *--BufPtr = idPrefix[idType];
- return BufPtr;
-}
-
-//---------------------------------------------------------
-template<class T, class V>
-bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) {
- typename T::iterator i = idMap.find(value);
- bool toAdd = i == idMap.end();
- if (toAdd)
- idMap.insert(typename T::value_type(value, getNewId(idType)));
- return toAdd;
-}
-
-} // anon NS
-
-
-//---------------------------------------------------------
-std::string DocumentXML::escapeString(const char* pStr,
- std::string::size_type len) {
- std::string value;
- value.reserve(len + 1);
- char buffer[16];
- for (unsigned i = 0; i < len; ++i) {
- switch (char C = pStr[i]) {
- default:
- if (isprint(C))
- value += C;
- else {
-#ifdef LLVM_ON_WIN32
- sprintf(buffer, "\\%03o", C);
-#else
- snprintf(buffer, sizeof(buffer), "\\%03o", C);
-#endif
- value += buffer;
- }
- break;
-
- case '\n': value += "\\n"; break;
- case '\t': value += "\\t"; break;
- case '\a': value += "\\a"; break;
- case '\b': value += "\\b"; break;
- case '\r': value += "\\r"; break;
-
- case '&': value += "&amp;"; break;
- case '<': value += "&lt;"; break;
- case '>': value += "&gt;"; break;
- case '"': value += "&quot;"; break;
- case '\'': value += "&apos;"; break;
-
- }
- }
- return value;
-}
-
-//---------------------------------------------------------
-void DocumentXML::finalize() {
- assert(NodeStack.size() == 1 && "not completely backtracked");
-
- addSubNode("ReferenceSection");
- addSubNode("Types");
-
- for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
- i != e; ++i) {
- if (i->first.hasLocalQualifiers()) {
- writeTypeToXML(i->first);
- addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
- toParent();
- }
- }
-
- for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
- e = BasicTypes.end(); i != e; ++i) {
- writeTypeToXML(i->first);
- addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
- toParent();
- }
-
-
- toParent().addSubNode("Contexts");
-
- for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(),
- e = Contexts.end(); i != e; ++i) {
- addSubNode(i->first->getDeclKindName());
- addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
- addAttribute("name", ND->getNameAsString());
- if (const TagDecl *TD = dyn_cast<TagDecl>(i->first))
- addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
- else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
- addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
-
- if (const DeclContext* parent = i->first->getParent())
- addAttribute("context", parent);
- toParent();
- }
-
- toParent().addSubNode("Files");
-
- for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(),
- e = SourceFiles.end(); i != e; ++i) {
- addSubNode("File");
- addAttribute("id", getPrefixedId(i->second, ID_FILE));
- addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
- toParent();
- }
-
- toParent().toParent();
-
- // write the root closing node (which has always subnodes)
- Out << "</" << NodeStack.top() << ">\n";
-}
-
-//---------------------------------------------------------
-void DocumentXML::addAttribute(const char* pAttributeName,
- const QualType& pType) {
- addTypeRecursively(pType);
- addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
-}
-
-//---------------------------------------------------------
-void DocumentXML::addPtrAttribute(const char* pAttributeName,
- const Type* pType) {
- addTypeRecursively(pType);
- addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
-}
-
-//---------------------------------------------------------
-void DocumentXML::addPtrAttribute(const char* pAttributeName,
- const NestedNameSpecifier* pNNS) {
- switch (pNNS->getKind()) {
- case NestedNameSpecifier::Identifier: {
- IdentifierInfo *ii = pNNS->getAsIdentifier();
- // FIXME how should we handle those ?
- addPtrAttribute(pAttributeName, ii->getName().data());
- break;
- }
- case NestedNameSpecifier::Namespace: {
- addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
- break;
- }
- case NestedNameSpecifier::NamespaceAlias: {
- addPtrAttribute(pAttributeName, pNNS->getAsNamespaceAlias());
- break;
- }
- case NestedNameSpecifier::TypeSpec: {
- addPtrAttribute(pAttributeName, pNNS->getAsType());
- break;
- }
- case NestedNameSpecifier::TypeSpecWithTemplate: {
- addPtrAttribute(pAttributeName, pNNS->getAsType());
- break;
- }
- case NestedNameSpecifier::Global: {
- addPtrAttribute(pAttributeName, "::");
- break;
- }
- }
-}
-
-//---------------------------------------------------------
-void DocumentXML::addTypeRecursively(const QualType& pType)
-{
- if (addToMap(Types, pType))
- {
- addTypeRecursively(pType.getTypePtr());
- // beautifier: a non-qualified type shall be transparent
- if (!pType.hasLocalQualifiers())
- {
- Types[pType] = BasicTypes[pType.getTypePtr()];
- }
- }
-}
-
-//---------------------------------------------------------
-void DocumentXML::addTypeRecursively(const Type* pType)
-{
- if (addToMap(BasicTypes, pType))
- {
- addParentTypes(pType);
-/*
- // FIXME: doesn't work in the immediate streaming approach
- if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
- {
- addSubNode("VariableArraySizeExpression");
- PrintStmt(VAT->getSizeExpr());
- toParent();
- }
-*/
- }
-}
-
-//---------------------------------------------------------
-void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
-{
- addContextsRecursively(DC);
- addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
-}
-
-//---------------------------------------------------------
-void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
-{
- if (const DeclContext* DC = dyn_cast<DeclContext>(D))
- {
- addContextsRecursively(DC);
- addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
- }
- else
- {
- addToMap(Decls, D);
- addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
- }
-}
-
-//---------------------------------------------------------
-void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
-{
- addPtrAttribute(pName, static_cast<const DeclContext*>(D));
-}
-
-//---------------------------------------------------------
-void DocumentXML::addContextsRecursively(const DeclContext *DC)
-{
- if (DC != 0 && addToMap(Contexts, DC))
- {
- addContextsRecursively(DC->getParent());
- }
-}
-
-//---------------------------------------------------------
-void DocumentXML::addSourceFileAttribute(const std::string& fileName)
-{
- addToMap(SourceFiles, fileName, ID_FILE);
- addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
-}
-
-
-//---------------------------------------------------------
-void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
-{
- addToMap(Labels, L, ID_LABEL);
- addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
-}
-
-
-//---------------------------------------------------------
-PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
-{
- SourceManager& SM = Ctx->getSourceManager();
- SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
- PresumedLoc PLoc;
- if (!SpellingLoc.isInvalid())
- {
- PLoc = SM.getPresumedLoc(SpellingLoc);
- if (PLoc.isValid()) {
- addSourceFileAttribute(PLoc.getFilename());
- addAttribute("line", PLoc.getLine());
- addAttribute("col", PLoc.getColumn());
- }
- }
- // else there is no error in some cases (eg. CXXThisExpr)
- return PLoc;
-}
-
-//---------------------------------------------------------
-void DocumentXML::addLocationRange(const SourceRange& R)
-{
- PresumedLoc PStartLoc = addLocation(R.getBegin());
- if (R.getBegin() != R.getEnd())
- {
- SourceManager& SM = Ctx->getSourceManager();
- SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
- if (!SpellingLoc.isInvalid())
- {
- PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
- if (PLoc.isInvalid()) {
- } else if (PStartLoc.isInvalid() ||
- strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
- addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
- addAttribute("endfile", PLoc.getFilename());
- addAttribute("endline", PLoc.getLine());
- addAttribute("endcol", PLoc.getColumn());
- } else if (PLoc.getLine() != PStartLoc.getLine()) {
- addAttribute("endline", PLoc.getLine());
- addAttribute("endcol", PLoc.getColumn());
- } else {
- addAttribute("endcol", PLoc.getColumn());
- }
- }
- }
-}
-
-//---------------------------------------------------------
-void DocumentXML::PrintDecl(Decl *D)
-{
- writeDeclToXML(D);
-}
-
-//---------------------------------------------------------
-} // NS clang
-
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index e3d8b8594190..42da44c2c720 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -20,6 +20,7 @@
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/ChainedIncludesSource.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/ErrorHandling.h"
@@ -209,8 +210,16 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
- /// Use PCH?
- if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
+ // Convert headers to PCH and chain them.
+ llvm::OwningPtr<ExternalASTSource> source;
+ source.reset(ChainedIncludesSource::create(CI));
+ if (!source)
+ goto failure;
+ CI.getASTContext().setExternalSource(source);
+
+ } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ // Use PCH.
assert(hasPCHSupport() && "This action does not have PCH support!");
ASTDeserializationListener *DeserialListener
= CI.getInvocation().getFrontendOpts().ChainedPCH ?
@@ -249,10 +258,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// matching EndSourceFile().
failure:
if (isCurrentFileAST()) {
- CI.takeASTContext();
- CI.takePreprocessor();
- CI.takeSourceManager();
- CI.takeFileManager();
+ CI.setASTContext(0);
+ CI.setPreprocessor(0);
+ CI.setSourceManager(0);
+ CI.setFileManager(0);
}
CI.getDiagnosticClient().EndSourceFile();
@@ -304,7 +313,7 @@ void FrontendAction::EndSourceFile() {
CI.takeASTConsumer();
if (!isCurrentFileAST()) {
CI.takeSema();
- CI.takeASTContext();
+ CI.resetAndLeakASTContext();
}
} else {
if (!isCurrentFileAST()) {
@@ -333,10 +342,10 @@ void FrontendAction::EndSourceFile() {
if (isCurrentFileAST()) {
CI.takeSema();
- CI.takeASTContext();
- CI.takePreprocessor();
- CI.takeSourceManager();
- CI.takeFileManager();
+ CI.resetAndLeakASTContext();
+ CI.resetAndLeakPreprocessor();
+ CI.resetAndLeakSourceManager();
+ CI.resetAndLeakFileManager();
}
setCompilerInstance(0);
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index d8e7d2904500..7b06c7e49acf 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -47,13 +47,6 @@ ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
return 0;
}
-ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml"))
- return CreateASTPrinterXML(OS);
- return 0;
-}
-
ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
return CreateASTDumper();
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index 45ff1d2e412f..51dec967cd6b 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -22,13 +22,16 @@ class HeaderIncludesCallback : public PPCallbacks {
bool HasProcessedPredefines;
bool OwnsOutputFile;
bool ShowAllHeaders;
+ bool ShowDepth;
public:
HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
- llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_)
+ llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_,
+ bool ShowDepth_)
: SM(PP->getSourceManager()), OutputFile(OutputFile_),
CurrentIncludeDepth(0), HasProcessedPredefines(false),
- OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_) {}
+ OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
+ ShowDepth(ShowDepth_) {}
~HeaderIncludesCallback() {
if (OwnsOutputFile)
@@ -41,7 +44,7 @@ public:
}
void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
- llvm::StringRef OutputPath) {
+ llvm::StringRef OutputPath, bool ShowDepth) {
llvm::raw_ostream *OutputFile = &llvm::errs();
bool OwnsOutputFile = false;
@@ -63,7 +66,8 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
}
PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders,
- OutputFile, OwnsOutputFile));
+ OutputFile, OwnsOutputFile,
+ ShowDepth));
}
void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
@@ -78,15 +82,18 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
// Adjust the current include depth.
if (Reason == PPCallbacks::EnterFile) {
++CurrentIncludeDepth;
- } else {
+ } else if (Reason == PPCallbacks::ExitFile) {
if (CurrentIncludeDepth)
--CurrentIncludeDepth;
// We track when we are done with the predefines by watching for the first
- // place where we drop back to a nesting depth of 0.
- if (CurrentIncludeDepth == 0 && !HasProcessedPredefines)
+ // place where we drop back to a nesting depth of 1.
+ if (CurrentIncludeDepth == 1 && !HasProcessedPredefines)
HasProcessedPredefines = true;
- }
+
+ return;
+ } else
+ return;
// Show the header if we are (a) past the predefines, or (b) showing all
// headers and in the predefines at a depth past the initial file and command
@@ -102,9 +109,12 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
Lexer::Stringify(Filename);
llvm::SmallString<256> Msg;
- for (unsigned i = 0; i != CurrentIncludeDepth; ++i)
- Msg += '.';
- Msg += ' ';
+ if (ShowDepth) {
+ // The main source file is at depth 1, so skip one dot.
+ for (unsigned i = 1; i != CurrentIncludeDepth; ++i)
+ Msg += '.';
+ Msg += ' ';
+ }
Msg += Filename;
Msg += '\n';
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 2e3162c0a32e..c552512dc957 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -76,6 +76,10 @@ public:
llvm::StringRef Arch,
llvm::StringRef Version);
+ /// AddMinGW64CXXPaths - Add the necessary paths to support
+ /// libstdc++ of x86_64-w64-mingw32 aka mingw-w64.
+ void AddMinGW64CXXPaths(llvm::StringRef Base);
+
/// AddDelimitedPaths - Add a list of paths delimited by the system PATH
/// separator. The processing follows that of the CPATH variable for gcc.
void AddDelimitedPaths(llvm::StringRef String);
@@ -113,8 +117,13 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
llvm::StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
// Handle isysroot.
- if (Group == System && !IgnoreSysRoot &&
+ if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot &&
+#if defined(_WIN32)
+ !MappedPathStr.empty() &&
+ llvm::sys::path::is_separator(MappedPathStr[0]) &&
+#else
llvm::sys::path::is_absolute(MappedPathStr) &&
+#endif
IsNotEmptyOrRoot) {
MappedPathStorage.clear();
MappedPathStr =
@@ -207,6 +216,15 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
CXXSystem, true, false, false);
}
+void InitHeaderSearch::AddMinGW64CXXPaths(llvm::StringRef Base) {
+ AddPath(Base,
+ CXXSystem, true, false, false);
+ AddPath(Base + "/x86_64-w64-mingw32",
+ CXXSystem, true, false, false);
+ AddPath(Base + "/backward",
+ CXXSystem, true, false, false);
+}
+
// FIXME: This probably should goto to some platform utils place.
#ifdef _MSC_VER
@@ -428,6 +446,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
llvm::Triple::OSType os = triple.getOS();
switch (os) {
+ case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
break;
default:
@@ -533,6 +552,11 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/usr/include/w32api", System, true, false, false);
break;
case llvm::Triple::MinGW32:
+ // FIXME: We should be aware of i686-w64-mingw32.
+ if (triple.getArch() == llvm::Triple::x86_64)
+ AddPath("c:/mingw/x86_64-w64-mingw32/include",
+ System, true, false, false);
+ AddPath("/mingw/include", System, true, false, false);
AddPath("c:/mingw/include", System, true, false, false);
break;
default:
@@ -559,36 +583,8 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
return;
}
// FIXME: temporary hack: hard-coded paths.
- switch (os) {
- case llvm::Triple::Cygwin:
- // Cygwin-1.7
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
- // g++-4 / Cygwin-1.5
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
- // FIXME: Do we support g++-3.4.4?
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4");
- break;
- case llvm::Triple::MinGW32:
- // mingw-w64-20110207
- AddPath("c:/MinGW/include/c++/4.5.3", CXXSystem, true, false, false);
- AddPath("c:/MinGW/include/c++/4.5.3/x86_64-w64-mingw32", CXXSystem, true,
- false, false);
- AddPath("c:/MinGW/include/c++/4.5.3/backward", CXXSystem, true, false,
- false);
- // mingw-w64-20101129
- AddPath("c:/MinGW/include/c++/4.5.2", CXXSystem, true, false, false);
- AddPath("c:/MinGW/include/c++/4.5.2/x86_64-w64-mingw32", CXXSystem, true,
- false, false);
- AddPath("c:/MinGW/include/c++/4.5.2/backward", CXXSystem, true, false,
- false);
- // Try gcc 4.5.0
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
- // Try gcc 4.4.0
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
- // Try gcc 4.3.0
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
- break;
- case llvm::Triple::Darwin:
+
+ if (triple.isOSDarwin()) {
switch (triple.getArch()) {
default: break;
@@ -618,6 +614,34 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"arm-apple-darwin10", "v6", "", triple);
break;
}
+ return;
+ }
+
+ switch (os) {
+ case llvm::Triple::Cygwin:
+ // Cygwin-1.7
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
+ // g++-4 / Cygwin-1.5
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
+ // FIXME: Do we support g++-3.4.4?
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4");
+ break;
+ case llvm::Triple::MinGW32:
+ // FIXME: We should be aware of i686-w64-mingw32.
+ if (triple.getArch() == llvm::Triple::x86_64) {
+ // mingw-w64-20110207
+ AddMinGW64CXXPaths("c:/mingw/x86_64-w64-mingw32/include/c++/4.5.3");
+ // mingw-w64-20101129
+ AddMinGW64CXXPaths("c:/mingw/x86_64-w64-mingw32/include/c++/4.5.2");
+ }
+ // Try gcc 4.5.2 (MSYS)
+ AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2");
+ // Try gcc 4.5.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
+ // Try gcc 4.4.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
+ // Try gcc 4.3.0
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
break;
case llvm::Triple::DragonFly:
AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false);
@@ -665,6 +689,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
//===------------------------------------------------------------------===//
// Redhat based distros.
//===------------------------------------------------------------------===//
+ // Fedora 15
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
+ "i686-redhat-linux", "", "", triple);
// Fedora 14
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1",
"x86_64-redhat-linux", "32", "", triple);
@@ -737,7 +766,26 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"i686-pc-linux-gnu", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
"x86_64-unknown-linux-gnu", "", "", triple);
- // Gentoo x86 2010.0 stable
+
+ // Arch Linux gcc 4.6
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
+ "i686-pc-linux-gnu", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0",
+ "x86_64-unknown-linux-gnu", "", "", triple);
+
+ // Gentoo x86 gcc 4.5.2
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.5.2/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Gentoo x86 gcc 4.4.5
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.4.5/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Gentoo x86 gcc 4.4.4
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/i686-pc-linux-gnu/4.4.4/include/g++-v4",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Gentoo x86 2010.0 stable
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/include/g++-v4",
"i686-pc-linux-gnu", "", "", triple);
@@ -753,7 +801,15 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
"i686-pc-linux-gnu", "", "", triple);
+ // Gentoo x86 llvm-gcc trunk
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/llvm-gcc-4.2-9999/include/c++/4.2.1",
+ "i686-pc-linux-gnu", "", "", triple);
+ // Gentoo amd64 gcc 4.5.2
+ AddGnuCPlusPlusIncludePaths(
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.2/include/g++-v4",
+ "x86_64-pc-linux-gnu", "32", "", triple);
// Gentoo amd64 gcc 4.4.5
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4",
@@ -773,7 +829,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
// Gentoo amd64 stable
AddGnuCPlusPlusIncludePaths(
"/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
- "i686-pc-linux-gnu", "", "", triple);
+ "x86_64-pc-linux-gnu", "", "", triple);
// Gentoo amd64 llvm-gcc trunk
AddGnuCPlusPlusIncludePaths(
@@ -822,7 +878,7 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
AddDefaultCIncludePaths(triple, HSOpts);
// Add the default framework include paths on Darwin.
- if (triple.getOS() == llvm::Triple::Darwin) {
+ if (triple.isOSDarwin()) {
AddPath("/System/Library/Frameworks", System, true, false, true);
AddPath("/Library/Frameworks", System, true, false, true);
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 91b5280a87ef..abe251d67df2 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -247,13 +247,18 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
Builder.defineMacro("__GNUC__", "4");
Builder.defineMacro("__GXX_ABI_VERSION", "1002");
- Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible Clang Compiler\"");
+
+ // As sad as it is, enough software depends on the __VERSION__ for version
+ // checks that it is necessary to report 4.2.1 (the base GCC version we claim
+ // compatibility with) first.
+ Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " +
+ llvm::Twine(getClangFullCPPVersion()) + "\"");
// Initialize language-specific preprocessor defines.
// These should all be defined in the preprocessor according to the
// current language configuration.
- if (!LangOpts.Microsoft)
+ if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP)
Builder.defineMacro("__STDC__");
if (LangOpts.AsmPreprocessor)
Builder.defineMacro("__ASSEMBLER__");
@@ -313,8 +318,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.SjLjExceptions)
Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
- if (LangOpts.CPlusPlus) {
+ if (LangOpts.Deprecated)
Builder.defineMacro("__DEPRECATED");
+
+ if (LangOpts.CPlusPlus) {
Builder.defineMacro("__GNUG__", "4");
Builder.defineMacro("__GXX_WEAK__");
if (LangOpts.GNUMode)
@@ -328,12 +335,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
}
if (LangOpts.Microsoft) {
- // Filter out some microsoft extensions when trying to parse in ms-compat
- // mode.
- Builder.defineMacro("__int8", "__INT8_TYPE__");
- Builder.defineMacro("__int16", "__INT16_TYPE__");
- Builder.defineMacro("__int32", "__INT32_TYPE__");
- Builder.defineMacro("__int64", "__INT64_TYPE__");
// Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
// VC++ appears to only like __FUNCTION__.
Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
@@ -414,6 +415,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (!LangOpts.CharIsSigned)
Builder.defineMacro("__CHAR_UNSIGNED__");
+ if (!TargetInfo::isTypeSigned(TI.getWIntType()))
+ Builder.defineMacro("__WINT_UNSIGNED__");
+
// Define exact-width integer types for stdint.h
Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__",
"char");
@@ -531,20 +535,13 @@ static void InitializeFileRemapping(Diagnostic &Diags,
continue;
}
- // Load the contents of the file we're mapping to.
- std::string ErrorStr;
- const llvm::MemoryBuffer *Buffer
- = FileMgr.getBufferForFile(ToFile->getName(), &ErrorStr);
- if (!Buffer) {
- Diags.Report(diag::err_fe_error_opening)
- << Remap->second << ErrorStr;
- continue;
- }
-
// Override the contents of the "from" file with the contents of
// the "to" file.
- SourceMgr.overrideFileContents(FromFile, Buffer);
+ SourceMgr.overrideFileContents(FromFile, ToFile);
}
+
+ SourceMgr.setOverridenFilesKeepOriginalName(
+ InitOpts.RemappedFilesKeepOriginalName);
}
/// InitializePreprocessor - Initialize the preprocessor getting it and the
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
new file mode 100644
index 000000000000..954bad4e7c54
--- /dev/null
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -0,0 +1,146 @@
+//===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/LogDiagnosticPrinter.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os,
+ const DiagnosticOptions &diags,
+ bool _OwnsOutputStream)
+ : OS(os), LangOpts(0), DiagOpts(&diags),
+ OwnsOutputStream(_OwnsOutputStream) {
+}
+
+LogDiagnosticPrinter::~LogDiagnosticPrinter() {
+ if (OwnsOutputStream)
+ delete &OS;
+}
+
+static llvm::StringRef getLevelName(Diagnostic::Level Level) {
+ switch (Level) {
+ default:
+ return "<unknown>";
+ case Diagnostic::Ignored: return "ignored";
+ case Diagnostic::Note: return "note";
+ case Diagnostic::Warning: return "warning";
+ case Diagnostic::Error: return "error";
+ case Diagnostic::Fatal: return "fatal error";
+ }
+}
+
+void LogDiagnosticPrinter::EndSourceFile() {
+ // We emit all the diagnostics in EndSourceFile. However, we don't emit any
+ // entry if no diagnostics were present.
+ //
+ // Note that DiagnosticClient has no "end-of-compilation" callback, so we will
+ // miss any diagnostics which are emitted after and outside the translation
+ // unit processing.
+ if (Entries.empty())
+ return;
+
+ // Write to a temporary string to ensure atomic write of diagnostic object.
+ llvm::SmallString<512> Msg;
+ llvm::raw_svector_ostream OS(Msg);
+
+ OS << "<dict>\n";
+ if (!MainFilename.empty()) {
+ OS << " <key>main-file</key>\n"
+ << " <string>" << MainFilename << "</string>\n";
+ }
+ if (!DwarfDebugFlags.empty()) {
+ OS << " <key>dwarf-debug-flags</key>\n"
+ << " <string>" << DwarfDebugFlags << "</string>\n";
+ }
+ OS << " <key>diagnostics</key>\n";
+ OS << " <array>\n";
+ for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
+ DiagEntry &DE = Entries[i];
+
+ OS << " <dict>\n";
+ OS << " <key>level</key>\n"
+ << " <string>" << getLevelName(DE.DiagnosticLevel) << "</string>\n";
+ if (!DE.Filename.empty()) {
+ OS << " <key>filename</key>\n"
+ << " <string>" << DE.Filename << "</string>\n";
+ }
+ if (DE.Line != 0) {
+ OS << " <key>line</key>\n"
+ << " <integer>" << DE.Line << "</integer>\n";
+ }
+ if (DE.Column != 0) {
+ OS << " <key>column</key>\n"
+ << " <integer>" << DE.Column << "</integer>\n";
+ }
+ if (!DE.Message.empty()) {
+ OS << " <key>message</key>\n"
+ << " <string>" << DE.Message << "</string>\n";
+ }
+ OS << " </dict>\n";
+ }
+ OS << " </array>\n";
+ OS << "</dict>\n";
+
+ this->OS << OS.str();
+}
+
+void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
+ const DiagnosticInfo &Info) {
+ // Default implementation (Warnings/errors count).
+ DiagnosticClient::HandleDiagnostic(Level, Info);
+
+ // Initialize the main file name, if we haven't already fetched it.
+ if (MainFilename.empty()) {
+ const SourceManager &SM = Info.getSourceManager();
+ FileID FID = SM.getMainFileID();
+ if (!FID.isInvalid()) {
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+ if (FE && FE->getName())
+ MainFilename = FE->getName();
+ }
+ }
+
+ // Create the diag entry.
+ DiagEntry DE;
+ DE.DiagnosticID = Info.getID();
+ DE.DiagnosticLevel = Level;
+
+ // Format the message.
+ llvm::SmallString<100> MessageStr;
+ Info.FormatDiagnostic(MessageStr);
+ DE.Message = MessageStr.str();
+
+ // Set the location information.
+ DE.Filename = "";
+ DE.Line = DE.Column = 0;
+ if (Info.getLocation().isValid()) {
+ const SourceManager &SM = Info.getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
+
+ if (PLoc.isInvalid()) {
+ // At least print the file name if available:
+ FileID FID = SM.getFileID(Info.getLocation());
+ if (!FID.isInvalid()) {
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+ if (FE && FE->getName())
+ DE.Filename = FE->getName();
+ }
+ } else {
+ DE.Filename = PLoc.getFilename();
+ DE.Line = PLoc.getLine();
+ DE.Column = PLoc.getColumn();
+ }
+ }
+
+ // Record the diagnostic entry.
+ Entries.push_back(DE);
+}
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 3649c3c99728..5aa65d7a60aa 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -95,6 +95,10 @@ public:
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
const ClassTemplateSpecializationDecl *D);
+ virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
+ const FunctionDecl *D);
+ virtual void CompletedImplicitDefinition(const FunctionDecl *D);
+ virtual void StaticDataMemberInstantiated(const VarDecl *D);
private:
std::vector<ASTMutationListener*> Listeners;
};
@@ -125,6 +129,21 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
+void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
+ const FunctionTemplateDecl *TD, const FunctionDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
+}
+void MultiplexASTMutationListener::CompletedImplicitDefinition(
+ const FunctionDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->CompletedImplicitDefinition(D);
+}
+void MultiplexASTMutationListener::StaticDataMemberInstantiated(
+ const VarDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->StaticDataMemberInstantiated(D);
+}
} // end namespace clang
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 922d743adf4e..b46e04749ba3 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -432,7 +432,7 @@ struct UnknownPragmaHandler : public PragmaHandler {
Callbacks->OS.write(Prefix, strlen(Prefix));
Callbacks->SetEmittedTokensOnThisLine();
// Read and print all of the pragma tokens.
- while (PragmaTok.isNot(tok::eom)) {
+ while (PragmaTok.isNot(tok::eod)) {
if (PragmaTok.hasLeadingSpace())
Callbacks->OS << ' ';
std::string TokSpell = PP.getSpelling(PragmaTok);
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
deleted file mode 100644
index c113cc18dc1c..000000000000
--- a/lib/Frontend/StmtXML.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-//===--- StmtXML.cpp - XML implementation for Stmt ASTs ------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Stmt::dumpXML methods, which dump out the
-// AST to an XML document.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/DocumentXML.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/Basic/SourceManager.h"
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// StmtXML Visitor
-//===----------------------------------------------------------------------===//
-
-namespace {
- class StmtXML : public StmtVisitor<StmtXML> {
- DocumentXML& Doc;
-
- //static const char *getOpcodeStr(UnaryOperator::Opcode Op);
- //static const char *getOpcodeStr(BinaryOperator::Opcode Op);
-
-
- void addSpecialAttribute(const char* pName, StringLiteral* Str) {
- Doc.addAttribute(pName, Doc.escapeString(Str->getString().data(),
- Str->getString().size()));
- }
-
- void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) {
- if (S->isArgumentType())
- Doc.addAttribute(pName, S->getArgumentType());
- }
-
- void addSpecialAttribute(const char* pName, CXXTypeidExpr* S) {
- if (S->isTypeOperand())
- Doc.addAttribute(pName, S->getTypeOperand());
- }
-
-
- public:
- StmtXML(DocumentXML& doc)
- : Doc(doc) {
- }
-
- void DumpSubTree(Stmt *S) {
- if (S) {
- Visit(S);
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
- for (DeclStmt::decl_iterator DI = DS->decl_begin(),
- DE = DS->decl_end(); DI != DE; ++DI) {
- Doc.PrintDecl(*DI);
- }
- } else {
- for (Stmt::child_range i = S->children(); i; ++i)
- DumpSubTree(*i);
- }
- Doc.toParent();
- } else {
- Doc.addSubNode("NULL").toParent();
- }
- }
-
-
-#define NODE_XML( CLASS, NAME ) \
- void Visit##CLASS(CLASS* S) \
- { \
- typedef CLASS tStmtType; \
- Doc.addSubNode(NAME);
-
-#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN);
-#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
-#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN);
-#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S);
-#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocationRange(S->getSourceRange());
-
-
-#define ATTRIBUTE_ENUM_XML( FN, NAME ) \
- { \
- const char* pAttributeName = NAME; \
- const bool optional = false; \
- switch (S->FN) { \
- default: assert(0 && "unknown enum value");
-
-#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
- { \
- const char* pAttributeName = NAME; \
- const bool optional = true; \
- switch (S->FN) { \
- default: assert(0 && "unknown enum value");
-
-#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
-#define END_ENUM_XML } }
-#define END_NODE_XML }
-
-#define ID_ATTRIBUTE_XML Doc.addAttribute("id", S);
-#define SUB_NODE_XML( CLASS )
-#define SUB_NODE_SEQUENCE_XML( CLASS )
-#define SUB_NODE_OPT_XML( CLASS )
-
-#include "clang/Frontend/StmtXML.def"
-
-#if (0)
- // Stmts.
- void VisitStmt(Stmt *Node);
- void VisitDeclStmt(DeclStmt *Node);
- void VisitLabelStmt(LabelStmt *Node);
- void VisitGotoStmt(GotoStmt *Node);
-
- // Exprs
- void VisitExpr(Expr *Node);
- void VisitDeclRefExpr(DeclRefExpr *Node);
- void VisitPredefinedExpr(PredefinedExpr *Node);
- void VisitCharacterLiteral(CharacterLiteral *Node);
- void VisitIntegerLiteral(IntegerLiteral *Node);
- void VisitFloatingLiteral(FloatingLiteral *Node);
- void VisitStringLiteral(StringLiteral *Str);
- void VisitUnaryOperator(UnaryOperator *Node);
- void VisitOffsetOfExpr(OffsetOfExpr *Node);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
- void VisitMemberExpr(MemberExpr *Node);
- void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
- void VisitBinaryOperator(BinaryOperator *Node);
- void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
- void VisitAddrLabelExpr(AddrLabelExpr *Node);
-
- // C++
- void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
- void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
- void VisitCXXThisExpr(CXXThisExpr *Node);
- void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
-
- // ObjC
- void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
- void VisitObjCMessageExpr(ObjCMessageExpr* Node);
- void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
- void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
- void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
- void VisitObjCImplicitSetterGetterRefExpr(
- ObjCImplicitSetterGetterRefExpr *Node);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
-#endif
- };
-}
-
-//===----------------------------------------------------------------------===//
-// Stmt printing methods.
-//===----------------------------------------------------------------------===//
-#if (0)
-void StmtXML::VisitStmt(Stmt *Node) {
- // nothing special to do
-}
-
-void StmtXML::VisitDeclStmt(DeclStmt *Node) {
- for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
- DI != DE; ++DI) {
- Doc.PrintDecl(*DI);
- }
-}
-
-void StmtXML::VisitLabelStmt(LabelStmt *Node) {
- Doc.addAttribute("name", Node->getName());
-}
-
-void StmtXML::VisitGotoStmt(GotoStmt *Node) {
- Doc.addAttribute("name", Node->getLabel()->getName());
-}
-
-//===----------------------------------------------------------------------===//
-// Expr printing methods.
-//===----------------------------------------------------------------------===//
-
-void StmtXML::VisitExpr(Expr *Node) {
- DumpExpr(Node);
-}
-
-void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) {
- DumpExpr(Node);
-
- const char* pKind;
- switch (Node->getDecl()->getKind()) {
- case Decl::Function: pKind = "FunctionDecl"; break;
- case Decl::Var: pKind = "Var"; break;
- case Decl::ParmVar: pKind = "ParmVar"; break;
- case Decl::EnumConstant: pKind = "EnumConstant"; break;
- case Decl::Typedef: pKind = "Typedef"; break;
- case Decl::Record: pKind = "Record"; break;
- case Decl::Enum: pKind = "Enum"; break;
- case Decl::CXXRecord: pKind = "CXXRecord"; break;
- case Decl::ObjCInterface: pKind = "ObjCInterface"; break;
- case Decl::ObjCClass: pKind = "ObjCClass"; break;
- default: pKind = "Decl"; break;
- }
-
- Doc.addAttribute("kind", pKind);
- Doc.addAttribute("name", Node->getDecl()->getNameAsString());
- Doc.addRefAttribute(Node->getDecl());
-}
-
-void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) {
- DumpExpr(Node);
- switch (Node->getIdentType()) {
- default: assert(0 && "unknown case");
- case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break;
- case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break;
- case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break;
- }
-}
-
-void StmtXML::VisitCharacterLiteral(CharacterLiteral *Node) {
- DumpExpr(Node);
- Doc.addAttribute("value", Node->getValue());
-}
-
-void StmtXML::VisitIntegerLiteral(IntegerLiteral *Node) {
- DumpExpr(Node);
- bool isSigned = Node->getType()->isSignedIntegerType();
- Doc.addAttribute("value", Node->getValue().toString(10, isSigned));
-}
-
-void StmtXML::VisitFloatingLiteral(FloatingLiteral *Node) {
- DumpExpr(Node);
- // FIXME: output float as written in source (no approximation or the like)
- //Doc.addAttribute("value", Node->getValueAsApproximateDouble()));
- Doc.addAttribute("value", "FIXME");
-}
-
-void StmtXML::VisitStringLiteral(StringLiteral *Str) {
- DumpExpr(Str);
- if (Str->isWide())
- Doc.addAttribute("is_wide", "1");
-
- Doc.addAttribute("value", Doc.escapeString(Str->getStrData(), Str->getByteLength()));
-}
-
-
-const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) {
- switch (Op) {
- default: assert(0 && "Unknown unary operator");
- case UnaryOperator::PostInc: return "postinc";
- case UnaryOperator::PostDec: return "postdec";
- case UnaryOperator::PreInc: return "preinc";
- case UnaryOperator::PreDec: return "predec";
- case UnaryOperator::AddrOf: return "addrof";
- case UnaryOperator::Deref: return "deref";
- case UnaryOperator::Plus: return "plus";
- case UnaryOperator::Minus: return "minus";
- case UnaryOperator::Not: return "not";
- case UnaryOperator::LNot: return "lnot";
- case UnaryOperator::Real: return "__real";
- case UnaryOperator::Imag: return "__imag";
- case UnaryOperator::Extension: return "__extension__";
- }
-}
-
-
-const char *StmtXML::getOpcodeStr(BinaryOperator::Opcode Op) {
- switch (Op) {
- default: assert(0 && "Unknown binary operator");
- case BinaryOperator::PtrMemD: return "ptrmemd";
- case BinaryOperator::PtrMemI: return "ptrmemi";
- case BinaryOperator::Mul: return "mul";
- case BinaryOperator::Div: return "div";
- case BinaryOperator::Rem: return "rem";
- case BinaryOperator::Add: return "add";
- case BinaryOperator::Sub: return "sub";
- case BinaryOperator::Shl: return "shl";
- case BinaryOperator::Shr: return "shr";
- case BinaryOperator::LT: return "lt";
- case BinaryOperator::GT: return "gt";
- case BinaryOperator::LE: return "le";
- case BinaryOperator::GE: return "ge";
- case BinaryOperator::EQ: return "eq";
- case BinaryOperator::NE: return "ne";
- case BinaryOperator::And: return "and";
- case BinaryOperator::Xor: return "xor";
- case BinaryOperator::Or: return "or";
- case BinaryOperator::LAnd: return "land";
- case BinaryOperator::LOr: return "lor";
- case BinaryOperator::Assign: return "assign";
- case BinaryOperator::MulAssign: return "mulassign";
- case BinaryOperator::DivAssign: return "divassign";
- case BinaryOperator::RemAssign: return "remassign";
- case BinaryOperator::AddAssign: return "addassign";
- case BinaryOperator::SubAssign: return "subassign";
- case BinaryOperator::ShlAssign: return "shlassign";
- case BinaryOperator::ShrAssign: return "shrassign";
- case BinaryOperator::AndAssign: return "andassign";
- case BinaryOperator::XorAssign: return "xorassign";
- case BinaryOperator::OrAssign: return "orassign";
- case BinaryOperator::Comma: return "comma";
- }
-}
-
-void StmtXML::VisitUnaryOperator(UnaryOperator *Node) {
- DumpExpr(Node);
- Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
-}
-
-void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) {
- DumpExpr(Node);
-}
-
-void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");
- Doc.addAttribute("is_type", Node->isArgumentType() ? "1" : "0");
- if (Node->isArgumentType())
- DumpTypeExpr(Node->getArgumentType());
-}
-
-void StmtXML::VisitMemberExpr(MemberExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("is_deref", Node->isArrow() ? "1" : "0");
- Doc.addAttribute("name", Node->getMemberDecl()->getNameAsString());
- Doc.addRefAttribute(Node->getMemberDecl());
-}
-
-void StmtXML::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("name", Node->getAccessor().getName());
-}
-
-void StmtXML::VisitBinaryOperator(BinaryOperator *Node) {
- DumpExpr(Node);
- Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
-}
-
-void StmtXML::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
- VisitBinaryOperator(Node);
-/* FIXME: is this needed in the AST?
- DumpExpr(Node);
- CurrentNode = CurrentNode->addSubNode("ComputeLHSTy");
- DumpType(Node->getComputationLHSType());
- CurrentNode = CurrentNode->Parent->addSubNode("ComputeResultTy");
- DumpType(Node->getComputationResultType());
- Doc.toParent();
-*/
-}
-
-// GNU extensions.
-
-void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("name", Node->getLabel()->getName());
-}
-
-//===----------------------------------------------------------------------===//
-// C++ Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtXML::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("kind", Node->getCastName());
- DumpTypeExpr(Node->getTypeAsWritten());
-}
-
-void StmtXML::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("value", Node->getValue() ? "true" : "false");
-}
-
-void StmtXML::VisitCXXThisExpr(CXXThisExpr *Node) {
- DumpExpr(Node);
-}
-
-void StmtXML::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
- DumpExpr(Node);
- DumpTypeExpr(Node->getTypeAsWritten());
-}
-
-//===----------------------------------------------------------------------===//
-// Obj-C Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
- DumpExpr(Node);
- Doc.addAttribute("selector", Node->getSelector().getAsString());
- IdentifierInfo* clsName = Node->getClassName();
- if (clsName)
- Doc.addAttribute("class", clsName->getName());
-}
-
-void StmtXML::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
- DumpExpr(Node);
- DumpTypeExpr(Node->getEncodedType());
-}
-
-void StmtXML::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("selector", Node->getSelector().getAsString());
-}
-
-void StmtXML::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("protocol", Node->getProtocol()->getNameAsString());
-}
-
-void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("property", Node->getProperty()->getNameAsString());
-}
-
-void StmtXML::VisitObjCImplicitSetterGetterRefExpr(
- ObjCImplicitSetterGetterRefExpr *Node) {
- DumpExpr(Node);
- ObjCMethodDecl *Getter = Node->getGetterMethod();
- ObjCMethodDecl *Setter = Node->getSetterMethod();
- Doc.addAttribute("Getter", Getter->getSelector().getAsString());
- Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)");
-}
-
-void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
- DumpExpr(Node);
- Doc.addAttribute("kind", Node->getDecl()->getDeclKindName());
- Doc.addAttribute("decl", Node->getDecl()->getNameAsString());
- if (Node->isFreeIvar())
- Doc.addAttribute("isFreeIvar", "1");
-}
-#endif
-//===----------------------------------------------------------------------===//
-// Stmt method implementations
-//===----------------------------------------------------------------------===//
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void DocumentXML::PrintStmt(const Stmt *S) {
- StmtXML P(*this);
- P.DumpSubTree(const_cast<Stmt*>(S));
-}
-
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 084915311dcc..47c942ca8dfa 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -53,8 +53,11 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
delete &OS;
}
-void TextDiagnosticPrinter::
-PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) {
+void TextDiagnosticPrinter::PrintIncludeStack(Diagnostic::Level Level,
+ SourceLocation Loc,
+ const SourceManager &SM) {
+ if (!DiagOpts->ShowNoteIncludeStack && Level == Diagnostic::Note) return;
+
if (Loc.isInvalid()) return;
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
@@ -62,7 +65,7 @@ PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) {
return;
// Print out the other include frames first.
- PrintIncludeStack(PLoc.getIncludeLoc(), SM);
+ PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM);
if (DiagOpts->ShowLocation)
OS << "In file included from " << PLoc.getFilename()
@@ -289,7 +292,8 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
}
}
-void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
+void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level,
+ SourceLocation Loc,
CharSourceRange *Ranges,
unsigned NumRanges,
const SourceManager &SM,
@@ -313,7 +317,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
// FIXME: Map ranges?
- EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns,
+ EmitCaretDiagnostic(Level, OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns,
OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
// Map the location.
@@ -339,7 +343,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
// "included from" lines.
if (LastWarningLoc != PLoc.getIncludeLoc()) {
LastWarningLoc = PLoc.getIncludeLoc();
- PrintIncludeStack(LastWarningLoc, SM);
+ PrintIncludeStack(Level, LastWarningLoc, SM);
}
if (DiagOpts->ShowLocation) {
@@ -351,8 +355,9 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
}
OS << "note: instantiated from:\n";
- EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns,
- OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
+ EmitCaretDiagnostic(Level, Loc, Ranges, NumRanges, SM, Hints, NumHints,
+ Columns, OnMacroInst + 1, MacroSkipStart,
+ MacroSkipEnd);
return;
}
@@ -805,12 +810,12 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// "included from" lines.
if (LastWarningLoc != PLoc.getIncludeLoc()) {
LastWarningLoc = PLoc.getIncludeLoc();
- PrintIncludeStack(LastWarningLoc, SM);
+ PrintIncludeStack(Level, LastWarningLoc, SM);
StartOfLocationInfo = OS.tell();
}
// Compute the column number.
- if (DiagOpts->ShowLocation && PLoc.isValid()) {
+ if (DiagOpts->ShowLocation) {
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
@@ -903,6 +908,13 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
llvm::SmallString<100> OutStr;
Info.FormatDiagnostic(OutStr);
+ if (DiagOpts->ShowNames &&
+ !DiagnosticIDs::isBuiltinNote(Info.getID())) {
+ OutStr += " [";
+ OutStr += DiagnosticIDs::getName(Info.getID());
+ OutStr += "]";
+ }
+
std::string OptionName;
if (DiagOpts->ShowOptionNames) {
// Was this a warning mapped to an error using -Werror or pragma?
@@ -1034,7 +1046,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
}
}
- EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
+ EmitCaretDiagnostic(Level, LastLoc, Ranges, NumRanges, LastLoc.getManager(),
Info.getFixItHints(),
Info.getNumFixItHints(),
DiagOpts->MessageLength,
diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp
deleted file mode 100644
index a8c8f75d4b7f..000000000000
--- a/lib/Frontend/TypeXML.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the XML document class, which provides the means to
-// dump out the AST in a XML form that exposes type details and other fields.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/DocumentXML.h"
-#include "clang/AST/TypeVisitor.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/Decl.h"
-
-namespace clang {
- namespace XML {
- namespace {
-
-//---------------------------------------------------------
-class TypeWriter : public TypeVisitor<TypeWriter> {
- DocumentXML& Doc;
-
-public:
- TypeWriter(DocumentXML& doc) : Doc(doc) {}
-
-#define NODE_XML( CLASS, NAME ) \
- void Visit##CLASS(const CLASS* T) { \
- Doc.addSubNode(NAME);
-
-#define ID_ATTRIBUTE_XML // done by the Document class itself
-#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN);
-#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type")
-#define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context")
-#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN);
-
-#define ATTRIBUTE_ENUM_XML( FN, NAME ) \
- { \
- const char* pAttributeName = NAME; \
- const bool optional = false; \
- switch (T->FN) { \
- default: assert(0 && "unknown enum value");
-
-#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
- { \
- const char* pAttributeName = NAME; \
- const bool optional = true; \
- switch (T->FN) { \
- default: assert(0 && "unknown enum value");
-
-#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
-#define END_ENUM_XML } }
-#define END_NODE_XML }
-
-#include "clang/Frontend/TypeXML.def"
-
-};
-
-//---------------------------------------------------------
- } // anon clang
- } // NS XML
-
-//---------------------------------------------------------
-class DocumentXML::TypeAdder : public TypeVisitor<DocumentXML::TypeAdder> {
- DocumentXML& Doc;
-
- void addIfType(const Type* pType) {
- Doc.addTypeRecursively(pType);
- }
-
- void addIfType(const QualType& pType) {
- Doc.addTypeRecursively(pType);
- }
-
- template<class T> void addIfType(T) {}
-
-public:
- TypeAdder(DocumentXML& doc) : Doc(doc) {}
-
-#define NODE_XML( CLASS, NAME ) \
- void Visit##CLASS(const CLASS* T) \
- {
-
-#define ID_ATTRIBUTE_XML
-#define TYPE_ATTRIBUTE_XML( FN ) Doc.addTypeRecursively(T->FN);
-#define CONTEXT_ATTRIBUTE_XML( FN )
-#define ATTRIBUTE_XML( FN, NAME ) addIfType(T->FN);
-#define ATTRIBUTE_OPT_XML( FN, NAME )
-#define ATTRIBUTE_ENUM_XML( FN, NAME )
-#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME )
-#define ENUM_XML( VALUE, NAME )
-#define END_ENUM_XML
-#define END_NODE_XML }
-
-#include "clang/Frontend/TypeXML.def"
-};
-
-//---------------------------------------------------------
-void DocumentXML::addParentTypes(const Type* pType) {
- TypeAdder(*this).Visit(pType);
-}
-
-//---------------------------------------------------------
-void DocumentXML::writeTypeToXML(const Type* pType) {
- XML::TypeWriter(*this).Visit(const_cast<Type*>(pType));
-}
-
-//---------------------------------------------------------
-void DocumentXML::writeTypeToXML(const QualType& pType) {
- XML::TypeWriter(*this).VisitQualType(const_cast<QualType*>(&pType));
-}
-
-//---------------------------------------------------------
-} // NS clang
-
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 65fad6da51fa..664b53351dc1 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -37,7 +37,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case ASTDump: return new ASTDumpAction();
case ASTDumpXML: return new ASTDumpXMLAction();
case ASTPrint: return new ASTPrintAction();
- case ASTPrintXML: return new ASTPrintXMLAction();
case ASTView: return new ASTViewAction();
case BoostCon: return new BoostConAction();
case CreateModule: return 0;
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 1e9eacc13ab3..78fd6f19f67b 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -1,22 +1,28 @@
set(files
altivec.h
avxintrin.h
- emmintrin.h
- float.h
+ emmintrin.h
+ float.h
immintrin.h
- iso646.h
- limits.h
- mm_malloc.h
- mmintrin.h
- pmmintrin.h
+ iso646.h
+ limits.h
+ mm3dnow.h
+ mmintrin.h
+ mm_malloc.h
+ nmmintrin.h
+ pmmintrin.h
smmintrin.h
- stdarg.h
- stdbool.h
- stddef.h
- stdint.h
+ stdarg.h
+ stdbool.h
+ stddef.h
+ stdint.h
tgmath.h
tmmintrin.h
- xmmintrin.h)
+ varargs.h
+ wmmintrin.h
+ x86intrin.h
+ xmmintrin.h
+ )
set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index 884d31cb8917..2eb2f8562256 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -385,41 +385,23 @@ _mm256_dp_ps(__m256 a, __m256 b, const int c)
#define _CMP_GT_OQ 0x1e /* Greater-than (ordered, non-signaling) */
#define _CMP_TRUE_US 0x1f /* True (unordered, signaling) */
-static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmp_pd(__m128d a, __m128d b, const int c)
-{
- return (__m128d)__builtin_ia32_cmppd((__v2df)a, (__v2df)b, c);
-}
+#define _mm_cmp_pd(a, b, c) \
+ (__m128d)__builtin_ia32_cmppd((__v2df)(a), (__v2df)(b), (c))
-static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmp_ps(__m128 a, __m128 b, const int c)
-{
- return (__m128)__builtin_ia32_cmpps((__v4sf)a, (__v4sf)b, c);
-}
+#define _mm_cmp_ps(a, b, c) \
+ (__m128)__builtin_ia32_cmpps((__v4sf)(a), (__v4sf)(b), (c))
-static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_cmp_pd(__m256d a, __m256d b, const int c)
-{
- return (__m256d)__builtin_ia32_cmppd256((__v4df)a, (__v4df)b, c);
-}
+#define _mm256_cmp_pd(a, b, c) \
+ (__m256d)__builtin_ia32_cmppd256((__v4df)(a), (__v4df)(b), (c))
-static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_cmp_ps(__m256 a, __m256 b, const int c)
-{
- return (__m256)__builtin_ia32_cmpps256((__v8sf)a, (__v8sf)b, c);
-}
+#define _mm256_cmp_ps(a, b, c) \
+ (__m256)__builtin_ia32_cmpps256((__v8sf)(a), (__v8sf)(b), (c))
-static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmp_sd(__m128d a, __m128d b, const int c)
-{
- return (__m128d)__builtin_ia32_cmpsd((__v2df)a, (__v2df)b, c);
-}
+#define _mm_cmp_sd(a, b, c) \
+ (__m128d)__builtin_ia32_cmpsd((__v2df)(a), (__v2df)(b), (c))
-static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmp_ss(__m128 a, __m128 b, const int c)
-{
- return (__m128)__builtin_ia32_cmpss((__v4sf)a, (__v4sf)b, c);
-}
+#define _mm_cmp_ss(a, b, c) \
+ (__m128)__builtin_ia32_cmpss((__v4sf)(a), (__v4sf)(b), (c))
/* Vector extract */
static __inline __m128d __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 11b258178103..0c1d730f015d 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -466,7 +466,7 @@ _mm_loadr_pd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadu_pd(double const *dp)
{
- return __builtin_ia32_loadupd(dp);
+ return (__m128d){ dp[0], dp[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -1210,16 +1210,18 @@ _mm_movemask_epi8(__m128i a)
}
#define _mm_shuffle_epi32(a, imm) \
- ((__m128i)__builtin_shufflevector((__v4si)(a), (__v4si) {0}, \
+ ((__m128i)__builtin_shufflevector((__v4si)(a), (__v4si) _mm_set1_epi32(0), \
(imm) & 0x3, ((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6))
+
+
#define _mm_shufflelo_epi16(a, imm) \
- ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) {0}, \
+ ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) _mm_set1_epi16(0), \
(imm) & 0x3, ((imm) & 0xc) >> 2, \
((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
4, 5, 6, 7))
#define _mm_shufflehi_epi16(a, imm) \
- ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) {0}, 0, 1, 2, 3, \
+ ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) _mm_set1_epi16(0), 0, 1, 2, 3, \
4 + (((imm) & 0x03) >> 0), \
4 + (((imm) & 0x0c) >> 2), \
4 + (((imm) & 0x30) >> 4), \
diff --git a/lib/Headers/mm3dnow.h b/lib/Headers/mm3dnow.h
new file mode 100644
index 000000000000..2f456ad940eb
--- /dev/null
+++ b/lib/Headers/mm3dnow.h
@@ -0,0 +1,161 @@
+/*===---- mm3dnow.h - 3DNow! 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 _MM3DNOW_H_INCLUDED
+#define _MM3DNOW_H_INCLUDED
+
+#include <mmintrin.h>
+
+typedef float __v2sf __attribute__((__vector_size__(8)));
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_m_femms() {
+ __builtin_ia32_femms();
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pavgusb(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pavgusb((__v8qi)__m1, (__v8qi)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pf2id(__m64 __m) {
+ return (__m64)__builtin_ia32_pf2id((__v2sf)__m);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfacc(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfacc((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfadd(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfadd((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfcmpeq(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfcmpeq((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfcmpge(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfcmpge((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfcmpgt(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfcmpgt((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfmax(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfmax((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfmin(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfmin((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfmul(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfmul((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfrcp(__m64 __m) {
+ return (__m64)__builtin_ia32_pfrcp((__v2sf)__m);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfrcpit1(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfrcpit1((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfrcpit2(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfrcpit2((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfrsqrt(__m64 __m) {
+ return (__m64)__builtin_ia32_pfrsqrt((__v2sf)__m);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfrsqrtit1(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfrsqrtit1((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfsub(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfsub((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfsubr(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfsubr((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pi2fd(__m64 __m) {
+ return (__m64)__builtin_ia32_pi2fd((__v2si)__m);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pmulhrw(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pmulhrw((__v4hi)__m1, (__v4hi)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pf2iw(__m64 __m) {
+ return (__m64)__builtin_ia32_pf2iw((__v2sf)__m);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfnacc(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfnacc((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pfpnacc(__m64 __m1, __m64 __m2) {
+ return (__m64)__builtin_ia32_pfpnacc((__v2sf)__m1, (__v2sf)__m2);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pi2fw(__m64 __m) {
+ return (__m64)__builtin_ia32_pi2fw((__v2si)__m);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pswapdsf(__m64 __m) {
+ return (__m64)__builtin_ia32_pswapdsf((__v2sf)__m);
+}
+
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
+_m_pswapdsi(__m64 __m) {
+ return (__m64)__builtin_ia32_pswapdsi((__v2si)__m);
+}
+
+#endif
diff --git a/lib/Headers/mm_malloc.h b/lib/Headers/mm_malloc.h
index e7da5434587a..ec9236204bb9 100644
--- a/lib/Headers/mm_malloc.h
+++ b/lib/Headers/mm_malloc.h
@@ -40,6 +40,7 @@ extern "C" int posix_memalign(void **memptr, size_t alignment, size_t size);
#endif
#endif
+#if !(defined(_WIN32) && defined(_mm_malloc))
static __inline__ void *__attribute__((__always_inline__, __nodebug__,
__malloc__))
_mm_malloc(size_t size, size_t align)
@@ -67,5 +68,6 @@ _mm_free(void *p)
{
free(p);
}
+#endif
#endif /* __MM_MALLOC_H */
diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h
index 7cc0bc1a75fd..9e87ee89b3b9 100644
--- a/lib/Headers/stddef.h
+++ b/lib/Headers/stddef.h
@@ -26,7 +26,10 @@
#ifndef __STDDEF_H
#define __STDDEF_H
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
+#endif
#ifndef _SIZE_T
#define _SIZE_T
typedef __typeof__(sizeof(int)) size_t;
@@ -51,7 +54,7 @@ typedef __WCHAR_TYPE__ wchar_t;
#endif /* __STDDEF_H */
/* Some C libraries expect to see a wint_t here. Others (notably MinGW) will use
-__WINT_TYPE__ directly; accomodate both by requiring __need_wint_t */
+__WINT_TYPE__ directly; accommodate both by requiring __need_wint_t */
#if defined(__need_wint_t)
#if !defined(_WINT_T)
#define _WINT_T
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
index 9498ed5f52d9..6f1a8761e1c8 100644
--- a/lib/Headers/stdint.h
+++ b/lib/Headers/stdint.h
@@ -46,7 +46,7 @@
* and 64-bit widths regardless of whether there are corresponding exact-width
* types.
*
- * To accomodate targets that are missing types that are exactly 8, 16, 32, or
+ * To accommodate targets that are missing types that are exactly 8, 16, 32, or
* 64 bits wide, this implementation takes an approach of cascading
* redefintions, redefining __int_leastN_t to successively smaller exact-width
* types. It is therefore important that the types are defined in order of
@@ -58,7 +58,7 @@
*
* In violation of the standard, some targets do not implement a type that is
* wide enough to represent all of the required widths (8-, 16-, 32-, 64-bit).
- * To accomodate these targets, a required minimum-width type is only
+ * To accommodate these targets, a required minimum-width type is only
* defined if there exists an exact-width type of equal or greater width.
*/
@@ -609,11 +609,15 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define UINT_FAST8_MAX __UINT_LEAST8_MAX
#endif /* __INT_LEAST8_MIN */
+/* Some utility macros */
+#define __INTN_MIN(n) __stdint_join3( INT, n, _MIN)
+#define __INTN_MAX(n) __stdint_join3( INT, n, _MAX)
+#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX)
+#define __INTN_C(n, v) __stdint_join3( INT, n, _C(v))
+#define __UINTN_C(n, v) __stdint_join3(UINT, n, _C(v))
+
/* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */
/* C99 7.18.3 Limits of other integer types. */
-#define __INTN_MIN(n) __stdint_join3( INT, n, _MIN)
-#define __INTN_MAX(n) __stdint_join3( INT, n, _MAX)
-#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX)
#define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__)
#define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__)
@@ -630,23 +634,26 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* C99 7.18.3 Limits of other integer types. */
#define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__)
#define SIG_ATOMIC_MAX __INTN_MAX(__SIG_ATOMIC_WIDTH__)
-#define WINT_MIN __INTN_MIN(__WINT_WIDTH__)
-#define WINT_MAX __INTN_MAX(__WINT_WIDTH__)
+#ifdef __WINT_UNSIGNED__
+# define WINT_MIN __UINTN_C(__WINT_WIDTH__, 0)
+# define WINT_MAX __UINTN_MAX(__WINT_WIDTH__)
+#else
+# define WINT_MIN __INTN_MIN(__WINT_WIDTH__)
+# define WINT_MAX __INTN_MAX(__WINT_WIDTH__)
+#endif
-/* FIXME: if we ever support a target with unsigned wchar_t, this should be
- * 0 .. Max.
- */
#ifndef WCHAR_MAX
-#define WCHAR_MAX __INTN_MAX(__WCHAR_WIDTH__)
+# define WCHAR_MAX __WCHAR_MAX__
#endif
#ifndef WCHAR_MIN
-#define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__)
+# if __WCHAR_MAX__ == __INTN_MAX(__WCHAR_WIDTH__)
+# define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__)
+# else
+# define WCHAR_MIN __UINTN_C(__WCHAR_WIDTH__, 0)
+# endif
#endif
/* 7.18.4.2 Macros for greatest-width integer constants. */
-#define __INTN_C(n, v) __stdint_join3( INT, n, _C(v))
-#define __UINTN_C(n, v) __stdint_join3(UINT, n, _C(v))
-
#define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v)
#define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v)
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 42dd3e8d3b87..00760ed6d1ef 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -539,7 +539,7 @@ _mm_load_ps(const float *p)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadu_ps(const float *p)
{
- return __builtin_ia32_loadups(p);
+ return (__m128){ p[0], p[1], p[2], p[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Index/DeclReferenceMap.cpp b/lib/Index/DeclReferenceMap.cpp
index d6e30ab39658..3fd4336230e2 100644
--- a/lib/Index/DeclReferenceMap.cpp
+++ b/lib/Index/DeclReferenceMap.cpp
@@ -55,7 +55,7 @@ void RefMapper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
}
void RefMapper::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
- NamedDecl *ND = TL.getTypedefDecl();
+ NamedDecl *ND = TL.getTypedefNameDecl();
Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc())));
}
diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp
index 749dcc899322..afac05c41377 100644
--- a/lib/Index/Entity.cpp
+++ b/lib/Index/Entity.cpp
@@ -141,7 +141,7 @@ Entity EntityGetter::VisitVarDecl(VarDecl *D) {
}
Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) {
- // If it's static it cannot be refered to by another translation unit.
+ // If it's static it cannot be referred to by another translation unit.
if (D->getStorageClass() == SC_Static)
return Entity(D);
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index e424f9165515..e102a6da608c 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -199,8 +199,8 @@ void HeaderMap::dump() const {
/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap. If so, open it and return its FileEntry.
-const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename,
- FileManager &FM) const {
+const FileEntry *HeaderMap::LookupFile(
+ llvm::StringRef Filename, FileManager &FM) const {
const HMapHeader &Hdr = getHeader();
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index b028e339ae91..372078c60d20 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -114,8 +114,11 @@ const char *DirectoryLookup::getName() const {
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
-const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename,
- HeaderSearch &HS) const {
+const FileEntry *DirectoryLookup::LookupFile(
+ llvm::StringRef Filename,
+ HeaderSearch &HS,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath) const {
llvm::SmallString<1024> TmpDir;
if (isNormalDir()) {
// Concatenate the requested file onto the directory.
@@ -123,21 +126,46 @@ const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename,
TmpDir += getDir()->getName();
TmpDir.push_back('/');
TmpDir.append(Filename.begin(), Filename.end());
- return HS.getFileMgr().getFile(TmpDir.str());
+ if (SearchPath != NULL) {
+ llvm::StringRef SearchPathRef(getDir()->getName());
+ SearchPath->clear();
+ SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+ }
+ if (RelativePath != NULL) {
+ RelativePath->clear();
+ RelativePath->append(Filename.begin(), Filename.end());
+ }
+ return HS.getFileMgr().getFile(TmpDir.str(), /*openFile=*/true);
}
if (isFramework())
- return DoFrameworkLookup(Filename, HS);
+ return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath);
assert(isHeaderMap() && "Unknown directory lookup");
- return getHeaderMap()->LookupFile(Filename, HS.getFileMgr());
+ const FileEntry * const Result = getHeaderMap()->LookupFile(
+ Filename, HS.getFileMgr());
+ if (Result) {
+ if (SearchPath != NULL) {
+ llvm::StringRef SearchPathRef(getName());
+ SearchPath->clear();
+ SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+ }
+ if (RelativePath != NULL) {
+ RelativePath->clear();
+ RelativePath->append(Filename.begin(), Filename.end());
+ }
+ }
+ return Result;
}
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
-const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
- HeaderSearch &HS) const {
+const FileEntry *DirectoryLookup::DoFrameworkLookup(
+ llvm::StringRef Filename,
+ HeaderSearch &HS,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath) const {
FileManager &FileMgr = HS.getFileMgr();
// Framework names must have a '/' in the filename.
@@ -183,19 +211,37 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
FrameworkDirCache = getFrameworkDir();
}
+ if (RelativePath != NULL) {
+ RelativePath->clear();
+ RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
+ }
+
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
unsigned OrigSize = FrameworkName.size();
FrameworkName += "Headers/";
+
+ if (SearchPath != NULL) {
+ SearchPath->clear();
+ // Without trailing '/'.
+ SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
+ }
+
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
- if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str()))
+ if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
+ /*openFile=*/true)) {
return FE;
+ }
// Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
const char *Private = "Private";
FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
Private+strlen(Private));
- return FileMgr.getFile(FrameworkName.str());
+ if (SearchPath != NULL)
+ SearchPath->insert(SearchPath->begin()+OrigSize, Private,
+ Private+strlen(Private));
+
+ return FileMgr.getFile(FrameworkName.str(), /*openFile=*/true);
}
@@ -209,11 +255,14 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
/// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if
/// non-null, indicates where the #including file is, in case a relative search
/// is needed.
-const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
- bool isAngled,
- const DirectoryLookup *FromDir,
- const DirectoryLookup *&CurDir,
- const FileEntry *CurFileEnt) {
+const FileEntry *HeaderSearch::LookupFile(
+ llvm::StringRef Filename,
+ bool isAngled,
+ const DirectoryLookup *FromDir,
+ const DirectoryLookup *&CurDir,
+ const FileEntry *CurFileEnt,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath) {
// If 'Filename' is absolute, check to see if it exists and no searching.
if (llvm::sys::path::is_absolute(Filename)) {
CurDir = 0;
@@ -221,8 +270,14 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
// If this was an #include_next "/absolute/file", fail.
if (FromDir) return 0;
+ if (SearchPath != NULL)
+ SearchPath->clear();
+ if (RelativePath != NULL) {
+ RelativePath->clear();
+ RelativePath->append(Filename.begin(), Filename.end());
+ }
// Otherwise, just return the file.
- return FileMgr.getFile(Filename);
+ return FileMgr.getFile(Filename, /*openFile=*/true);
}
// Step #0, unless disabled, check to see if the file is in the #includer's
@@ -237,7 +292,7 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
TmpDir += CurFileEnt->getDir()->getName();
TmpDir.push_back('/');
TmpDir.append(Filename.begin(), Filename.end());
- if (const FileEntry *FE = FileMgr.getFile(TmpDir.str())) {
+ if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(),/*openFile=*/true)) {
// Leave CurDir unset.
// This file is a system header or C++ unfriendly if the old file is.
//
@@ -246,6 +301,15 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
// of evaluation.
unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo;
getFileInfo(FE).DirInfo = DirInfo;
+ if (SearchPath != NULL) {
+ llvm::StringRef SearchPathRef(CurFileEnt->getDir()->getName());
+ SearchPath->clear();
+ SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+ }
+ if (RelativePath != NULL) {
+ RelativePath->clear();
+ RelativePath->append(Filename.begin(), Filename.end());
+ }
return FE;
}
}
@@ -283,7 +347,7 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
const FileEntry *FE =
- SearchDirs[i].LookupFile(Filename, *this);
+ SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath);
if (!FE) continue;
CurDir = &SearchDirs[i];
@@ -308,7 +372,9 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
/// for the designated file, otherwise return null.
const FileEntry *HeaderSearch::
LookupSubframeworkHeader(llvm::StringRef Filename,
- const FileEntry *ContextFileEnt) {
+ const FileEntry *ContextFileEnt,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath) {
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
@@ -356,17 +422,34 @@ LookupSubframeworkHeader(llvm::StringRef Filename,
const FileEntry *FE = 0;
+ if (RelativePath != NULL) {
+ RelativePath->clear();
+ RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
+ }
+
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
llvm::SmallString<1024> HeadersFilename(FrameworkName);
HeadersFilename += "Headers/";
+ if (SearchPath != NULL) {
+ SearchPath->clear();
+ // Without trailing '/'.
+ SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
+ }
+
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename.str()))) {
+ if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true))) {
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
HeadersFilename += "PrivateHeaders/";
+ if (SearchPath != NULL) {
+ SearchPath->clear();
+ // Without trailing '/'.
+ SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
+ }
+
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename.str())))
+ if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true)))
return 0;
}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index b17198b21983..16cc4f8fd54f 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -71,9 +71,22 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
"We assume that the input buffer has a null character at the end"
" to simplify lexing!");
+ // Check whether we have a BOM in the beginning of the buffer. If yes - act
+ // accordingly. Right now we support only UTF-8 with and without BOM, so, just
+ // skip the UTF-8 BOM if it's present.
+ if (BufferStart == BufferPtr) {
+ // Determine the size of the BOM.
+ size_t BOMLength = llvm::StringSwitch<size_t>(BufferStart)
+ .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM
+ .Default(0);
+
+ // Skip the BOM.
+ BufferPtr += BOMLength;
+ }
+
Is_PragmaLexer = false;
IsInConflictMarker = false;
-
+
// Start of the file is a start of line.
IsAtStartOfLine = true;
@@ -178,7 +191,7 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
InstantiationLocEnd, TokLen);
// Ensure that the lexer thinks it is inside a directive, so that end \n will
- // return an EOM token.
+ // return an EOD token.
L->ParsingPreprocessorDirective = true;
// This lexer really is for _Pragma.
@@ -221,6 +234,54 @@ void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) {
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
+llvm::StringRef Lexer::getSpelling(SourceLocation loc,
+ llvm::SmallVectorImpl<char> &buffer,
+ const SourceManager &SM,
+ const LangOptions &options,
+ bool *invalid) {
+ // Break down the source location.
+ std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
+
+ // Try to the load the file buffer.
+ bool invalidTemp = false;
+ llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+ if (invalidTemp) {
+ if (invalid) *invalid = true;
+ return llvm::StringRef();
+ }
+
+ const char *tokenBegin = file.data() + locInfo.second;
+
+ // Lex from the start of the given location.
+ Lexer lexer(SM.getLocForStartOfFile(locInfo.first), options,
+ file.begin(), tokenBegin, file.end());
+ Token token;
+ lexer.LexFromRawLexer(token);
+
+ unsigned length = token.getLength();
+
+ // Common case: no need for cleaning.
+ if (!token.needsCleaning())
+ return llvm::StringRef(tokenBegin, length);
+
+ // Hard case, we need to relex the characters into the string.
+ buffer.clear();
+ buffer.reserve(length);
+
+ for (const char *ti = tokenBegin, *te = ti + length; ti != te; ) {
+ unsigned charSize;
+ buffer.push_back(Lexer::getCharAndSizeNoWarn(ti, charSize, options));
+ ti += charSize;
+ }
+
+ return llvm::StringRef(buffer.data(), buffer.size());
+}
+
+/// getSpelling() - Return the 'spelling' of this token. The spelling of a
+/// token are the characters used to represent the token in the source file
+/// after trigraph expansion and escaped-newline folding. In particular, this
+/// wants to get the true, uncanonicalized, spelling of things like digraphs
+/// UCNs, etc.
std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
const LangOptions &Features, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
@@ -626,7 +687,7 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
else
return Loc;
- return AdvanceToTokenCharacter(Loc, Len, SM, Features);
+ return Loc.getFileLocWithOffset(Len);
}
//===----------------------------------------------------------------------===//
@@ -1407,7 +1468,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
return SaveBCPLComment(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 EOM token.
+ // return immediately, so that the lexer can return this as an EOD token.
if (ParsingPreprocessorDirective || CurPtr == BufferEnd) {
BufferPtr = CurPtr;
return false;
@@ -1534,7 +1595,7 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
/// some tokens, this will store the first token and return true.
bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// Scan one character past where we should, looking for a '/' character. Once
- // we find it, check to see if it was preceeded by a *. This common
+ // we find it, check to see if it was preceded by a *. This common
// optimization helps people who like to put a lot of * characters in their
// comments.
@@ -1715,14 +1776,14 @@ std::string Lexer::ReadToEndOfLine() {
assert(CurPtr[-1] == Char && "Trigraphs for newline?");
BufferPtr = CurPtr-1;
- // Next, lex the character, which should handle the EOM transition.
+ // Next, lex the character, which should handle the EOD transition.
Lex(Tmp);
if (Tmp.is(tok::code_completion)) {
if (PP && PP->getCodeCompletionHandler())
PP->getCodeCompletionHandler()->CodeCompleteNaturalLanguage();
Lex(Tmp);
}
- assert(Tmp.is(tok::eom) && "Unexpected token!");
+ assert(Tmp.is(tok::eod) && "Unexpected token!");
// Finally, we're done, return the string we found.
return Result;
@@ -1758,7 +1819,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// Done parsing the "line".
ParsingPreprocessorDirective = false;
// Update the location of token as well as BufferPtr.
- FormTokenWithChars(Result, CurPtr, tok::eom);
+ FormTokenWithChars(Result, CurPtr, tok::eod);
// Restore comment saving mode, in case it was disabled for directive.
SetCommentRetentionState(PP->getCommentRetentionState());
@@ -2006,7 +2067,7 @@ LexNextToken:
case '\n':
case '\r':
// If we are inside a preprocessor directive and we see the end of line,
- // we know we are done with the directive, so return an EOM token.
+ // we know we are done with the directive, so return an EOD token.
if (ParsingPreprocessorDirective) {
// Done parsing the "line".
ParsingPreprocessorDirective = false;
@@ -2017,7 +2078,7 @@ LexNextToken:
// Since we consumed a newline, we are back at the start of a line.
IsAtStartOfLine = true;
- Kind = tok::eom;
+ Kind = tok::eod;
break;
}
// The returned token is at the start of the line.
@@ -2043,7 +2104,7 @@ 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() &&
- Features.BCPLComment) {
+ Features.BCPLComment && !Features.TraditionalCPP) {
if (SkipBCPLComment(Result, CurPtr+2))
return; // There is a token to return.
goto SkipIgnoredUnits;
@@ -2232,8 +2293,10 @@ LexNextToken:
// this as "foo / bar" and langauges with BCPL 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.
- if (Features.BCPLComment ||
- getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') {
+ // However, we never do this in -traditional-cpp mode.
+ if ((Features.BCPLComment ||
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
+ !Features.TraditionalCPP) {
if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; // There is a token to return.
@@ -2335,6 +2398,21 @@ LexNextToken:
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessequal;
} else if (Features.Digraphs && Char == ':') { // '<:' -> '['
+ if (Features.CPlusPlus0x &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') {
+ // C++0x [lex.pptoken]p3:
+ // Otherwise, if the next three characters are <:: and the subsequent
+ // character is neither : nor >, the < is treated as a preprocessor
+ // token by itself and not as the first character of the alternative
+ // token <:.
+ unsigned SizeTmp3;
+ char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
+ if (After != ':' && After != '>') {
+ Kind = tok::less;
+ break;
+ }
+ }
+
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_square;
} else if (Features.Digraphs && Char == '%') { // '<%' -> '{'
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 16d7b36f02ef..37e7bf4d628e 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -710,7 +710,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
++begin;
// FIXME: The "Value" is an uint64_t so we can handle char literals of
- // upto 64-bits.
+ // up to 64-bits.
// FIXME: This extensively assumes that 'char' is 8-bits.
assert(PP.getTargetInfo().getCharWidth() == 8 &&
"Assumes char is 8 bits");
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index 89f6368a277f..dee7da38aaa0 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -284,7 +284,7 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
if (StringifiedArgs.empty()) {
StringifiedArgs.resize(getNumArguments());
- memset(&StringifiedArgs[0], 0,
+ memset((void*)&StringifiedArgs[0], 0,
sizeof(StringifiedArgs[0])*getNumArguments());
}
if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 3e871ae7ab47..af3fa6e2add7 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -81,17 +81,17 @@ void Preprocessor::ReleaseMacroInfo(MacroInfo *MI) {
}
/// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
-/// current line until the tok::eom token is found.
+/// current line until the tok::eod token is found.
void Preprocessor::DiscardUntilEndOfDirective() {
Token Tmp;
do {
LexUnexpandedToken(Tmp);
assert(Tmp.isNot(tok::eof) && "EOF seen while discarding directive tokens");
- } while (Tmp.isNot(tok::eom));
+ } while (Tmp.isNot(tok::eod));
}
/// ReadMacroName - Lex and validate a macro name, which occurs after a
-/// #define or #undef. This sets the token kind to eom and discards the rest
+/// #define or #undef. This sets the token kind to eod and discards the rest
/// of the macro line if the macro name is invalid. isDefineUndef is 1 if
/// this is due to a a #define, 2 if #undef directive, 0 if it is something
/// else (e.g. #ifdef).
@@ -107,7 +107,7 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
}
// Missing macro name?
- if (MacroNameTok.is(tok::eom)) {
+ if (MacroNameTok.is(tok::eod)) {
Diag(MacroNameTok, diag::err_pp_missing_macro_name);
return;
}
@@ -143,13 +143,13 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
}
// Invalid macro name, read and discard the rest of the line. Then set the
- // token kind to tok::eom.
- MacroNameTok.setKind(tok::eom);
+ // token kind to tok::eod.
+ MacroNameTok.setKind(tok::eod);
return DiscardUntilEndOfDirective();
}
-/// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
-/// not, emit a diagnostic and consume up until the eom. If EnableMacros is
+/// CheckEndOfDirective - Ensure that the next token is a tok::eod token. If
+/// not, emit a diagnostic and consume up until the eod. If EnableMacros is
/// true, then we consider macros that expand to zero tokens as being ok.
void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
Token Tmp;
@@ -166,7 +166,7 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
while (Tmp.is(tok::comment)) // Skip comments in -C mode.
LexUnexpandedToken(Tmp);
- if (Tmp.isNot(tok::eom)) {
+ if (Tmp.isNot(tok::eod)) {
// Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89,
// or if this is a macro-style preprocessing directive, because it is more
// trouble than it is worth to insert /**/ and check that there is no /**/
@@ -238,7 +238,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// We just parsed a # character at the start of a line, so we're in
// directive mode. Tell the lexer this so any newlines we see will be
- // converted into an EOM token (this terminates the macro).
+ // converted into an EOD token (this terminates the macro).
CurPPLexer->ParsingPreprocessorDirective = true;
if (CurLexer) CurLexer->SetCommentRetentionState(false);
@@ -425,7 +425,7 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
if (!CondInfo.FoundNonSkip) {
CondInfo.FoundNonSkip = true;
- // Scan until the eom token.
+ // Scan until the eod token.
CurPTHLexer->ParsingPreprocessorDirective = true;
DiscardUntilEndOfDirective();
CurPTHLexer->ParsingPreprocessorDirective = false;
@@ -469,10 +469,13 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
/// for system #include's or not (i.e. using <> instead of "").
-const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
- bool isAngled,
- const DirectoryLookup *FromDir,
- const DirectoryLookup *&CurDir) {
+const FileEntry *Preprocessor::LookupFile(
+ llvm::StringRef Filename,
+ bool isAngled,
+ const DirectoryLookup *FromDir,
+ const DirectoryLookup *&CurDir,
+ llvm::SmallVectorImpl<char> *SearchPath,
+ llvm::SmallVectorImpl<char> *RelativePath) {
// If the header lookup mechanism may be relative to the current file, pass in
// info about where the current file is.
const FileEntry *CurFileEnt = 0;
@@ -494,8 +497,9 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
// Do a standard file entry lookup.
CurDir = CurDirLookup;
- const FileEntry *FE =
- HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt);
+ const FileEntry *FE = HeaderInfo.LookupFile(
+ Filename, isAngled, FromDir, CurDir, CurFileEnt,
+ SearchPath, RelativePath);
if (FE) return FE;
// Otherwise, see if this is a subframework header. If so, this is relative
@@ -503,7 +507,8 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
// headers on the #include stack and pass them to HeaderInfo.
if (IsFileLexer()) {
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
- if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt)))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
+ SearchPath, RelativePath)))
return FE;
}
@@ -512,7 +517,8 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
if (IsFileLexer(ISEntry)) {
if ((CurFileEnt =
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
- if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt)))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(
+ Filename, CurFileEnt, SearchPath, RelativePath)))
return FE;
}
}
@@ -535,7 +541,7 @@ void Preprocessor::HandleDirective(Token &Result) {
// We just parsed a # character at the start of a line, so we're in directive
// mode. Tell the lexer this so any newlines we see will be converted into an
- // EOM token (which terminates the directive).
+ // EOD token (which terminates the directive).
CurPPLexer->ParsingPreprocessorDirective = true;
++NumDirectives;
@@ -563,7 +569,7 @@ void Preprocessor::HandleDirective(Token &Result) {
TryAgain:
switch (Result.getKind()) {
- case tok::eom:
+ case tok::eod:
return; // null directive.
case tok::comment:
// Handle stuff like "# /*foo*/ define X" in -E -C mode.
@@ -686,7 +692,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
if (DigitTok.isNot(tok::numeric_constant)) {
PP.Diag(DigitTok, DiagID);
- if (DigitTok.isNot(tok::eom))
+ if (DigitTok.isNot(tok::eod))
PP.DiscardUntilEndOfDirective();
return true;
}
@@ -758,9 +764,9 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
Token StrTok;
Lex(StrTok);
- // If the StrTok is "eom", then it wasn't present. Otherwise, it must be a
- // string followed by eom.
- if (StrTok.is(tok::eom))
+ // If the StrTok is "eod", then it wasn't present. Otherwise, it must be a
+ // string followed by eod.
+ if (StrTok.is(tok::eod))
; // ok
else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_line_invalid_filename);
@@ -779,7 +785,7 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString(),
Literal.GetStringLength());
- // Verify that there is nothing after the string, other than EOM. Because
+ // Verify that there is nothing after the string, other than EOD. Because
// of C99 6.10.4p5, macros that expand to empty tokens are ok.
CheckEndOfDirective("line", true);
}
@@ -800,7 +806,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
unsigned FlagVal;
Token FlagTok;
PP.Lex(FlagTok);
- if (FlagTok.is(tok::eom)) return false;
+ if (FlagTok.is(tok::eod)) return false;
if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP))
return true;
@@ -808,7 +814,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
IsFileEntry = true;
PP.Lex(FlagTok);
- if (FlagTok.is(tok::eom)) return false;
+ if (FlagTok.is(tok::eod)) return false;
if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP))
return true;
} else if (FlagVal == 2) {
@@ -834,7 +840,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
}
PP.Lex(FlagTok);
- if (FlagTok.is(tok::eom)) return false;
+ if (FlagTok.is(tok::eod)) return false;
if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP))
return true;
}
@@ -849,7 +855,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
IsSystemHeader = true;
PP.Lex(FlagTok);
- if (FlagTok.is(tok::eom)) return false;
+ if (FlagTok.is(tok::eod)) return false;
if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP))
return true;
@@ -863,7 +869,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
IsExternCHeader = true;
PP.Lex(FlagTok);
- if (FlagTok.is(tok::eom)) return false;
+ if (FlagTok.is(tok::eod)) return false;
// There are no more valid flags here.
PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag);
@@ -893,9 +899,9 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
bool IsSystemHeader = false, IsExternCHeader = false;
int FilenameID = -1;
- // If the StrTok is "eom", then it wasn't present. Otherwise, it must be a
- // string followed by eom.
- if (StrTok.is(tok::eom))
+ // If the StrTok is "eod", then it wasn't present. Otherwise, it must be a
+ // string followed by eod.
+ if (StrTok.is(tok::eod))
; // ok
else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
@@ -978,12 +984,12 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
if (StrTok.isNot(tok::string_literal) &&
StrTok.isNot(tok::wide_string_literal)) {
Diag(StrTok, diag::err_pp_malformed_ident);
- if (StrTok.isNot(tok::eom))
+ if (StrTok.isNot(tok::eod))
DiscardUntilEndOfDirective();
return;
}
- // Verify that there is nothing after the string, other than EOM.
+ // Verify that there is nothing after the string, other than EOD.
CheckEndOfDirective("ident");
if (Callbacks) {
@@ -1052,14 +1058,14 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
///
/// This code concatenates and consumes tokens up to the '>' token. It returns
/// false if the > was found, otherwise it returns true if it finds and consumes
-/// the EOM marker.
+/// the EOD marker.
bool Preprocessor::ConcatenateIncludeName(
llvm::SmallString<128> &FilenameBuffer,
SourceLocation &End) {
Token CurTok;
Lex(CurTok);
- while (CurTok.isNot(tok::eom)) {
+ while (CurTok.isNot(tok::eod)) {
End = CurTok.getLocation();
// FIXME: Provide code completion for #includes.
@@ -1095,8 +1101,8 @@ bool Preprocessor::ConcatenateIncludeName(
Lex(CurTok);
}
- // If we hit the eom marker, emit an error and return true so that the caller
- // knows the EOM has been read.
+ // If we hit the eod marker, emit an error and return true so that the caller
+ // knows the EOD has been read.
Diag(CurTok.getLocation(), diag::err_pp_expects_filename);
return true;
}
@@ -1120,8 +1126,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
SourceLocation End;
switch (FilenameTok.getKind()) {
- case tok::eom:
- // If the token kind is EOM, the error has already been diagnosed.
+ case tok::eod:
+ // If the token kind is EOD, the error has already been diagnosed.
return;
case tok::angle_string_literal:
@@ -1135,7 +1141,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// case, glue the tokens together into FilenameBuffer and interpret those.
FilenameBuffer.push_back('<');
if (ConcatenateIncludeName(FilenameBuffer, End))
- return; // Found <eom> but no ">"? Diagnostic already emitted.
+ return; // Found <eod> but no ">"? Diagnostic already emitted.
Filename = FilenameBuffer.str();
break;
default:
@@ -1153,7 +1159,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
return;
}
- // Verify that there is nothing after the filename, other than EOM. Note that
+ // Verify that there is nothing after the filename, other than EOD. Note that
// we allow macros that expand to nothing after the filename, because this
// falls into the category of "#include pp-tokens new-line" specified in
// C99 6.10.2p4.
@@ -1167,7 +1173,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(Filename, isAngled, LookupFrom, CurDir);
+ llvm::SmallString<1024> SearchPath;
+ llvm::SmallString<1024> RelativePath;
+ // We get the raw path only if we have 'Callbacks' to which we later pass
+ // the path.
+ const FileEntry *File = LookupFile(
+ Filename, isAngled, LookupFrom, CurDir,
+ Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL);
if (File == 0) {
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
@@ -1175,9 +1187,9 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Notify the callback object that we've seen an inclusion directive.
if (Callbacks)
- Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
- End);
-
+ Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
+ End, SearchPath, RelativePath);
+
// The #included file will be considered to be a system header if either it is
// in a system include directory, or if the #includer is a system include
// header.
@@ -1302,7 +1314,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
MI->setIsC99Varargs();
MI->setArgumentList(&Arguments[0], Arguments.size(), BP);
return false;
- case tok::eom: // #define X(
+ case tok::eod: // #define X(
Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
return true;
default:
@@ -1366,7 +1378,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
ReadMacroName(MacroNameTok, 1);
// Error reading macro name? If so, diagnostic already issued.
- if (MacroNameTok.is(tok::eom))
+ if (MacroNameTok.is(tok::eod))
return;
Token LastTok = MacroNameTok;
@@ -1384,7 +1396,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// If this is a function-like macro definition, parse the argument list,
// marking each of the identifiers as being used as macro arguments. Also,
// check other constraints on the first token of the macro body.
- if (Tok.is(tok::eom)) {
+ if (Tok.is(tok::eod)) {
// If there is no body to this macro, we have no special handling here.
} else if (Tok.hasLeadingSpace()) {
// This is a normal token with leading space. Clear the leading space
@@ -1439,13 +1451,13 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
Diag(Tok, diag::warn_missing_whitespace_after_macro_name);
}
- if (!Tok.is(tok::eom))
+ if (!Tok.is(tok::eod))
LastTok = Tok;
// Read the rest of the macro body.
if (MI->isObjectLike()) {
// Object-like macros are very simple, just read their body.
- while (Tok.isNot(tok::eom)) {
+ while (Tok.isNot(tok::eod)) {
LastTok = Tok;
MI->AddTokenToBody(Tok);
// Get the next token of the macro.
@@ -1456,7 +1468,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Otherwise, read the body of a function-like macro. While we are at it,
// check C99 6.10.3.2p1: ensure that # operators are followed by macro
// parameters in function-like macro expansions.
- while (Tok.isNot(tok::eom)) {
+ while (Tok.isNot(tok::eod)) {
LastTok = Tok;
if (Tok.isNot(tok::hash)) {
@@ -1478,7 +1490,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// the '#' because '#' is often a comment character. However, change
// the kind of the token to tok::unknown so that the preprocessor isn't
// confused.
- if (getLangOptions().AsmPreprocessor && Tok.isNot(tok::eom)) {
+ if (getLangOptions().AsmPreprocessor && Tok.isNot(tok::eod)) {
LastTok.setKind(tok::unknown);
} else {
Diag(Tok, diag::err_pp_stringize_not_parameter);
@@ -1504,7 +1516,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Disable __VA_ARGS__ again.
Ident__VA_ARGS__->setIsPoisoned(true);
- // Check that there is no paste (##) operator at the begining or end of the
+ // Check that there is no paste (##) operator at the beginning or end of the
// replacement list.
unsigned NumTokens = MI->getNumTokens();
if (NumTokens != 0) {
@@ -1573,7 +1585,7 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
ReadMacroName(MacroNameTok, 2);
// Error reading macro name? If so, diagnostic already issued.
- if (MacroNameTok.is(tok::eom))
+ if (MacroNameTok.is(tok::eod))
return;
// Check to see if this is the last token on the #undef line.
@@ -1619,7 +1631,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
ReadMacroName(MacroNameTok);
// Error reading macro name? If so, diagnostic already issued.
- if (MacroNameTok.is(tok::eom)) {
+ if (MacroNameTok.is(tok::eod)) {
// Skip code until we get to #endif. This helps with recovery by not
// emitting an error when the #endif is reached.
SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 1451c5a1ef5f..8fcfc70a7c67 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -180,7 +180,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
default: // Non-value token.
PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr);
return true;
- case tok::eom:
+ case tok::eod:
case tok::r_paren:
// If there is no expression, report and exit.
PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr);
@@ -372,7 +372,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
/// token. This returns:
/// ~0 - Invalid token.
/// 14 -> 3 - various operators.
-/// 0 - 'eom' or ')'
+/// 0 - 'eod' or ')'
static unsigned getPrecedence(tok::TokenKind Kind) {
switch (Kind) {
default: return ~0U;
@@ -397,8 +397,8 @@ static unsigned getPrecedence(tok::TokenKind Kind) {
case tok::question: return 4;
case tok::comma: return 3;
case tok::colon: return 2;
- case tok::r_paren: return 0; // Lowest priority, end of expr.
- case tok::eom: return 0; // Lowest priority, end of macro.
+ case tok::r_paren: return 0;// Lowest priority, end of expr.
+ case tok::eod: return 0;// Lowest priority, end of directive.
}
}
@@ -713,7 +713,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
DefinedTracker DT;
if (EvaluateValue(ResVal, Tok, DT, true, *this)) {
// Parse error, skip the rest of the macro line.
- if (Tok.isNot(tok::eom))
+ if (Tok.isNot(tok::eod))
DiscardUntilEndOfDirective();
// Restore 'DisableMacroExpansion'.
@@ -724,7 +724,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// If we are at the end of the expression after just parsing a value, there
// must be no (unparenthesized) binary operators involved, so we can exit
// directly.
- if (Tok.is(tok::eom)) {
+ if (Tok.is(tok::eod)) {
// If the expression we parsed was of the form !defined(macro), return the
// macro in IfNDefMacro.
if (DT.State == DefinedTracker::NotDefinedMacro)
@@ -740,7 +740,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question),
Tok, true, *this)) {
// Parse error, skip the rest of the macro line.
- if (Tok.isNot(tok::eom))
+ if (Tok.isNot(tok::eod))
DiscardUntilEndOfDirective();
// Restore 'DisableMacroExpansion'.
@@ -748,9 +748,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
return false;
}
- // If we aren't at the tok::eom token, something bad happened, like an extra
+ // If we aren't at the tok::eod token, something bad happened, like an extra
// ')' token.
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
Diag(Tok, diag::err_pp_expected_eol);
DiscardUntilEndOfDirective();
}
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index eef42b69d87f..bf0a7fbfef18 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -301,7 +301,7 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
// We handle this by scanning for the closest real lexer, switching it to
// raw mode and preprocessor mode. This will cause it to return \n as an
- // explicit EOM token.
+ // explicit EOD token.
PreprocessorLexer *FoundLexer = 0;
bool LexerWasInPPMode = false;
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
@@ -309,11 +309,11 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
if (ISI.ThePPLexer == 0) continue; // Scan for a real lexer.
// Once we find a real lexer, mark it as raw mode (disabling macro
- // expansions) and preprocessor mode (return EOM). We know that the lexer
+ // expansions) and preprocessor mode (return EOD). We know that the lexer
// was *not* in raw mode before, because the macro that the comment came
// from was expanded. However, it could have already been in preprocessor
// mode (#if COMMENT) in which case we have to return it to that mode and
- // return EOM.
+ // return EOD.
FoundLexer = ISI.ThePPLexer;
FoundLexer->LexingRawMode = true;
LexerWasInPPMode = FoundLexer->ParsingPreprocessorDirective;
@@ -326,22 +326,22 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
// the next token.
if (!HandleEndOfTokenLexer(Tok)) Lex(Tok);
- // Discarding comments as long as we don't have EOF or EOM. This 'comments
+ // Discarding comments as long as we don't have EOF or EOD. This 'comments
// out' the rest of the line, including any tokens that came from other macros
// that were active, as in:
// #define submacro a COMMENT b
// submacro c
// which should lex to 'a' only: 'b' and 'c' should be removed.
- while (Tok.isNot(tok::eom) && Tok.isNot(tok::eof))
+ while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof))
Lex(Tok);
- // If we got an eom token, then we successfully found the end of the line.
- if (Tok.is(tok::eom)) {
+ // If we got an eod token, then we successfully found the end of the line.
+ if (Tok.is(tok::eod)) {
assert(FoundLexer && "Can't get end of line without an active lexer");
// Restore the lexer back to normal mode instead of raw mode.
FoundLexer->LexingRawMode = false;
- // If the lexer was already in preprocessor mode, just return the EOM token
+ // If the lexer was already in preprocessor mode, just return the EOD token
// to finish the preprocessor line.
if (LexerWasInPPMode) return;
@@ -352,7 +352,7 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
// If we got an EOF token, then we reached the end of the token stream but
// didn't find an explicit \n. This can only happen if there was no lexer
- // active (an active lexer would return EOM at EOF if there was no \n in
+ // active (an active lexer would return EOD at EOF if there was no \n in
// preprocessor directive mode), so just return EOF as our token.
- assert(!FoundLexer && "Lexer should return EOM before EOF in PP mode");
+ assert(!FoundLexer && "Lexer should return EOD before EOF in PP mode");
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index ba9261491030..d6e0d3a1c08b 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -176,8 +176,6 @@ bool Preprocessor::isNextPPTokenLParen() {
/// expanded as a macro, handle it and return the next token as 'Identifier'.
bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
MacroInfo *MI) {
- if (Callbacks) Callbacks->MacroExpands(Identifier, MI);
-
// If this is a macro expansion in the "#if !defined(x)" line for the file,
// then the macro could expand to different things in other contexts, we need
// to disable the optimization in this case.
@@ -185,6 +183,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// If this is a builtin macro, like __LINE__ or _Pragma, handle it specially.
if (MI->isBuiltinMacro()) {
+ if (Callbacks) Callbacks->MacroExpands(Identifier, MI);
ExpandBuiltinMacro(Identifier);
return false;
}
@@ -225,8 +224,13 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// Notice that this macro has been used.
markMacroAsUsed(MI);
+ if (Callbacks) Callbacks->MacroExpands(Identifier, MI);
+
// If we started lexing a macro, enter the macro expansion body.
+ // Remember where the token is instantiated.
+ SourceLocation InstantiateLoc = Identifier.getLocation();
+
// If this macro expands to no tokens, don't bother to push it onto the
// expansion stack, only to take it right back off.
if (MI->getNumTokens() == 0) {
@@ -249,6 +253,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace);
}
Identifier.setFlag(Token::LeadingEmptyMacro);
+ LastEmptyMacroInstantiationLoc = InstantiateLoc;
++NumFastMacroExpanded;
return false;
@@ -267,9 +272,6 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
bool isAtStartOfLine = Identifier.isAtStartOfLine();
bool hasLeadingSpace = Identifier.hasLeadingSpace();
- // Remember where the token is instantiated.
- SourceLocation InstantiateLoc = Identifier.getLocation();
-
// Replace the result token.
Identifier = MI->getReplacementToken(0);
@@ -355,9 +357,9 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
LexUnexpandedToken(Tok);
}
- if (Tok.is(tok::eof) || Tok.is(tok::eom)) { // "#if f(<eof>" & "#if f(\n"
+ if (Tok.is(tok::eof) || Tok.is(tok::eod)) { // "#if f(<eof>" & "#if f(\n"
Diag(MacroName, diag::err_unterm_macro_invoc);
- // Do not lose the EOF/EOM. Return it to the client.
+ // Do not lose the EOF/EOD. Return it to the client.
MacroName = Tok;
return 0;
} else if (Tok.is(tok::r_paren)) {
@@ -410,9 +412,9 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
return 0;
}
- // Empty arguments are standard in C99 and supported as an extension in
+ // Empty arguments are standard in C99 and C++0x, and are supported as an extension in
// other modes.
- if (ArgTokens.size() == ArgTokenStart && !Features.C99)
+ if (ArgTokens.size() == ArgTokenStart && !Features.C99 && !Features.CPlusPlus0x)
Diag(Tok, diag::ext_empty_fnmacro_arg);
// Add a marker EOF token to the end of the token list for this argument.
@@ -530,6 +532,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
return llvm::StringSwitch<bool>(II->getName())
.Case("attribute_analyzer_noreturn", true)
+ .Case("attribute_availability", true)
.Case("attribute_cf_returns_not_retained", true)
.Case("attribute_cf_returns_retained", true)
.Case("attribute_deprecated_with_message", true)
@@ -540,12 +543,14 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("attribute_ns_consumed", true)
.Case("attribute_cf_consumed", true)
.Case("attribute_objc_ivar_unused", true)
+ .Case("attribute_objc_method_family", true)
.Case("attribute_overloadable", true)
.Case("attribute_unavailable_with_message", true)
.Case("blocks", LangOpts.Blocks)
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
+ .Case("generic_selections", true)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
@@ -556,10 +561,14 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
.Case("cxx_decltype", LangOpts.CPlusPlus0x)
.Case("cxx_default_function_template_args", LangOpts.CPlusPlus0x)
+ .Case("cxx_delegating_constructors", LangOpts.CPlusPlus0x)
.Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
//.Case("cxx_lambdas", false)
+ .Case("cxx_noexcept", LangOpts.CPlusPlus0x)
//.Case("cxx_nullptr", false)
+ .Case("cxx_override_control", LangOpts.CPlusPlus0x)
+ .Case("cxx_range_for", LangOpts.CPlusPlus0x)
.Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x)
.Case("cxx_rvalue_references", LangOpts.CPlusPlus0x)
.Case("cxx_strong_enums", LangOpts.CPlusPlus0x)
@@ -581,10 +590,11 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_convertible_to", LangOpts.CPlusPlus)
.Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
+ .Case("is_literal", LangOpts.CPlusPlus)
.Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
+ .Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_union", LangOpts.CPlusPlus)
- .Case("is_literal", LangOpts.CPlusPlus)
.Case("tls", PP.getTargetInfo().isTLSSupported())
.Default(false);
}
@@ -626,8 +636,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
SourceLocation EndLoc;
switch (Tok.getKind()) {
- case tok::eom:
- // If the token kind is EOM, the error has already been diagnosed.
+ case tok::eod:
+ // If the token kind is EOD, the error has already been diagnosed.
return false;
case tok::angle_string_literal:
@@ -644,7 +654,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// case, glue the tokens together into FilenameBuffer and interpret those.
FilenameBuffer.push_back('<');
if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc))
- return false; // Found <eom> but no ">"? Diagnostic already emitted.
+ return false; // Found <eod> but no ">"? Diagnostic already emitted.
Filename = FilenameBuffer.str();
break;
default:
@@ -660,7 +670,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = PP.LookupFile(Filename, isAngled, LookupFrom, CurDir);
+ const FileEntry *File =
+ PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL);
// Get the result value. Result = true means the file exists.
bool Result = File != 0;
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index 975753bc23bc..e5ef0fdf20eb 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -125,7 +125,7 @@ LexNextToken:
return PP->Lex(Tok);
}
- if (TKind == tok::eom) {
+ if (TKind == tok::eod) {
assert(ParsingPreprocessorDirective);
ParsingPreprocessorDirective = false;
return;
@@ -527,7 +527,7 @@ PTHManager *PTHManager::Create(const std::string &file, Diagnostic &Diags) {
// Get the number of IdentifierInfos and pre-allocate the identifier cache.
uint32_t NumIds = ReadLE32(IData);
- // Pre-allocate the peristent ID -> IdentifierInfo* cache. We use calloc()
+ // Pre-allocate the persistent ID -> IdentifierInfo* cache. We use calloc()
// so that we in the best case only zero out memory once when the OS returns
// us new pages.
IdentifierInfo** PerIDCache = 0;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 80d3bb1d2790..0c180918dc26 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -229,8 +229,8 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
PragmaToks.front().setFlag(Token::LeadingSpace);
- // Replace the ')' with an EOM to mark the end of the pragma.
- PragmaToks.back().setKind(tok::eom);
+ // Replace the ')' with an EOD to mark the end of the pragma.
+ PragmaToks.back().setKind(tok::eod);
Token *TokArray = new Token[PragmaToks.size()];
std::copy(PragmaToks.begin(), PragmaToks.end(), TokArray);
@@ -283,7 +283,7 @@ void Preprocessor::HandlePragmaPoison(Token &PoisonTok) {
if (CurPPLexer) CurPPLexer->LexingRawMode = false;
// If we reached the end of line, we're done.
- if (Tok.is(tok::eom)) return;
+ if (Tok.is(tok::eod)) return;
// Can only poison identifiers.
if (Tok.isNot(tok::raw_identifier)) {
@@ -348,8 +348,8 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
Token FilenameTok;
CurPPLexer->LexIncludeFilename(FilenameTok);
- // If the token kind is EOM, the error has already been diagnosed.
- if (FilenameTok.is(tok::eom))
+ // If the token kind is EOD, the error has already been diagnosed.
+ if (FilenameTok.is(tok::eod))
return;
// Reserve a buffer to get the spelling.
@@ -368,7 +368,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir);
+ const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL);
if (File == 0) {
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
@@ -381,7 +381,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Lex tokens at the end of the message and include them in the message.
std::string Message;
Lex(DependencyTok);
- while (DependencyTok.isNot(tok::eom)) {
+ while (DependencyTok.isNot(tok::eod)) {
Message += getSpelling(DependencyTok) + " ";
Lex(DependencyTok);
}
@@ -470,7 +470,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
}
Lex(Tok); // eat the r_paren.
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
return;
}
@@ -541,7 +541,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
Lex(Tok); // eat the r_paren.
}
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
Diag(Tok.getLocation(), diag::err_pragma_message_malformed);
return;
}
@@ -737,10 +737,10 @@ bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) {
return true;
}
- // Verify that this is followed by EOM.
+ // Verify that this is followed by EOD.
LexUnexpandedToken(Tok);
- if (Tok.isNot(tok::eom))
- Diag(Tok, diag::ext_pragma_syntax_eom);
+ if (Tok.isNot(tok::eod))
+ Diag(Tok, diag::ext_pragma_syntax_eod);
return false;
}
@@ -883,7 +883,7 @@ public:
PP.LexUnexpandedToken(Tok);
}
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
return;
}
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 3a43ac11e4e0..9555611dc59d 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -146,12 +146,15 @@ void PreprocessingRecord::MacroUndefined(const Token &Id,
MacroDefinitions.erase(Pos);
}
-void PreprocessingRecord::InclusionDirective(SourceLocation HashLoc,
- const clang::Token &IncludeTok,
- llvm::StringRef FileName,
- bool IsAngled,
- const FileEntry *File,
- clang::SourceLocation EndLoc) {
+void PreprocessingRecord::InclusionDirective(
+ SourceLocation HashLoc,
+ const clang::Token &IncludeTok,
+ llvm::StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ clang::SourceLocation EndLoc,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath) {
InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 6fe414b66414..31fd667a651d 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -89,6 +89,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
// "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
// This gets unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
+ SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
// Initialize the pragma handlers.
PragmaHandlers = new PragmaNamespace(llvm::StringRef());
@@ -96,6 +97,23 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
// Initialize builtin macros like __LINE__ and friends.
RegisterBuiltinMacros();
+
+ if(Features.Borland) {
+ Ident__exception_info = getIdentifierInfo("_exception_info");
+ Ident___exception_info = getIdentifierInfo("__exception_info");
+ Ident_GetExceptionInfo = getIdentifierInfo("GetExceptionInformation");
+ Ident__exception_code = getIdentifierInfo("_exception_code");
+ Ident___exception_code = getIdentifierInfo("__exception_code");
+ Ident_GetExceptionCode = getIdentifierInfo("GetExceptionCode");
+ Ident__abnormal_termination = getIdentifierInfo("_abnormal_termination");
+ Ident___abnormal_termination = getIdentifierInfo("__abnormal_termination");
+ Ident_AbnormalTermination = getIdentifierInfo("AbnormalTermination");
+ } else {
+ Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0;
+ Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0;
+ Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0;
+ }
+
}
Preprocessor::~Preprocessor() {
@@ -278,7 +296,6 @@ void Preprocessor::CodeCompleteNaturalLanguage() {
CodeComplete->CodeCompleteNaturalLanguage();
}
-
/// getSpelling - This method is used to get the spelling of a token into a
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
@@ -400,6 +417,34 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
return II;
}
+void Preprocessor::SetPoisonReason(IdentifierInfo *II, unsigned DiagID) {
+ PoisonReasons[II] = DiagID;
+}
+
+void Preprocessor::PoisonSEHIdentifiers(bool Poison) {
+ assert(Ident__exception_code && Ident__exception_info);
+ assert(Ident___exception_code && Ident___exception_info);
+ Ident__exception_code->setIsPoisoned(Poison);
+ Ident___exception_code->setIsPoisoned(Poison);
+ Ident_GetExceptionCode->setIsPoisoned(Poison);
+ Ident__exception_info->setIsPoisoned(Poison);
+ Ident___exception_info->setIsPoisoned(Poison);
+ Ident_GetExceptionInfo->setIsPoisoned(Poison);
+ Ident__abnormal_termination->setIsPoisoned(Poison);
+ Ident___abnormal_termination->setIsPoisoned(Poison);
+ Ident_AbnormalTermination->setIsPoisoned(Poison);
+}
+
+void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) {
+ assert(Identifier.getIdentifierInfo() &&
+ "Can't handle identifiers without identifier info!");
+ llvm::DenseMap<IdentifierInfo*,unsigned>::const_iterator it =
+ PoisonReasons.find(Identifier.getIdentifierInfo());
+ if(it == PoisonReasons.end())
+ Diag(Identifier, diag::err_pp_used_poisoned_id);
+ else
+ Diag(Identifier,it->second) << Identifier.getIdentifierInfo();
+}
/// HandleIdentifier - This callback is invoked when the lexer reads an
/// identifier. This callback looks up the identifier in the map and/or
@@ -418,10 +463,7 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
// If this identifier was poisoned, and if it was not produced from a macro
// expansion, emit an error.
if (II.isPoisoned() && CurPPLexer) {
- if (&II != Ident__VA_ARGS__) // We warn about __VA_ARGS__ with poisoning.
- Diag(Identifier, diag::err_pp_used_poisoned_id);
- else
- Diag(Identifier, diag::ext_pp_bad_vaargs_use);
+ HandlePoisonedIdentifier(Identifier);
}
// If this is a macro to be expanded, do it.
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
index e005c494763c..808a81bd5e87 100644
--- a/lib/Lex/PreprocessorLexer.cpp
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -34,7 +34,7 @@ void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) {
ParsingFilename = false;
// No filename?
- if (FilenameTok.is(tok::eom))
+ if (FilenameTok.is(tok::eod))
PP->Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
}
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index caa44bf4a146..65aff0d1d037 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -367,11 +367,7 @@ void TokenLexer::Lex(Token &Tok) {
// won't be handled by Preprocessor::HandleIdentifier because this is coming
// from a macro expansion.
if (II->isPoisoned() && TokenIsFromPaste) {
- // We warn about __VA_ARGS__ with poisoning.
- if (II->isStr("__VA_ARGS__"))
- PP.Diag(Tok, diag::ext_pp_bad_vaargs_use);
- else
- PP.Diag(Tok, diag::err_pp_used_poisoned_id);
+ PP.HandlePoisonedIdentifier(Tok);
}
if (!DisableMacroExpansion && II->isHandleIdentifierCase())
@@ -546,7 +542,7 @@ unsigned TokenLexer::isNextTokenLParen() const {
/// isParsingPreprocessorDirective - Return true if we are in the middle of a
/// preprocessor directive.
bool TokenLexer::isParsingPreprocessorDirective() const {
- return Tokens[NumTokens-1].is(tok::eom) && !isAtEnd();
+ return Tokens[NumTokens-1].is(tok::eod) && !isAtEnd();
}
/// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes
diff --git a/lib/Makefile b/lib/Makefile
index bf357fc7d569..eda7017bb8bf 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,7 +9,8 @@
CLANG_LEVEL := ..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
- StaticAnalyzer Rewrite Serialization Frontend FrontendTool Index Driver
+ StaticAnalyzer Rewrite Serialization Frontend FrontendTool \
+ Index Driver Tooling
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index edb1675b99e5..21917b23ffb6 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -21,6 +21,8 @@
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/Parser.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdio>
using namespace clang;
@@ -37,8 +39,15 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
ASTContext &Ctx, bool PrintStats,
bool CompleteTranslationUnit,
CodeCompleteConsumer *CompletionConsumer) {
- Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer);
- ParseAST(S, PrintStats);
+
+ llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
+ CompleteTranslationUnit,
+ CompletionConsumer));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleaupSema(S.get());
+
+ ParseAST(*S.get(), PrintStats);
}
void clang::ParseAST(Sema &S, bool PrintStats) {
@@ -50,7 +59,15 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
ASTConsumer *Consumer = &S.getASTConsumer();
- Parser P(S.getPreprocessor(), S);
+ llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S));
+ Parser &P = *ParseOP.get();
+
+ PrettyStackTraceParserEntry CrashInfo(P);
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<Parser>
+ CleaupParser(ParseOP.get());
+
S.getPreprocessor().EnterMainSourceFile();
P.Initialize();
S.Initialize();
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 399473840a94..87e2f343748e 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -15,6 +15,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
+#include "clang/AST/DeclTemplate.h"
using namespace clang;
/// ParseCXXInlineMethodDef - We parsed and verified that the specified
@@ -37,13 +38,6 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true,
move(TemplateParams));
else { // FIXME: pass template information through
- if (VS.isOverrideSpecified())
- Diag(VS.getOverrideLoc(), diag::ext_override_inline) << "override";
- if (VS.isFinalSpecified())
- Diag(VS.getFinalLoc(), diag::ext_override_inline) << "final";
- if (VS.isNewSpecified())
- Diag(VS.getNewLoc(), diag::ext_override_inline) << "new";
-
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
move(TemplateParams), 0,
VS, 0, /*IsDefinition*/true);
@@ -53,6 +47,37 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
D.complete(FnD);
+ // In delayed template parsing mode, if we are within a class template
+ // or if we are about to parse function member template then consume
+ // the tokens and store them for parsing at the end of the translation unit.
+ if (getLang().DelayedTemplateParsing &&
+ ((Actions.CurContext->isDependentContext() ||
+ TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) &&
+ !Actions.IsInsideALocalClassWithinATemplateFunction()) &&
+ !D.getDeclSpec().isFriendSpecified()) {
+
+ if (FnD) {
+ LateParsedTemplatedFunction *LPT =
+ new LateParsedTemplatedFunction(this, FnD);
+
+ FunctionDecl *FD = 0;
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD))
+ FD = FunTmpl->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(FnD);
+ Actions.CheckForFunctionRedefinition(FD);
+
+ LateParsedTemplateMap[FD] = LPT;
+ Actions.MarkAsLateParsedTemplate(FD);
+ LexTemplateFunctionForLateParsing(LPT->Toks);
+ } else {
+ CachedTokens Toks;
+ LexTemplateFunctionForLateParsing(Toks);
+ }
+
+ return FnD;
+ }
+
// Consume the tokens and store them for later parsing.
LexedMethod* LM = new LexedMethod(this, FnD);
@@ -94,6 +119,14 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
}
}
+
+ if (!FnD) {
+ // If semantic analysis could not build a function declaration,
+ // just throw away the late-parsed declaration.
+ delete getCurrentClass().LateParsedDeclarations.back();
+ getCurrentClass().LateParsedDeclarations.pop_back();
+ }
+
return FnD;
}
@@ -261,7 +294,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D);
if (Tok.is(tok::kw_try)) {
- ParseFunctionTryBlock(LM.D);
+ ParseFunctionTryBlock(LM.D, FnScope);
assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
Tok.getLocation()) &&
"ParseFunctionTryBlock went over the cached tokens!");
@@ -276,13 +309,14 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
// Error recovery.
if (!Tok.is(tok::l_brace)) {
+ FnScope.Exit();
Actions.ActOnFinishFunctionBody(LM.D, 0);
return;
}
} else
Actions.ActOnDefaultCtorInitializers(LM.D);
- ParseFunctionStatementBody(LM.D);
+ ParseFunctionStatementBody(LM.D, FnScope);
if (Tok.getLocation() != origLoc) {
// Due to parsing error, we either went over the cached tokens or
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 077edd700ad6..a20e90bd0ea3 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -13,6 +13,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Basic/OpenCL.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
@@ -32,7 +33,7 @@ using namespace clang;
TypeResult Parser::ParseTypeName(SourceRange *Range,
Declarator::TheContext Context) {
// Parse the common declaration-specifiers piece.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseSpecifierQualifierList(DS);
// Parse the abstract-declarator, if present.
@@ -111,8 +112,11 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
+ // Availability attributes have their own grammar.
+ if (AttrName->isStr("availability"))
+ ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc);
// check if we have a "parameterized" attribute
- if (Tok.is(tok::l_paren)) {
+ else if (Tok.is(tok::l_paren)) {
ConsumeParen(); // ignore the left paren loc for now
if (Tok.is(tok::identifier)) {
@@ -122,8 +126,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
if (Tok.is(tok::r_paren)) {
// __attribute__(( mode(byte) ))
ConsumeParen(); // ignore the right paren loc for now
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc,
- ParmName, ParmLoc, 0, 0));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ ParmName, ParmLoc, 0, 0);
} else if (Tok.is(tok::comma)) {
ConsumeToken();
// __attribute__(( format(printf, 1, 2) ))
@@ -146,9 +150,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0,
- AttrNameLoc, ParmName, ParmLoc,
- ArgExprs.take(), ArgExprs.size()));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
}
}
} else { // not an identifier
@@ -157,8 +160,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
// parse a possibly empty comma separated list of expressions
// __attribute__(( nonnull() ))
ConsumeParen(); // ignore the right paren loc for now
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0);
break;
case tok::kw_char:
case tok::kw_wchar_t:
@@ -168,6 +171,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
case tok::kw_short:
case tok::kw_int:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_float:
@@ -175,9 +179,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
case tok::kw_void:
case tok::kw_typeof: {
AttributeList *attr
- = AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0);
- attrs.add(attr);
+ = attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0);
if (attr->getKind() == AttributeList::AT_IBOutletCollection)
Diag(Tok, diag::err_iboutletcollection_builtintype);
// If it's a builtin type name, eat it and expect a rparen
@@ -209,16 +212,16 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
// Match the ')'.
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0,
- AttrNameLoc, 0, SourceLocation(),
- ArgExprs.take(), ArgExprs.size()));
+ attrs.addNew(AttrName, AttrNameLoc, 0,
+ AttrNameLoc, 0, SourceLocation(),
+ ArgExprs.take(), ArgExprs.size());
}
break;
}
}
} else {
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0);
}
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
@@ -260,14 +263,14 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) {
ExprResult ArgExpr(ParseAssignmentExpression());
if (!ArgExpr.isInvalid()) {
Expr *ExprList = ArgExpr.take();
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), &ExprList, 1, true));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
+ SourceLocation(), &ExprList, 1, true);
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
SkipUntil(tok::r_paren, false);
} else {
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0, true));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, true);
}
}
if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
@@ -286,8 +289,8 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64))
// FIXME: Support these properly!
continue;
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, true));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
+ SourceLocation(), 0, 0, true);
}
}
@@ -296,8 +299,8 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___pascal)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, true));
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
+ SourceLocation(), 0, 0, true);
}
}
@@ -305,12 +308,334 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) {
// Treat these like attributes
while (Tok.is(tok::kw___kernel)) {
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.add(AttrFactory.Create(PP.getIdentifierInfo("opencl_kernel_function"),
- AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, false));
+ attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"),
+ AttrNameLoc, 0, AttrNameLoc, 0,
+ SourceLocation(), 0, 0, false);
}
}
+void Parser::ParseOpenCLQualifiers(DeclSpec &DS) {
+ SourceLocation Loc = Tok.getLocation();
+ switch(Tok.getKind()) {
+ // OpenCL qualifiers:
+ case tok::kw___private:
+ case tok::kw_private:
+ DS.getAttributes().addNewInteger(
+ Actions.getASTContext(),
+ PP.getIdentifierInfo("address_space"), Loc, 0);
+ break;
+
+ case tok::kw___global:
+ DS.getAttributes().addNewInteger(
+ Actions.getASTContext(),
+ PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global);
+ break;
+
+ case tok::kw___local:
+ DS.getAttributes().addNewInteger(
+ Actions.getASTContext(),
+ PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local);
+ break;
+
+ case tok::kw___constant:
+ DS.getAttributes().addNewInteger(
+ Actions.getASTContext(),
+ PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant);
+ break;
+
+ case tok::kw___read_only:
+ DS.getAttributes().addNewInteger(
+ Actions.getASTContext(),
+ PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only);
+ break;
+
+ case tok::kw___write_only:
+ DS.getAttributes().addNewInteger(
+ Actions.getASTContext(),
+ PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only);
+ break;
+
+ case tok::kw___read_write:
+ DS.getAttributes().addNewInteger(
+ Actions.getASTContext(),
+ PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write);
+ break;
+ default: break;
+ }
+}
+
+/// \brief Parse a version number.
+///
+/// version:
+/// simple-integer
+/// simple-integer ',' simple-integer
+/// simple-integer ',' simple-integer ',' simple-integer
+VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
+ Range = Tok.getLocation();
+
+ if (!Tok.is(tok::numeric_constant)) {
+ Diag(Tok, diag::err_expected_version);
+ SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ return VersionTuple();
+ }
+
+ // Parse the major (and possibly minor and subminor) versions, which
+ // are stored in the numeric constant. We utilize a quirk of the
+ // lexer, which is that it handles something like 1.2.3 as a single
+ // numeric constant, rather than two separate tokens.
+ llvm::SmallString<512> Buffer;
+ Buffer.resize(Tok.getLength()+1);
+ const char *ThisTokBegin = &Buffer[0];
+
+ // Get the spelling of the token, which eliminates trigraphs, etc.
+ bool Invalid = false;
+ unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid);
+ if (Invalid)
+ return VersionTuple();
+
+ // Parse the major version.
+ unsigned AfterMajor = 0;
+ unsigned Major = 0;
+ while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) {
+ Major = Major * 10 + ThisTokBegin[AfterMajor] - '0';
+ ++AfterMajor;
+ }
+
+ if (AfterMajor == 0) {
+ Diag(Tok, diag::err_expected_version);
+ SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ return VersionTuple();
+ }
+
+ if (AfterMajor == ActualLength) {
+ ConsumeToken();
+
+ // We only had a single version component.
+ if (Major == 0) {
+ Diag(Tok, diag::err_zero_version);
+ return VersionTuple();
+ }
+
+ return VersionTuple(Major);
+ }
+
+ if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) {
+ Diag(Tok, diag::err_expected_version);
+ SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ return VersionTuple();
+ }
+
+ // Parse the minor version.
+ unsigned AfterMinor = AfterMajor + 1;
+ unsigned Minor = 0;
+ while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) {
+ Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0';
+ ++AfterMinor;
+ }
+
+ if (AfterMinor == ActualLength) {
+ ConsumeToken();
+
+ // We had major.minor.
+ if (Major == 0 && Minor == 0) {
+ Diag(Tok, diag::err_zero_version);
+ return VersionTuple();
+ }
+
+ return VersionTuple(Major, Minor);
+ }
+
+ // If what follows is not a '.', we have a problem.
+ if (ThisTokBegin[AfterMinor] != '.') {
+ Diag(Tok, diag::err_expected_version);
+ SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ return VersionTuple();
+ }
+
+ // Parse the subminor version.
+ unsigned AfterSubminor = AfterMinor + 1;
+ unsigned Subminor = 0;
+ while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) {
+ Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0';
+ ++AfterSubminor;
+ }
+
+ if (AfterSubminor != ActualLength) {
+ Diag(Tok, diag::err_expected_version);
+ SkipUntil(tok::comma, tok::r_paren, true, true, true);
+ return VersionTuple();
+ }
+ ConsumeToken();
+ return VersionTuple(Major, Minor, Subminor);
+}
+
+/// \brief Parse the contents of the "availability" attribute.
+///
+/// availability-attribute:
+/// 'availability' '(' platform ',' version-arg-list ')'
+///
+/// platform:
+/// identifier
+///
+/// version-arg-list:
+/// version-arg
+/// version-arg ',' version-arg-list
+///
+/// version-arg:
+/// 'introduced' '=' version
+/// 'deprecated' '=' version
+/// 'removed' = version
+/// 'unavailable'
+void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
+ SourceLocation AvailabilityLoc,
+ ParsedAttributes &attrs,
+ SourceLocation *endLoc) {
+ SourceLocation PlatformLoc;
+ IdentifierInfo *Platform = 0;
+
+ enum { Introduced, Deprecated, Obsoleted, Unknown };
+ AvailabilityChange Changes[Unknown];
+
+ // Opening '('.
+ SourceLocation LParenLoc;
+ if (!Tok.is(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen);
+ return;
+ }
+ LParenLoc = ConsumeParen();
+
+ // Parse the platform name,
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_availability_expected_platform);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+ Platform = Tok.getIdentifierInfo();
+ PlatformLoc = ConsumeToken();
+
+ // Parse the ',' following the platform name.
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren))
+ return;
+
+ // If we haven't grabbed the pointers for the identifiers
+ // "introduced", "deprecated", and "obsoleted", do so now.
+ if (!Ident_introduced) {
+ Ident_introduced = PP.getIdentifierInfo("introduced");
+ Ident_deprecated = PP.getIdentifierInfo("deprecated");
+ Ident_obsoleted = PP.getIdentifierInfo("obsoleted");
+ Ident_unavailable = PP.getIdentifierInfo("unavailable");
+ }
+
+ // Parse the set of introductions/deprecations/removals.
+ SourceLocation UnavailableLoc;
+ do {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_availability_expected_change);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+ IdentifierInfo *Keyword = Tok.getIdentifierInfo();
+ SourceLocation KeywordLoc = ConsumeToken();
+
+ if (Keyword == Ident_unavailable) {
+ if (UnavailableLoc.isValid()) {
+ Diag(KeywordLoc, diag::err_availability_redundant)
+ << Keyword << SourceRange(UnavailableLoc);
+ }
+ UnavailableLoc = KeywordLoc;
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ continue;
+ }
+
+ if (Tok.isNot(tok::equal)) {
+ Diag(Tok, diag::err_expected_equal_after)
+ << Keyword;
+ SkipUntil(tok::r_paren);
+ return;
+ }
+ ConsumeToken();
+
+ SourceRange VersionRange;
+ VersionTuple Version = ParseVersionTuple(VersionRange);
+
+ if (Version.empty()) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ unsigned Index;
+ if (Keyword == Ident_introduced)
+ Index = Introduced;
+ else if (Keyword == Ident_deprecated)
+ Index = Deprecated;
+ else if (Keyword == Ident_obsoleted)
+ Index = Obsoleted;
+ else
+ Index = Unknown;
+
+ if (Index < Unknown) {
+ if (!Changes[Index].KeywordLoc.isInvalid()) {
+ Diag(KeywordLoc, diag::err_availability_redundant)
+ << Keyword
+ << SourceRange(Changes[Index].KeywordLoc,
+ Changes[Index].VersionRange.getEnd());
+ }
+
+ Changes[Index].KeywordLoc = KeywordLoc;
+ Changes[Index].Version = Version;
+ Changes[Index].VersionRange = VersionRange;
+ } else {
+ Diag(KeywordLoc, diag::err_availability_unknown_change)
+ << Keyword << VersionRange;
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ } while (true);
+
+ // Closing ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ if (RParenLoc.isInvalid())
+ return;
+
+ if (endLoc)
+ *endLoc = RParenLoc;
+
+ // The 'unavailable' availability cannot be combined with any other
+ // availability changes. Make sure that hasn't happened.
+ if (UnavailableLoc.isValid()) {
+ bool Complained = false;
+ for (unsigned Index = Introduced; Index != Unknown; ++Index) {
+ if (Changes[Index].KeywordLoc.isValid()) {
+ if (!Complained) {
+ Diag(UnavailableLoc, diag::warn_availability_and_unavailable)
+ << SourceRange(Changes[Index].KeywordLoc,
+ Changes[Index].VersionRange.getEnd());
+ Complained = true;
+ }
+
+ // Clear out the availability.
+ Changes[Index] = AvailabilityChange();
+ }
+ }
+ }
+
+ // Record this attribute
+ attrs.addNew(&Availability, AvailabilityLoc,
+ 0, SourceLocation(),
+ Platform, PlatformLoc,
+ Changes[Introduced],
+ Changes[Deprecated],
+ Changes[Obsoleted],
+ UnavailableLoc, false, false);
+}
+
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
<< attrs.Range;
@@ -329,7 +654,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
/// [C++] namespace-definition
/// [C++] using-directive
/// [C++] using-declaration
-/// [C++0x] static_assert-declaration
+/// [C++0x/C1X] static_assert-declaration
/// others... [FIXME]
///
Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
@@ -364,6 +689,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
DeclEnd, attrs);
break;
case tok::kw_static_assert:
+ case tok::kw__Static_assert:
ProhibitAttributes(attrs);
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break;
@@ -381,33 +707,42 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
///[C90/C++]init-declarator-list ';' [TODO]
/// [OMP] threadprivate-directive [TODO]
///
+/// for-range-declaration: [C++0x 6.5p1: stmt.ranged]
+/// attribute-specifier-seq[opt] type-specifier-seq declarator
+///
/// If RequireSemi is false, this does not check for a ';' at the end of the
/// declaration. If it is true, it checks for and eats it.
+///
+/// If FRI is non-null, we might be parsing a for-range-declaration instead
+/// of a simple-declaration. If we find that we are, we also parse the
+/// for-range-initializer, and place it here.
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
unsigned Context,
SourceLocation &DeclEnd,
ParsedAttributes &attrs,
- bool RequireSemi) {
+ bool RequireSemi,
+ ForRangeInit *FRI) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
DS.takeAttributesFrom(attrs);
+
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
getDeclSpecContextFromDeclaratorContext(Context));
StmtResult R = Actions.ActOnVlaStmt(DS);
if (R.isUsable())
Stmts.push_back(R.release());
-
+
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
if (RequireSemi) ConsumeToken();
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
- DS);
+ DS);
DS.complete(TheDecl);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
-
- return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd);
+
+ return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
}
/// ParseDeclGroup - Having concluded that this is either a function
@@ -416,7 +751,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
unsigned Context,
bool AllowFunctionDefinitions,
- SourceLocation *DeclEnd) {
+ SourceLocation *DeclEnd,
+ ForRangeInit *FRI) {
// Parse the first declarator.
ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context));
ParseDeclarator(D);
@@ -462,8 +798,24 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}
}
+ if (ParseAttributesAfterDeclarator(D))
+ return DeclGroupPtrTy();
+
+ // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we
+ // must parse and analyze the for-range-initializer before the declaration is
+ // analyzed.
+ if (FRI && Tok.is(tok::colon)) {
+ FRI->ColonLoc = ConsumeToken();
+ // FIXME: handle braced-init-list here.
+ FRI->RangeExpr = ParseExpression();
+ Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
+ Actions.ActOnCXXForRangeDecl(ThisDecl);
+ Actions.FinalizeDeclaration(ThisDecl);
+ return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1);
+ }
+
llvm::SmallVector<Decl *, 8> DeclsInGroup;
- Decl *FirstDecl = ParseDeclarationAfterDeclarator(D);
+ Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
D.complete(FirstDecl);
if (FirstDecl)
DeclsInGroup.push_back(FirstDecl);
@@ -517,6 +869,26 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DeclsInGroup.size());
}
+/// Parse an optional simple-asm-expr and attributes, and attach them to a
+/// declarator. Returns true on an error.
+bool Parser::ParseAttributesAfterDeclarator(Declarator &D) {
+ // If a simple-asm-expr is present, parse it.
+ if (Tok.is(tok::kw_asm)) {
+ SourceLocation Loc;
+ ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ if (AsmLabel.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return true;
+ }
+
+ D.setAsmLabel(AsmLabel.release());
+ D.SetRangeEnd(Loc);
+ }
+
+ MaybeParseGNUAttributes(D);
+ return false;
+}
+
/// \brief Parse 'declaration' after parsing 'declaration-specifiers
/// declarator'. This method parses the remainder of the declaration
/// (including any attributes or initializer, among other things) and
@@ -540,21 +912,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
///
Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
const ParsedTemplateInfo &TemplateInfo) {
- // If a simple-asm-expr is present, parse it.
- if (Tok.is(tok::kw_asm)) {
- SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
- if (AsmLabel.isInvalid()) {
- SkipUntil(tok::semi, true, true);
- return 0;
- }
-
- D.setAsmLabel(AsmLabel.release());
- D.SetRangeEnd(Loc);
- }
+ if (ParseAttributesAfterDeclarator(D))
+ return 0;
- MaybeParseGNUAttributes(D);
+ return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
+}
+Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
+ const ParsedTemplateInfo &TemplateInfo) {
// Inform the current actions module that we just parsed this declarator.
Decl *ThisDecl = 0;
switch (TemplateInfo.Kind) {
@@ -780,21 +1145,25 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
//
// C++ doesn't need this, and isTagName doesn't take SS.
if (SS == 0) {
- const char *TagName = 0;
+ const char *TagName = 0, *FixitTagName = 0;
tok::TokenKind TagKind = tok::unknown;
switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) {
default: break;
- case DeclSpec::TST_enum: TagName="enum" ;TagKind=tok::kw_enum ;break;
- case DeclSpec::TST_union: TagName="union" ;TagKind=tok::kw_union ;break;
- case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break;
- case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;break;
+ case DeclSpec::TST_enum:
+ TagName="enum" ; FixitTagName = "enum " ; TagKind=tok::kw_enum ;break;
+ case DeclSpec::TST_union:
+ 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_class:
+ TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break;
}
if (TagName) {
Diag(Loc, diag::err_use_of_tag_name_without_tag)
<< Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus
- << FixItHint::CreateInsertion(Tok.getLocation(),TagName);
+ << FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName);
// Parse this as a tag as if the missing tag were present.
if (TagKind == tok::kw_enum)
@@ -887,9 +1256,12 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
- DeclSpecContext DSContext) {
- DS.SetRangeStart(Tok.getLocation());
- DS.SetRangeEnd(Tok.getLocation());
+ DeclSpecContext DSContext) {
+ if (DS.getSourceRange().isInvalid()) {
+ DS.SetRangeStart(Tok.getLocation());
+ DS.SetRangeEnd(Tok.getLocation());
+ }
+
while (1) {
bool isInvalid = false;
const char *PrevSpec = 0;
@@ -1013,7 +1385,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
- AnnotateTemplateIdTokenAsType(&SS);
+ AnnotateTemplateIdTokenAsType();
continue;
}
@@ -1056,7 +1428,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
Next.getLocation(),
- getCurScope(), &SS);
+ getCurScope(), &SS,
+ false, false, ParsedType(),
+ /*NonTrivialSourceInfo=*/true);
// If the referenced identifier is not a type, then this declspec is
// erroneous: We already checked about that it has no type specifier, and
@@ -1105,6 +1479,24 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
+ case tok::kw___is_signed:
+ // GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang
+ // typically treats it as a trait. If we see __is_signed as it appears
+ // in libstdc++, e.g.,
+ //
+ // static const bool __is_signed;
+ //
+ // then treat __is_signed as an identifier rather than as a keyword.
+ if (DS.getTypeSpecType() == TST_bool &&
+ DS.getTypeQualifiers() == DeclSpec::TQ_const &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
+ Tok.setKind(tok::identifier);
+ }
+
+ // We're done with the declaration-specifiers.
+ goto DoneWithDeclSpec;
+
// typedef-name
case tok::identifier: {
// In C++, check to see if this is a scope specifier like foo::bar::, if
@@ -1247,7 +1639,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DiagID, getLang());
break;
case tok::kw_auto:
- if (getLang().CPlusPlus0x || getLang().ObjC2) {
+ if (getLang().CPlusPlus0x) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec,
DiagID, getLang());
@@ -1315,6 +1707,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
DiagID);
break;
+ case tok::kw___int64:
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
+ DiagID);
+ break;
case tok::kw_signed:
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec,
DiagID);
@@ -1370,6 +1766,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
PrevSpec = ""; // Not used by the diagnostic.
DiagID = diag::err_bool_redeclaration;
+ // For better error recovery.
+ Tok.setKind(tok::identifier);
isInvalid = true;
} else {
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec,
@@ -1394,6 +1792,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
break;
+ case tok::kw___unknown_anytype:
+ isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
+ PrevSpec, DiagID);
+ break;
// class-specifier:
case tok::kw_class:
@@ -1444,6 +1846,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParseDecltypeSpecifier(DS);
continue;
+ // OpenCL qualifiers:
+ case tok::kw_private:
+ if (!getLang().OpenCL)
+ goto DoneWithDeclSpec;
+ case tok::kw___private:
+ case tok::kw___global:
+ case tok::kw___local:
+ case tok::kw___constant:
+ case tok::kw___read_only:
+ case tok::kw___write_only:
+ case tok::kw___read_write:
+ ParseOpenCLQualifiers(DS);
+ break;
+
case tok::less:
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
@@ -1473,7 +1889,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
DS.SetRangeEnd(Tok.getLocation());
- ConsumeToken();
+ if (DiagID != diag::err_bool_redeclaration)
+ ConsumeToken();
}
}
@@ -1592,6 +2009,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
DiagID);
break;
+ case tok::kw___int64:
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
+ DiagID);
+ break;
case tok::kw_signed:
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
break;
@@ -1695,6 +2116,20 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
ParseDecltypeSpecifier(DS);
return true;
+ // OpenCL qualifiers:
+ case tok::kw_private:
+ if (!getLang().OpenCL)
+ return false;
+ case tok::kw___private:
+ case tok::kw___global:
+ case tok::kw___local:
+ case tok::kw___constant:
+ case tok::kw___read_only:
+ case tok::kw___write_only:
+ case tok::kw___read_write:
+ ParseOpenCLQualifiers(DS);
+ break;
+
// C++0x auto support.
case tok::kw_auto:
if (!getLang().CPlusPlus0x)
@@ -1856,7 +2291,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
// Parse all the comma separated declarators.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
if (!Tok.is(tok::at)) {
struct CFieldCallback : FieldCallback {
@@ -1917,7 +2352,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
// If attributes exist after struct contents, parse them.
MaybeParseGNUAttributes(attrs);
@@ -1967,7 +2402,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
// If attributes exist after tag, parse them.
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
CXXScopeSpec &SS = DS.getTypeSpecScope();
@@ -2121,7 +2556,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool Owned = false;
bool IsDependent = false;
- SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
const char *PrevSpec = 0;
unsigned DiagID;
Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK,
@@ -2148,8 +2582,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
- if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID,
- Type.get()))
+ if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc,
+ NameLoc.isValid() ? NameLoc : StartLoc,
+ PrevSpec, DiagID, Type.get()))
Diag(StartLoc, DiagID) << PrevSpec;
return;
@@ -2170,10 +2605,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.is(tok::l_brace))
ParseEnumBody(StartLoc, TagDecl);
- // FIXME: The DeclSpec should keep the locations of both the keyword
- // and the name (if there is one).
- if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID,
- TagDecl, Owned))
+ if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
+ NameLoc.isValid() ? NameLoc : StartLoc,
+ PrevSpec, DiagID, TagDecl, Owned))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -2208,7 +2642,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
SourceLocation IdentLoc = ConsumeToken();
// If attributes exist after the enumerator, parse them.
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
SourceLocation EqualLoc;
@@ -2252,7 +2686,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
// If attributes exist after the identifier list, parse them.
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
@@ -2268,10 +2702,22 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
bool Parser::isTypeQualifier() const {
switch (Tok.getKind()) {
default: return false;
+
+ // type-qualifier only in OpenCL
+ case tok::kw_private:
+ return getLang().OpenCL;
+
// type-qualifier
case tok::kw_const:
case tok::kw_volatile:
case tok::kw_restrict:
+ case tok::kw___private:
+ case tok::kw___local:
+ case tok::kw___global:
+ case tok::kw___constant:
+ case tok::kw___read_only:
+ case tok::kw___read_write:
+ case tok::kw___write_only:
return true;
}
}
@@ -2285,6 +2731,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
// type-specifiers
case tok::kw_short:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw__Complex:
@@ -2353,6 +2800,7 @@ bool Parser::isTypeSpecifierQualifier() {
// type-specifiers
case tok::kw_short:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw__Complex:
@@ -2399,7 +2847,19 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___w64:
case tok::kw___ptr64:
case tok::kw___pascal:
+
+ case tok::kw___private:
+ case tok::kw___local:
+ case tok::kw___global:
+ case tok::kw___constant:
+ case tok::kw___read_only:
+ case tok::kw___read_write:
+ case tok::kw___write_only:
+
return true;
+
+ case tok::kw_private:
+ return getLang().OpenCL;
}
}
@@ -2412,6 +2872,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
switch (Tok.getKind()) {
default: return false;
+ case tok::kw_private:
+ return getLang().OpenCL;
+
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
if (getLang().ObjC1 && NextToken().is(tok::period))
@@ -2461,6 +2924,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// type-specifiers
case tok::kw_short:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw__Complex:
@@ -2498,8 +2962,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_virtual:
case tok::kw_explicit:
- // typedef-name
- case tok::annot_typename:
+ // static_assert-declaration
+ case tok::kw__Static_assert:
// GNU typeof support.
case tok::kw_typeof:
@@ -2512,6 +2976,11 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::less:
return getLang().ObjC1;
+ // typedef-name
+ case tok::annot_typename:
+ return !DisambiguatingWithExpression ||
+ !isStartOfObjCClassMessageMissingOpenBracket();
+
case tok::kw___declspec:
case tok::kw___cdecl:
case tok::kw___stdcall:
@@ -2521,6 +2990,15 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw___ptr64:
case tok::kw___forceinline:
case tok::kw___pascal:
+
+ case tok::kw___private:
+ case tok::kw___local:
+ case tok::kw___global:
+ case tok::kw___constant:
+ case tok::kw___read_only:
+ case tok::kw___read_write:
+ case tok::kw___write_only:
+
return true;
}
}
@@ -2564,7 +3042,7 @@ bool Parser::isConstructorDeclarator() {
DeclScopeObj.EnterDeclaratorScope();
// Optionally skip Microsoft attributes.
- ParsedAttributes Attrs;
+ ParsedAttributes Attrs(AttrFactory);
MaybeParseMicrosoftAttributes(Attrs);
// Check whether the next token(s) are part of a declaration
@@ -2592,14 +3070,16 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
bool CXX0XAttributesAllowed) {
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
SourceLocation Loc = Tok.getLocation();
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
ParseCXX0XAttributes(attrs);
if (CXX0XAttributesAllowed)
DS.takeAttributesFrom(attrs);
else
Diag(Loc, diag::err_attributes_not_allowed);
}
-
+
+ SourceLocation EndLoc;
+
while (1) {
bool isInvalid = false;
const char *PrevSpec = 0;
@@ -2624,6 +3104,21 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
getLang());
break;
+
+ // OpenCL qualifiers:
+ case tok::kw_private:
+ if (!getLang().OpenCL)
+ goto DoneWithTypeQuals;
+ case tok::kw___private:
+ case tok::kw___global:
+ case tok::kw___local:
+ case tok::kw___constant:
+ case tok::kw___read_only:
+ case tok::kw___write_only:
+ case tok::kw___read_write:
+ ParseOpenCLQualifiers(DS);
+ break;
+
case tok::kw___w64:
case tok::kw___ptr64:
case tok::kw___cdecl:
@@ -2652,6 +3147,8 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
// If this is not a type-qualifier token, we're done reading type
// qualifiers. First verify that DeclSpec's are consistent.
DS.Finish(Diags, PP);
+ if (EndLoc.isValid())
+ DS.SetRangeEnd(EndLoc);
return;
}
@@ -2660,7 +3157,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
assert(PrevSpec && "Method did not return previous specifier!");
Diag(Tok, DiagID) << PrevSpec;
}
- ConsumeToken();
+ EndLoc = ConsumeToken();
}
}
@@ -2719,7 +3216,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
SourceLocation Loc = ConsumeToken();
D.SetRangeEnd(Loc);
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseTypeQualifierListOpt(DS);
D.ExtendWithDeclSpec(DS);
@@ -2729,7 +3226,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Sema will have to catch (syntactically invalid) pointers into global
// scope. It has to catch pointers into namespace scope anyway.
D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(),
- Loc, DS.takeAttributes()),
+ Loc),
+ DS.getAttributes(),
/* Don't replace range end. */SourceLocation());
return;
}
@@ -2753,7 +3251,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
if (Kind == tok::star || Kind == tok::caret) {
// Is a pointer.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseTypeQualifierListOpt(DS);
D.ExtendWithDeclSpec(DS);
@@ -2765,17 +3263,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
DS.getConstSpecLoc(),
DS.getVolatileSpecLoc(),
- DS.getRestrictSpecLoc(),
- DS.takeAttributes()),
+ DS.getRestrictSpecLoc()),
+ DS.getAttributes(),
SourceLocation());
else
// Remember that we parsed a Block type, and remember the type-quals.
D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
- Loc, DS.takeAttributes()),
+ Loc),
+ DS.getAttributes(),
SourceLocation());
} else {
// Is a reference
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
// Complain about rvalue references in C++03, but then go on and build
// the declarator.
@@ -2823,8 +3322,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Remember that we parsed a reference type. It doesn't have type-quals.
D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc,
- DS.takeAttributes(),
Kind == tok::amp),
+ DS.getAttributes(),
SourceLocation());
}
}
@@ -2989,7 +3488,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (!isCXXFunctionDeclarator(warnIfAmbiguous))
break;
}
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
ParseFunctionDeclarator(ConsumeParen(), D, attrs);
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
@@ -3026,7 +3525,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// In either case, we need to eat any attributes to be able to determine what
// sort of paren this is.
//
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
bool RequiresArg = false;
if (Tok.is(tok::kw___attribute)) {
ParseGNUAttributes(attrs);
@@ -3072,13 +3571,12 @@ void Parser::ParseParenDeclarator(Declarator &D) {
if (isGrouping) {
bool hadGroupingParens = D.hasGroupingParens();
D.setGroupingParens(true);
- if (!attrs.empty())
- D.addAttributes(attrs.getList(), SourceLocation());
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
// Match the ')'.
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, StartLoc);
- D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc), EndLoc);
+ D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc),
+ attrs, EndLoc);
D.setGroupingParens(hadGroupingParens);
return;
@@ -3125,6 +3623,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]",
/// C++0x "ref-qualifier[opt]" and "exception-specification[opt]".
///
+/// [C++0x] exception-specification:
+/// dynamic-exception-specification
+/// noexcept-specification
+///
void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
ParsedAttributes &attrs,
bool RequiresArg) {
@@ -3138,18 +3640,17 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
- SourceLocation RParenLoc = ConsumeParen(); // Eat the closing ')'.
- SourceLocation EndLoc = RParenLoc;
+ SourceLocation EndLoc = ConsumeParen(); // Eat the closing ')'.
// cv-qualifier-seq[opt].
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
SourceLocation RefQualifierLoc;
bool RefQualifierIsLValueRef = true;
- bool hasExceptionSpec = false;
- SourceLocation ThrowLoc;
- bool hasAnyExceptionSpec = false;
- llvm::SmallVector<ParsedType, 2> Exceptions;
- llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+ ExceptionSpecificationType ESpecType = EST_None;
+ SourceRange ESpecRange;
+ llvm::SmallVector<ParsedType, 2> DynamicExceptions;
+ llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
if (getLang().CPlusPlus) {
MaybeParseCXX0XAttributes(attrs);
@@ -3161,21 +3662,19 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::ext_ref_qualifier);
-
+
RefQualifierIsLValueRef = Tok.is(tok::amp);
RefQualifierLoc = ConsumeToken();
EndLoc = RefQualifierLoc;
}
-
+
// Parse exception-specification[opt].
- if (Tok.is(tok::kw_throw)) {
- hasExceptionSpec = true;
- ThrowLoc = Tok.getLocation();
- ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
- hasAnyExceptionSpec);
- assert(Exceptions.size() == ExceptionRanges.size() &&
- "Produced different number of exception types and ranges.");
- }
+ ESpecType = MaybeParseExceptionSpecification(ESpecRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr);
+ if (ESpecType != EST_None)
+ EndLoc = ESpecRange.getEnd();
// Parse trailing-return-type.
if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
@@ -3185,22 +3684,22 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Remember that we parsed a function type, and remember the attributes.
// int() -> no prototype, no '...'.
- D.AddTypeInfo(DeclaratorChunk::getFunction(attrs,
- /*prototype*/getLang().CPlusPlus,
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
/*variadic*/ false,
SourceLocation(),
/*arglist*/ 0, 0,
DS.getTypeQualifiers(),
RefQualifierIsLValueRef,
RefQualifierLoc,
- hasExceptionSpec, ThrowLoc,
- hasAnyExceptionSpec,
- Exceptions.data(),
- ExceptionRanges.data(),
- Exceptions.size(),
- LParenLoc, RParenLoc, D,
+ ESpecType, ESpecRange.getBegin(),
+ DynamicExceptions.data(),
+ DynamicExceptionRanges.data(),
+ DynamicExceptions.size(),
+ NoexceptExpr.isUsable() ?
+ NoexceptExpr.get() : 0,
+ LParenLoc, EndLoc, D,
TrailingReturnType),
- EndLoc);
+ attrs, EndLoc);
return;
}
@@ -3264,7 +3763,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Parse the declaration-specifiers.
// Just use the ParsingDeclaration "scope" of the declarator.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
// Skip any Microsoft attributes before a param.
if (getLang().Microsoft && Tok.is(tok::l_square))
@@ -3388,17 +3887,16 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
}
// If we have the closing ')', eat it.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- SourceLocation EndLoc = RParenLoc;
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
SourceLocation RefQualifierLoc;
bool RefQualifierIsLValueRef = true;
- bool hasExceptionSpec = false;
- SourceLocation ThrowLoc;
- bool hasAnyExceptionSpec = false;
- llvm::SmallVector<ParsedType, 2> Exceptions;
- llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+ ExceptionSpecificationType ESpecType = EST_None;
+ SourceRange ESpecRange;
+ llvm::SmallVector<ParsedType, 2> DynamicExceptions;
+ llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ ExprResult NoexceptExpr;
if (getLang().CPlusPlus) {
MaybeParseCXX0XAttributes(attrs);
@@ -3418,15 +3916,17 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
EndLoc = RefQualifierLoc;
}
+ // FIXME: We should leave the prototype scope before parsing the exception
+ // specification, and then reenter it when parsing the trailing return type.
+ // FIXMEFIXME: Why? That wouldn't be right for the noexcept clause.
+
// Parse exception-specification[opt].
- if (Tok.is(tok::kw_throw)) {
- hasExceptionSpec = true;
- ThrowLoc = Tok.getLocation();
- ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
- hasAnyExceptionSpec);
- assert(Exceptions.size() == ExceptionRanges.size() &&
- "Produced different number of exception types and ranges.");
- }
+ ESpecType = MaybeParseExceptionSpecification(ESpecRange,
+ DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr);
+ if (ESpecType != EST_None)
+ EndLoc = ESpecRange.getEnd();
// Parse trailing-return-type.
if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
@@ -3434,28 +3934,25 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
}
}
- // FIXME: We should leave the prototype scope before parsing the exception
- // specification, and then reenter it when parsing the trailing return type.
-
// Leave prototype scope.
PrototypeScope.Exit();
// Remember that we parsed a function type, and remember the attributes.
- D.AddTypeInfo(DeclaratorChunk::getFunction(attrs,
- /*proto*/true, IsVariadic,
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
EllipsisLoc,
ParamInfo.data(), ParamInfo.size(),
DS.getTypeQualifiers(),
RefQualifierIsLValueRef,
RefQualifierLoc,
- hasExceptionSpec, ThrowLoc,
- hasAnyExceptionSpec,
- Exceptions.data(),
- ExceptionRanges.data(),
- Exceptions.size(),
- LParenLoc, RParenLoc, D,
+ ESpecType, ESpecRange.getBegin(),
+ DynamicExceptions.data(),
+ DynamicExceptionRanges.data(),
+ DynamicExceptions.size(),
+ NoexceptExpr.isUsable() ?
+ NoexceptExpr.get() : 0,
+ LParenLoc, EndLoc, D,
TrailingReturnType),
- EndLoc);
+ attrs, EndLoc);
}
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
@@ -3524,16 +4021,15 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
// Remember that we parsed a function type, and remember the attributes. This
// function type is always a K&R style function type, which is not varargs and
// has no prototype.
- D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(),
- /*proto*/false, /*varargs*/false,
+ ParsedAttributes attrs(AttrFactory);
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
SourceLocation(),
&ParamInfo[0], ParamInfo.size(),
/*TypeQuals*/0,
true, SourceLocation(),
- /*exception*/false,
- SourceLocation(), false, 0, 0, 0,
- LParenLoc, RLoc, D),
- RLoc);
+ EST_None, SourceLocation(), 0, 0,
+ 0, 0, LParenLoc, RLoc, D),
+ attrs, RLoc);
}
/// [C90] direct-declarator '[' constant-expression[opt] ']'
@@ -3548,14 +4044,14 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// This code does a fast path to handle some of the most obvious cases.
if (Tok.getKind() == tok::r_square) {
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
// Remember that we parsed the empty array type.
ExprResult NumElements;
- D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, false, 0,
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
StartLoc, EndLoc),
- EndLoc);
+ attrs, EndLoc);
return;
} else if (Tok.getKind() == tok::numeric_constant &&
GetLookAheadToken(1).is(tok::r_square)) {
@@ -3564,14 +4060,14 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
ConsumeToken();
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
// Remember that we parsed a array type, and remember its features.
- D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, 0,
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0,
ExprRes.release(),
StartLoc, EndLoc),
- EndLoc);
+ attrs, EndLoc);
return;
}
@@ -3582,7 +4078,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// If there is a type-qualifier-list, read it now.
// Type qualifiers in an array subscript are a C99 feature.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
// If we haven't already read 'static', check to see if there is one after the
@@ -3630,15 +4126,15 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
// Remember that we parsed a array type, and remember its features.
- D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), attrs,
+ D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
StaticLoc.isValid(), isStar,
NumElements.release(),
StartLoc, EndLoc),
- EndLoc);
+ attrs, EndLoc);
}
/// [GNU] typeof-specifier:
@@ -3656,10 +4152,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
bool isCastExpr;
ParsedType CastTy;
SourceRange CastRange;
- ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok,
- isCastExpr,
- CastTy,
- CastRange);
+ ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr,
+ CastTy, CastRange);
if (hasParens)
DS.setTypeofParensRange(CastRange);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index b3ad25b024fc..8c0aa1ba694c 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -69,11 +69,9 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
// Read label attributes, if present.
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
if (Tok.is(tok::kw___attribute)) {
attrTok = Tok;
-
- // FIXME: save these somewhere.
ParseGNUAttributes(attrs);
}
@@ -111,14 +109,14 @@ Decl *Parser::ParseNamespace(unsigned Context,
ParseScope NamespaceScope(this, Scope::DeclScope);
Decl *NamespcDecl =
- Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, IdentLoc, Ident,
- LBrace, attrs.getList());
+ Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc,
+ IdentLoc, Ident, LBrace, attrs.getList());
PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc,
"parsing namespace");
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
@@ -138,9 +136,9 @@ Decl *Parser::ParseNamespace(unsigned Context,
/// alias definition.
///
Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
- SourceLocation AliasLoc,
- IdentifierInfo *Alias,
- SourceLocation &DeclEnd) {
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ SourceLocation &DeclEnd) {
assert(Tok.is(tok::equal) && "Not equal token");
ConsumeToken(); // eat the '='.
@@ -194,16 +192,21 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
ParseScope LinkageScope(this, Scope::DeclScope);
Decl *LinkageSpec
= Actions.ActOnStartLinkageSpecification(getCurScope(),
- /*FIXME: */SourceLocation(),
+ DS.getSourceRange().getBegin(),
Loc, Lang,
- Tok.is(tok::l_brace)? Tok.getLocation()
+ Tok.is(tok::l_brace) ? Tok.getLocation()
: SourceLocation());
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
if (Tok.isNot(tok::l_brace)) {
+ // Reset the source range in DS, as the leading "extern"
+ // does not really belong to the inner declaration ...
+ DS.SetRangeStart(SourceLocation());
+ DS.SetRangeEnd(SourceLocation());
+ // ... but anyway remember that such an "extern" was seen.
DS.setExternInLinkageSpec(true);
ParseExternalDeclaration(attrs, &DS);
return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec,
@@ -216,7 +219,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
SourceLocation LBrace = ConsumeBrace();
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
@@ -255,7 +258,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs);
}
- // Otherwise, it must be a using-declaration.
+ // Otherwise, it must be a using-declaration or an alias-declaration.
// Using declarations can't have attributes.
ProhibitAttributes(attrs);
@@ -325,14 +328,17 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
IdentLoc, NamespcName, attrs.getList());
}
-/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that
-/// 'using' was already seen.
+/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration.
+/// Assumes that 'using' was already seen.
///
/// using-declaration: [C++ 7.3.p3: namespace.udecl]
/// 'using' 'typename'[opt] ::[opt] nested-name-specifier
/// unqualified-id
/// 'using' :: unqualified-id
///
+/// alias-declaration: C++0x [decl.typedef]p2
+/// 'using' identifier = type-id ;
+///
Decl *Parser::ParseUsingDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
SourceLocation UsingLoc,
@@ -342,10 +348,6 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
SourceLocation TypenameLoc;
bool IsTypeName;
- // TODO: in C++0x, if we have template parameters this must be a
- // template alias:
- // template <...> using id = type;
-
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
if (Tok.is(tok::kw_typename)) {
@@ -379,17 +381,48 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
- // Parse (optional) attributes (most likely GNU strong-using extension).
- ParsedAttributes attrs;
- MaybeParseGNUAttributes(attrs);
+ ParsedAttributes attrs(AttrFactory);
+
+ // Maybe this is an alias-declaration.
+ bool IsAliasDecl = Tok.is(tok::equal);
+ TypeResult TypeAlias;
+ if (IsAliasDecl) {
+ // TODO: Do we want to support attributes somewhere in an alias declaration?
+ // Can't follow GCC since it doesn't support them yet!
+ ConsumeToken();
+
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok.getLocation(), diag::ext_alias_declaration);
+
+ // Name must be an identifier.
+ if (Name.getKind() != UnqualifiedId::IK_Identifier) {
+ Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
+ // No removal fixit: can't recover from this.
+ SkipUntil(tok::semi);
+ return 0;
+ } else if (IsTypeName)
+ Diag(TypenameLoc, diag::err_alias_declaration_not_identifier)
+ << FixItHint::CreateRemoval(SourceRange(TypenameLoc,
+ SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc));
+ else if (SS.isNotEmpty())
+ Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
+ << FixItHint::CreateRemoval(SS.getRange());
+
+ TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext);
+ } else
+ // Parse (optional) attributes (most likely GNU strong-using extension).
+ MaybeParseGNUAttributes(attrs);
// Eat ';'.
DeclEnd = Tok.getLocation();
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- !attrs.empty() ? "attributes list" : "using declaration",
+ !attrs.empty() ? "attributes list" :
+ IsAliasDecl ? "alias declaration" : "using declaration",
tok::semi);
// Diagnose an attempt to declare a templated using-declaration.
+ // TODO: in C++0x, alias-declarations can be templates:
+ // template <...> using id = type;
if (TemplateInfo.Kind) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_declaration)
@@ -401,18 +434,30 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
+ if (IsAliasDecl)
+ return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name,
+ TypeAlias);
+
return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
Name, attrs.getList(),
IsTypeName, TypenameLoc);
}
-/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
+/// ParseStaticAssertDeclaration - Parse C++0x or C1X static_assert-declaration.
+///
+/// [C++0x] static_assert-declaration:
+/// static_assert ( constant-expression , string-literal ) ;
///
-/// static_assert-declaration:
-/// static_assert ( constant-expression , string-literal ) ;
+/// [C1X] static_assert-declaration:
+/// _Static_assert ( constant-expression , string-literal ) ;
///
Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
- assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration");
+ assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) &&
+ "Not a static_assert declaration");
+
+ if (Tok.is(tok::kw__Static_assert) && !getLang().C1X)
+ Diag(Tok, diag::ext_c1x_static_assert);
+
SourceLocation StaticAssertLoc = ConsumeToken();
if (Tok.isNot(tok::l_paren)) {
@@ -441,14 +486,15 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
if (AssertMessage.isInvalid())
return 0;
- MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
DeclEnd = Tok.getLocation();
ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc,
AssertExpr.take(),
- AssertMessage.take());
+ AssertMessage.take(),
+ RParenLoc);
}
/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier.
@@ -508,14 +554,14 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
/// simple-template-id
///
Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
- CXXScopeSpec *SS) {
+ CXXScopeSpec &SS) {
// Check whether we have a template-id that names a type.
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType();
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
ParsedType Type = getTypeAnnotation(Tok);
@@ -544,7 +590,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
TemplateNameKind TNK = TNK_Type_template;
TemplateTy Template;
if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(),
- SS, Template, TNK)) {
+ &SS, Template, TNK)) {
Diag(IdLoc, diag::err_unknown_template_name)
<< Id;
}
@@ -561,7 +607,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
SourceLocation(), true))
return true;
if (TNK == TNK_Dependent_template_name)
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType();
// If we didn't end up with a typename token, there's nothing more we
// can do.
@@ -577,7 +623,9 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
}
// We have an identifier; check whether it is actually a type.
- ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), SS, true);
+ ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true,
+ false, ParsedType(),
+ /*NonTrivialTypeSourceInfo=*/true);
if (!Type) {
Diag(IdLoc, diag::err_expected_class_name);
return true;
@@ -587,10 +635,10 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
EndLocation = IdLoc;
// Fake up a Declarator to use with ActOnTypeName.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
DS.SetRangeStart(IdLoc);
DS.SetRangeEnd(EndLocation);
- DS.getTypeSpecScope() = *SS;
+ DS.getTypeSpecScope() = SS;
const char *PrevSpec = 0;
unsigned DiagID;
@@ -674,7 +722,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SuppressingAccessChecks = true;
}
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
ParseGNUAttributes(attrs);
@@ -688,22 +736,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// styles of attributes?
MaybeParseCXX0XAttributes(attrs);
- if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) {
- // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but
- // __is_pod is a keyword in GCC >= 4.3. Therefore, when we see the
- // token sequence "struct __is_pod", make __is_pod into a normal
- // identifier rather than a keyword, to allow libstdc++ 4.2 to work
- // properly.
- Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
- Tok.setKind(tok::identifier);
- }
-
- if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_empty)) {
- // GNU libstdc++ 4.2 uses __is_empty as the name of a struct template, but
- // __is_empty is a keyword in GCC >= 4.3. Therefore, when we see the
- // token sequence "struct __is_empty", make __is_empty into a normal
- // identifier rather than a keyword, to allow libstdc++ 4.2 to work
- // properly.
+ if (TagType == DeclSpec::TST_struct &&
+ !Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo() &&
+ (Tok.is(tok::kw___is_arithmetic) ||
+ Tok.is(tok::kw___is_convertible) ||
+ Tok.is(tok::kw___is_empty) ||
+ Tok.is(tok::kw___is_floating_point) ||
+ Tok.is(tok::kw___is_function) ||
+ Tok.is(tok::kw___is_fundamental) ||
+ Tok.is(tok::kw___is_integral) ||
+ Tok.is(tok::kw___is_member_function_pointer) ||
+ Tok.is(tok::kw___is_member_pointer) ||
+ Tok.is(tok::kw___is_pod) ||
+ Tok.is(tok::kw___is_pointer) ||
+ Tok.is(tok::kw___is_same) ||
+ Tok.is(tok::kw___is_scalar) ||
+ Tok.is(tok::kw___is_signed) ||
+ Tok.is(tok::kw___is_unsigned) ||
+ Tok.is(tok::kw___is_void))) {
+ // GNU libstdc++ 4.2 and libc++ uaw certain intrinsic names as the
+ // name of struct templates, but some are keywords in GCC >= 4.3
+ // and Clang. Therefore, when we see the token sequence "struct
+ // X", make X into a normal identifier rather than a keyword, to
+ // allow libstdc++ 4.2 and libc++ to work properly.
Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
Tok.setKind(tok::identifier);
}
@@ -737,7 +793,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// a class (or template thereof).
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS,
+ if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS,
true, LAngleLoc,
TemplateArgs, RAngleLoc)) {
// We couldn't parse the template argument list at all, so don't
@@ -779,7 +835,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
NameLoc = ConsumeToken();
- if (TemplateId->Kind != TNK_Type_template) {
+ if (TemplateId->Kind != TNK_Type_template &&
+ TemplateId->Kind != TNK_Dependent_template_name) {
// The template-name in the simple-template-id refers to
// something other than a class template. Give an appropriate
// error message and skip to the ';'.
@@ -808,7 +865,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// There are four options here. If we have 'struct foo;', then this
// is either a forward declaration or a friend declaration, which
// have to be treated differently. If we have 'struct foo {...',
- // 'struct foo :...' or 'struct foo <class-virt-specifier>' then this is a
+ // 'struct foo :...' or 'struct foo final[opt]' then this is a
// definition. Otherwise we have something like 'struct foo xyz', a reference.
// However, in some contexts, things look like declarations but are just
// references, e.g.
@@ -821,7 +878,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TUK = Sema::TUK_Reference;
else if (Tok.is(tok::l_brace) ||
(getLang().CPlusPlus && Tok.is(tok::colon)) ||
- isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None) {
+ isCXX0XFinalKeyword()) {
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
// A class shall not be defined in a friend declaration.
@@ -891,15 +948,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (TUK == Sema::TUK_Reference ||
(TUK == Sema::TUK_Friend &&
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
- TypeResult
- = Actions.ActOnTemplateIdType(TemplateId->Template,
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
- TemplateArgsPtr,
- TemplateId->RAngleLoc);
-
- TypeResult = Actions.ActOnTagTemplateIdType(SS, TypeResult, TUK,
- TagType, StartLoc);
+ TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType,
+ StartLoc,
+ TemplateId->SS,
+ TemplateId->Template,
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->RAngleLoc);
} else {
// This is an explicit specialization or a class template
// partial specialization.
@@ -1007,26 +1063,24 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Definition) {
assert(Tok.is(tok::l_brace) ||
(getLang().CPlusPlus && Tok.is(tok::colon)) ||
- isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None);
+ isCXX0XFinalKeyword());
if (getLang().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
else
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
}
- // FIXME: The DeclSpec should keep the locations of both the keyword and the
- // name (if there is one).
- SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
-
const char *PrevSpec = 0;
unsigned DiagID;
bool Result;
if (!TypeResult.isInvalid()) {
- Result = DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc,
+ Result = DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc,
+ NameLoc.isValid() ? NameLoc : StartLoc,
PrevSpec, DiagID, TypeResult.get());
} else if (!TagOrTempResult.isInvalid()) {
- Result = DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID,
- TagOrTempResult.get(), Owned);
+ Result = DS.SetTypeSpecType(TagType, StartLoc,
+ NameLoc.isValid() ? NameLoc : StartLoc,
+ PrevSpec, DiagID, TagOrTempResult.get(), Owned);
} else {
DS.SetTypeSpecError();
return;
@@ -1072,7 +1126,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
case tok::kw_mutable: // struct foo {...} mutable x;
// As shown above, type qualifiers and storage class specifiers absolutely
// can occur after class specifiers according to the grammar. However,
- // almost noone actually writes code like this. If we see one of these,
+ // almost no one actually writes code like this. If we see one of these,
// it is much more likely that someone missed a semi colon and the
// type/storage class specifier we're seeing is part of the *next*
// intended declaration, as in:
@@ -1195,7 +1249,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
// Parse the class-name.
SourceLocation EndLocation;
- TypeResult BaseType = ParseClassName(EndLocation, &SS);
+ TypeResult BaseType = ParseClassName(EndLocation, SS);
if (BaseType.isInvalid())
return true;
@@ -1270,14 +1324,10 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
/// virt-specifier:
/// override
/// final
-/// new
VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const {
if (!getLang().CPlusPlus)
return VirtSpecifiers::VS_None;
- if (Tok.is(tok::kw_new))
- return VirtSpecifiers::VS_New;
-
if (Tok.is(tok::identifier)) {
IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -1323,61 +1373,22 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
}
}
-/// isCXX0XClassVirtSpecifier - Determine whether the next token is a C++0x
-/// class-virt-specifier.
-///
-/// class-virt-specifier:
-/// final
-/// explicit
-ClassVirtSpecifiers::Specifier Parser::isCXX0XClassVirtSpecifier() const {
+/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x
+/// contextual 'final' keyword.
+bool Parser::isCXX0XFinalKeyword() const {
if (!getLang().CPlusPlus)
- return ClassVirtSpecifiers::CVS_None;
-
- if (Tok.is(tok::kw_explicit))
- return ClassVirtSpecifiers::CVS_Explicit;
-
- if (Tok.is(tok::identifier)) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
-
- // Initialize the contextual keywords.
- if (!Ident_final) {
- Ident_final = &PP.getIdentifierTable().get("final");
- Ident_override = &PP.getIdentifierTable().get("override");
- }
-
- if (II == Ident_final)
- return ClassVirtSpecifiers::CVS_Final;
- }
-
- return ClassVirtSpecifiers::CVS_None;
-}
-
-/// ParseOptionalCXX0XClassVirtSpecifierSeq - Parse a class-virt-specifier-seq.
-///
-/// class-virt-specifier-seq:
-/// class-virt-specifier
-/// class-virt-specifier-seq class-virt-specifier
-void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) {
- while (true) {
- ClassVirtSpecifiers::Specifier Specifier = isCXX0XClassVirtSpecifier();
- if (Specifier == ClassVirtSpecifiers::CVS_None)
- return;
-
- // C++ [class]p1:
- // A class-virt-specifier-seq shall contain at most one of each
- // class-virt-specifier.
- const char *PrevSpec = 0;
- if (CVS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec))
- Diag(Tok.getLocation(), diag::err_duplicate_class_virt_specifier)
- << PrevSpec
- << FixItHint::CreateRemoval(Tok.getLocation());
+ return false;
- if (!getLang().CPlusPlus0x)
- Diag(Tok.getLocation(), diag::ext_override_control_keyword)
- << ClassVirtSpecifiers::getSpecifierName(Specifier);
+ if (!Tok.is(tok::identifier))
+ return false;
- ConsumeToken();
+ // Initialize the contextual keywords.
+ if (!Ident_final) {
+ Ident_final = &PP.getIdentifierTable().get("final");
+ Ident_override = &PP.getIdentifierTable().get("override");
}
+
+ return Tok.getIdentifierInfo() == Ident_final;
}
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
@@ -1418,6 +1429,17 @@ void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) {
void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject *TemplateDiags) {
+ if (Tok.is(tok::at)) {
+ if (getLang().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs))
+ Diag(Tok, diag::err_at_defs_cxx);
+ else
+ Diag(Tok, diag::err_at_in_class);
+
+ ConsumeToken();
+ SkipUntil(tok::r_brace);
+ return;
+ }
+
// Access declarations.
if (!TemplateInfo.Kind &&
(Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
@@ -1459,7 +1481,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
// static_assert-declaration
- if (Tok.is(tok::kw_static_assert)) {
+ if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) {
// FIXME: Check for templates
SourceLocation DeclEnd;
ParseStaticAssertDeclaration(DeclEnd);
@@ -1487,7 +1509,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// is a bitfield.
ColonProtectionRAIIObject X(*this);
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
// Optional C++0x attribute-specifier
MaybeParseCXX0XAttributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
@@ -1542,7 +1564,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
// If so, skip until the semi-colon or a }.
- SkipUntil(tok::r_brace, true);
+ SkipUntil(tok::r_brace, true, true);
if (Tok.is(tok::semi))
ConsumeToken();
return;
@@ -1763,8 +1785,24 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl)
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
- ClassVirtSpecifiers CVS;
- ParseOptionalCXX0XClassVirtSpecifierSeq(CVS);
+ SourceLocation FinalLoc;
+
+ // Parse the optional 'final' keyword.
+ if (getLang().CPlusPlus && Tok.is(tok::identifier)) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ // Initialize the contextual keywords.
+ if (!Ident_final) {
+ Ident_final = &PP.getIdentifierTable().get("final");
+ Ident_override = &PP.getIdentifierTable().get("override");
+ }
+
+ if (II == Ident_final)
+ FinalLoc = ConsumeToken();
+
+ if (!getLang().CPlusPlus0x)
+ Diag(FinalLoc, diag::ext_override_control_keyword) << "final";
+ }
if (Tok.is(tok::colon)) {
ParseBaseClause(TagDecl);
@@ -1783,7 +1821,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation LBraceLoc = ConsumeBrace();
if (TagDecl)
- Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, CVS,
+ Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc,
LBraceLoc);
// C++ 11p3: Members of a class defined with the keyword class are private
@@ -1836,7 +1874,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
// If attributes exist after class contents, parse them.
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
if (TagDecl)
@@ -1893,6 +1931,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
+ // Poison the SEH identifiers so they are flagged as illegal in constructor initializers
+ PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
SourceLocation ColonLoc = ConsumeToken();
llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers;
@@ -1956,7 +1996,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
- AnnotateTemplateIdTokenAsType(&SS);
+ AnnotateTemplateIdTokenAsType();
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = getTypeAnnotation(Tok);
}
@@ -1999,10 +2039,81 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
EllipsisLoc);
}
-/// ParseExceptionSpecification - Parse a C++ exception-specification
-/// (C++ [except.spec]).
+/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]).
///
/// exception-specification:
+/// dynamic-exception-specification
+/// noexcept-specification
+///
+/// noexcept-specification:
+/// 'noexcept'
+/// 'noexcept' '(' constant-expression ')'
+ExceptionSpecificationType
+Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
+ llvm::SmallVectorImpl<ParsedType> &DynamicExceptions,
+ llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
+ ExprResult &NoexceptExpr) {
+ ExceptionSpecificationType Result = EST_None;
+
+ // See if there's a dynamic specification.
+ if (Tok.is(tok::kw_throw)) {
+ Result = ParseDynamicExceptionSpecification(SpecificationRange,
+ DynamicExceptions,
+ DynamicExceptionRanges);
+ assert(DynamicExceptions.size() == DynamicExceptionRanges.size() &&
+ "Produced different number of exception types and ranges.");
+ }
+
+ // If there's no noexcept specification, we're done.
+ if (Tok.isNot(tok::kw_noexcept))
+ return Result;
+
+ // If we already had a dynamic specification, parse the noexcept for,
+ // recovery, but emit a diagnostic and don't store the results.
+ SourceRange NoexceptRange;
+ ExceptionSpecificationType NoexceptType = EST_None;
+
+ SourceLocation KeywordLoc = ConsumeToken();
+ if (Tok.is(tok::l_paren)) {
+ // There is an argument.
+ SourceLocation LParenLoc = ConsumeParen();
+ NoexceptType = EST_ComputedNoexcept;
+ NoexceptExpr = ParseConstantExpression();
+ // The argument must be contextually convertible to bool. We use
+ // ActOnBooleanCondition for this purpose.
+ if (!NoexceptExpr.isInvalid())
+ NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc,
+ NoexceptExpr.get());
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ NoexceptRange = SourceRange(KeywordLoc, RParenLoc);
+ } else {
+ // There is no argument.
+ NoexceptType = EST_BasicNoexcept;
+ NoexceptRange = SourceRange(KeywordLoc, KeywordLoc);
+ }
+
+ if (Result == EST_None) {
+ SpecificationRange = NoexceptRange;
+ Result = NoexceptType;
+
+ // If there's a dynamic specification after a noexcept specification,
+ // parse that and ignore the results.
+ if (Tok.is(tok::kw_throw)) {
+ Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification);
+ ParseDynamicExceptionSpecification(NoexceptRange, DynamicExceptions,
+ DynamicExceptionRanges);
+ }
+ } else {
+ Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification);
+ }
+
+ return Result;
+}
+
+/// ParseDynamicExceptionSpecification - Parse a C++
+/// dynamic-exception-specification (C++ [except.spec]).
+///
+/// dynamic-exception-specification:
/// 'throw' '(' type-id-list [opt] ')'
/// [MS] 'throw' '(' '...' ')'
///
@@ -2010,46 +2121,47 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
/// type-id ... [opt]
/// type-id-list ',' type-id ... [opt]
///
-bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
- llvm::SmallVectorImpl<ParsedType>
- &Exceptions,
- llvm::SmallVectorImpl<SourceRange>
- &Ranges,
- bool &hasAnyExceptionSpec) {
+ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
+ SourceRange &SpecificationRange,
+ llvm::SmallVectorImpl<ParsedType> &Exceptions,
+ llvm::SmallVectorImpl<SourceRange> &Ranges) {
assert(Tok.is(tok::kw_throw) && "expected throw");
- ConsumeToken();
+ SpecificationRange.setBegin(ConsumeToken());
if (!Tok.is(tok::l_paren)) {
- return Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ SpecificationRange.setEnd(SpecificationRange.getBegin());
+ return EST_DynamicNone;
}
SourceLocation LParenLoc = ConsumeParen();
// Parse throw(...), a Microsoft extension that means "this function
// can throw anything".
if (Tok.is(tok::ellipsis)) {
- hasAnyExceptionSpec = true;
SourceLocation EllipsisLoc = ConsumeToken();
if (!getLang().Microsoft)
Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
- EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- return false;
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ SpecificationRange.setEnd(RParenLoc);
+ return EST_MSAny;
}
// Parse the sequence of type-ids.
SourceRange Range;
while (Tok.isNot(tok::r_paren)) {
TypeResult Res(ParseTypeName(&Range));
-
+
if (Tok.is(tok::ellipsis)) {
// C++0x [temp.variadic]p5:
// - In a dynamic-exception-specification (15.4); the pattern is a
// type-id.
SourceLocation Ellipsis = ConsumeToken();
+ Range.setEnd(Ellipsis);
if (!Res.isInvalid())
Res = Actions.ActOnPackExpansion(Res.get(), Ellipsis);
}
-
+
if (!Res.isInvalid()) {
Exceptions.push_back(Res.get());
Ranges.push_back(Range);
@@ -2061,8 +2173,8 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
break;
}
- EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- return false;
+ SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc));
+ return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic;
}
/// ParseTrailingReturnType - Parse a trailing return type on a new-style
@@ -2236,8 +2348,8 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
break;
}
- attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc, 0,
- SourceLocation(), 0, 0, false, true));
+ attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, 0,
+ SourceLocation(), 0, 0, false, true);
AttrParsed = true;
break;
}
@@ -2257,9 +2369,9 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
ExprVector ArgExprs(Actions);
ArgExprs.push_back(ArgExpr.release());
- attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc,
- 0, ParamLoc, ArgExprs.take(), 1,
- false, true));
+ attrs.addNew(AttrName, AttrLoc, 0, AttrLoc,
+ 0, ParamLoc, ArgExprs.take(), 1,
+ false, true);
AttrParsed = true;
break;
@@ -2301,8 +2413,8 @@ ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) {
SourceLocation TypeLoc = Tok.getLocation();
ParsedType Ty = ParseTypeName().get();
SourceRange TypeRange(Start, Tok.getLocation());
- return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true,
- Ty.getAsOpaquePtr(), TypeRange);
+ return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true,
+ Ty.getAsOpaquePtr(), TypeRange);
} else
return ParseConstantExpression();
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 616c251583fb..91fe1e1935e9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -174,7 +174,6 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// expression: [C99 6.5.17]
/// assignment-expression ...[opt]
/// expression ',' assignment-expression ...[opt]
-///
ExprResult Parser::ParseExpression() {
ExprResult LHS(ParseAssignmentExpression());
return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
@@ -212,7 +211,6 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
}
/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
-///
ExprResult Parser::ParseAssignmentExpression() {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
@@ -222,7 +220,7 @@ ExprResult Parser::ParseAssignmentExpression() {
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
- ExprResult LHS(ParseCastExpression(false));
+ ExprResult LHS = ParseCastExpression(false, false, ParsedType());
return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
}
@@ -415,8 +413,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
/// due to member pointers.
///
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
- bool isAddressOfOperand,
- ParsedType TypeOfCast) {
+ bool isAddressOfOperand,
+ ParsedType TypeOfCast) {
bool NotCastExpr;
ExprResult Res = ParseCastExpression(isUnaryExpression,
isAddressOfOperand,
@@ -465,6 +463,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [C++] boolean-literal [C++ 2.13.5]
/// [C++0x] 'nullptr' [C++0x 2.14.7]
/// '(' expression ')'
+/// [C1X] generic-selection
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
/// [GNU] '__PRETTY_FUNCTION__'
@@ -491,6 +490,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [C++] 'this' [C++ 9.3.2]
/// [G++] unary-type-trait '(' type-id ')'
/// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO]
+/// [EMBT] array-type-trait '(' type-id ',' integer ')'
/// [clang] '^' block-literal
///
/// constant: [C99 6.4.4]
@@ -520,6 +520,34 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// '::'[opt] 'delete' cast-expression
/// '::'[opt] 'delete' '[' ']' cast-expression
///
+/// [GNU/Embarcadero] unary-type-trait:
+/// '__is_arithmetic'
+/// '__is_floating_point'
+/// '__is_integral'
+/// '__is_lvalue_expr'
+/// '__is_rvalue_expr'
+/// '__is_complete_type'
+/// '__is_void'
+/// '__is_array'
+/// '__is_function'
+/// '__is_reference'
+/// '__is_lvalue_reference'
+/// '__is_rvalue_reference'
+/// '__is_fundamental'
+/// '__is_object'
+/// '__is_scalar'
+/// '__is_compound'
+/// '__is_pointer'
+/// '__is_member_object_pointer'
+/// '__is_member_function_pointer'
+/// '__is_member_pointer'
+/// '__is_const'
+/// '__is_volatile'
+/// '__is_trivial'
+/// '__is_standard_layout'
+/// '__is_signed'
+/// '__is_unsigned'
+///
/// [GNU] unary-type-trait:
/// '__has_nothrow_assign'
/// '__has_nothrow_copy'
@@ -535,11 +563,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// '__is_enum'
/// '__is_pod'
/// '__is_polymorphic'
+/// '__is_trivial'
/// '__is_union'
///
/// binary-type-trait:
/// [GNU] '__is_base_of'
/// [MS] '__is_convertible_to'
+/// '__is_convertible'
+/// '__is_same'
+///
+/// [Embarcadero] array-type-trait:
+/// '__array_rank'
+/// '__array_extent'
+///
+/// [Embarcadero] expression-trait:
+/// '__is_lvalue_expr'
+/// '__is_rvalue_expr'
///
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
@@ -610,6 +649,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_nullptr:
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
+ case tok::annot_primary_expr:
+ assert(Res.get() == 0 && "Stray primary-expression annotation?");
+ Res = getExprAnnotation(Tok);
+ ConsumeToken();
+ break;
+
case tok::identifier: { // primary-expression: identifier
// unqualified-id: identifier
// constant: enumeration-constant
@@ -683,7 +728,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope()))
if (Typ.get()->isObjCObjectOrInterfaceType()) {
// Fake up a Declarator to use with ActOnTypeName.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
DS.SetRangeStart(ILoc);
DS.SetRangeEnd(ILoc);
const char *PrevSpec = 0;
@@ -731,6 +776,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::wide_string_literal:
Res = ParseStringLiteralExpression();
break;
+ case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1]
+ Res = ParseGenericSelectionExpression();
+ break;
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
@@ -788,7 +836,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
// unary-expression: '__alignof' '(' type-name ')'
// unary-expression: 'alignof' '(' type-id ')'
- return ParseSizeofAlignofExpression();
+ case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression
+ return ParseUnaryExprOrTypeTraitExpression();
case tok::ampamp: { // unary-expression: '&&' identifier
SourceLocation AmpAmpLoc = ConsumeToken();
if (Tok.isNot(tok::identifier))
@@ -825,7 +874,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ParsedType Type = getTypeAnnotation(Tok);
// Fake up a Declarator to use with ActOnTypeName.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
DS.SetRangeStart(Tok.getLocation());
DS.SetRangeEnd(Tok.getLastLoc());
@@ -854,6 +903,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_short:
case tok::kw_int:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_float:
@@ -875,7 +925,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
//
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
@@ -904,7 +954,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// cast expression.
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
- AnnotateTemplateIdTokenAsType(&SS);
+ AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, TypeOfCast);
}
@@ -978,14 +1028,39 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return move(Result);
}
- case tok::kw___is_pod: // [GNU] unary-type-trait
+ case tok::kw___is_abstract: // [GNU] unary-type-trait
case tok::kw___is_class:
- case tok::kw___is_enum:
- case tok::kw___is_union:
case tok::kw___is_empty:
- case tok::kw___is_polymorphic:
- case tok::kw___is_abstract:
+ case tok::kw___is_enum:
case tok::kw___is_literal:
+ case tok::kw___is_arithmetic:
+ case tok::kw___is_integral:
+ case tok::kw___is_floating_point:
+ case tok::kw___is_complete_type:
+ case tok::kw___is_void:
+ case tok::kw___is_array:
+ case tok::kw___is_function:
+ case tok::kw___is_reference:
+ case tok::kw___is_lvalue_reference:
+ case tok::kw___is_rvalue_reference:
+ case tok::kw___is_fundamental:
+ case tok::kw___is_object:
+ case tok::kw___is_scalar:
+ case tok::kw___is_compound:
+ case tok::kw___is_pointer:
+ case tok::kw___is_member_object_pointer:
+ case tok::kw___is_member_function_pointer:
+ case tok::kw___is_member_pointer:
+ case tok::kw___is_const:
+ case tok::kw___is_volatile:
+ case tok::kw___is_standard_layout:
+ case tok::kw___is_signed:
+ case tok::kw___is_unsigned:
+ case tok::kw___is_literal_type:
+ case tok::kw___is_pod:
+ case tok::kw___is_polymorphic:
+ case tok::kw___is_trivial:
+ case tok::kw___is_union:
case tok::kw___has_trivial_constructor:
case tok::kw___has_trivial_copy:
case tok::kw___has_trivial_assign:
@@ -998,9 +1073,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___builtin_types_compatible_p:
case tok::kw___is_base_of:
+ case tok::kw___is_same:
+ case tok::kw___is_convertible:
case tok::kw___is_convertible_to:
return ParseBinaryTypeTrait();
+ case tok::kw___array_rank:
+ case tok::kw___array_extent:
+ return ParseArrayTypeTrait();
+
+ case tok::kw___is_lvalue_expr:
+ case tok::kw___is_rvalue_expr:
+ return ParseExpressionTrait();
+
case tok::at: {
SourceLocation AtLoc = ConsumeToken();
return ParseObjCAtExpression(AtLoc);
@@ -1256,10 +1341,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
}
}
-/// ParseExprAfterTypeofSizeofAlignof - We parsed a typeof/sizeof/alignof and
-/// we are at the start of an expression or a parenthesized type-id.
-/// OpTok is the operand token (typeof/sizeof/alignof). Returns the expression
-/// (isCastExpr == false) or the type (isCastExpr == true).
+/// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/
+/// vec_step and we are at the start of an expression or a parenthesized
+/// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the
+/// expression (isCastExpr == false) or the type (isCastExpr == true).
///
/// unary-expression: [C99 6.5.3]
/// 'sizeof' unary-expression
@@ -1273,15 +1358,20 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
/// typeof ( type-name )
/// [GNU/C++] typeof unary-expression
///
+/// [OpenCL 1.1 6.11.12] vec_step built-in function:
+/// vec_step ( expressions )
+/// vec_step ( type-name )
+///
ExprResult
-Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
- bool &isCastExpr,
- ParsedType &CastTy,
- SourceRange &CastRange) {
+Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
+ bool &isCastExpr,
+ ParsedType &CastTy,
+ SourceRange &CastRange) {
assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) ||
- OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof)) &&
- "Not a typeof/sizeof/alignof expression!");
+ OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) ||
+ OpTok.is(tok::kw_vec_step)) &&
+ "Not a typeof/sizeof/alignof/vec_step expression!");
ExprResult Operand;
@@ -1345,7 +1435,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
}
-/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression.
+/// ParseUnaryExprOrTypeTraitExpression - Parse a sizeof or alignof expression.
/// unary-expression: [C99 6.5.3]
/// 'sizeof' unary-expression
/// 'sizeof' '(' type-name ')'
@@ -1353,10 +1443,10 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
/// [GNU] '__alignof' unary-expression
/// [GNU] '__alignof' '(' type-name ')'
/// [C++0x] 'alignof' '(' type-id ')'
-ExprResult Parser::ParseSizeofAlignofExpression() {
+ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof)
- || Tok.is(tok::kw_alignof)) &&
- "Not a sizeof/alignof expression!");
+ || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) &&
+ "Not a sizeof/alignof/vec_step expression!");
Token OpTok = Tok;
ConsumeToken();
@@ -1403,24 +1493,31 @@ ExprResult Parser::ParseSizeofAlignofExpression() {
bool isCastExpr;
ParsedType CastTy;
SourceRange CastRange;
- ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok,
- isCastExpr,
- CastTy,
- CastRange);
+ ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok,
+ isCastExpr,
+ CastTy,
+ CastRange);
+
+ UnaryExprOrTypeTrait ExprKind = UETT_SizeOf;
+ if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof))
+ ExprKind = UETT_AlignOf;
+ else if (OpTok.is(tok::kw_vec_step))
+ ExprKind = UETT_VecStep;
if (isCastExpr)
- return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
- OpTok.is(tok::kw_sizeof),
- /*isType=*/true,
- CastTy.getAsOpaquePtr(),
- CastRange);
+ return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
+ ExprKind,
+ /*isType=*/true,
+ CastTy.getAsOpaquePtr(),
+ CastRange);
// If we get here, the operand to the sizeof/alignof was an expresion.
if (!Operand.isInvalid())
- Operand = Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
- OpTok.is(tok::kw_sizeof),
- /*isType=*/false,
- Operand.release(), CastRange);
+ Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
+ ExprKind,
+ /*isType=*/false,
+ Operand.release(),
+ CastRange);
return move(Operand);
}
@@ -1618,15 +1715,18 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
ConsumeCodeCompletionToken();
return ExprError();
}
+
+ // None of these cases should fall through with an invalid Result
+ // unless they've already reported an error.
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
Diag(Tok, diag::ext_gnu_statement_expr);
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
StmtResult Stmt(ParseCompoundStatement(attrs, true));
ExprType = CompoundStmt;
// If the substmt parsed correctly, build the AST node.
- if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
+ if (!Stmt.isInvalid())
Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation());
} else if (ExprType >= CompoundLiteral &&
@@ -1724,6 +1824,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Result = ParseExpression();
ExprType = SimpleExpr;
+
+ // Don't build a paren expression unless we actually match a ')'.
if (!Result.isInvalid() && Tok.is(tok::r_paren))
Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.take());
}
@@ -1784,6 +1886,100 @@ ExprResult Parser::ParseStringLiteralExpression() {
return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
}
+/// ParseGenericSelectionExpression - Parse a C1X generic-selection
+/// [C1X 6.5.1.1].
+///
+/// generic-selection:
+/// _Generic ( assignment-expression , generic-assoc-list )
+/// generic-assoc-list:
+/// generic-association
+/// generic-assoc-list , generic-association
+/// generic-association:
+/// type-name : assignment-expression
+/// default : assignment-expression
+ExprResult Parser::ParseGenericSelectionExpression() {
+ assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
+ SourceLocation KeyLoc = ConsumeToken();
+
+ if (!getLang().C1X)
+ Diag(KeyLoc, diag::ext_c1x_generic_selection);
+
+ SourceLocation LParenLoc = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, ""))
+ return ExprError();
+
+ ExprResult ControllingExpr;
+ {
+ // C1X 6.5.1.1p3 "The controlling expression of a generic selection is
+ // not evaluated."
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ ControllingExpr = ParseAssignmentExpression();
+ if (ControllingExpr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ SourceLocation DefaultLoc;
+ TypeVector Types(Actions);
+ ExprVector Exprs(Actions);
+ while (1) {
+ ParsedType Ty;
+ if (Tok.is(tok::kw_default)) {
+ // C1X 6.5.1.1p2 "A generic selection shall have no more than one default
+ // generic association."
+ if (!DefaultLoc.isInvalid()) {
+ Diag(Tok, diag::err_duplicate_default_assoc);
+ Diag(DefaultLoc, diag::note_previous_default_assoc);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ DefaultLoc = ConsumeToken();
+ Ty = ParsedType();
+ } else {
+ ColonProtectionRAIIObject X(*this);
+ TypeResult TR = ParseTypeName();
+ if (TR.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ Ty = TR.release();
+ }
+ Types.push_back(Ty);
+
+ if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ // FIXME: These expressions should be parsed in a potentially potentially
+ // evaluated context.
+ ExprResult ER(ParseAssignmentExpression());
+ if (ER.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ Exprs.push_back(ER.release());
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken();
+ }
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ if (RParenLoc.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
+ ControllingExpr.release(),
+ move_arg(Types), move_arg(Exprs));
+}
+
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
///
/// argument-expression-list:
@@ -1837,7 +2033,7 @@ void Parser::ParseBlockId() {
}
// Parse the specifier-qualifier-list piece.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseSpecifierQualifierList(DS);
// Parse the block-declarator.
@@ -1845,7 +2041,7 @@ void Parser::ParseBlockId() {
ParseDeclarator(DeclaratorInfo);
// We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes.
- DeclaratorInfo.addAttributes(DS.takeAttributes());
+ DeclaratorInfo.takeAttributes(DS.getAttributes(), SourceLocation());
MaybeParseGNUAttributes(DeclaratorInfo);
@@ -1881,7 +2077,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
Actions.ActOnBlockStart(CaretLoc, getCurScope());
// Parse the return type if present.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
Declarator ParamInfo(DS, Declarator::BlockLiteralContext);
// FIXME: Since the return type isn't actually parsed, it can't be used to
// fill ParamInfo with an initial valid range, so do it manually.
@@ -1913,16 +2109,17 @@ ExprResult Parser::ParseBlockLiteralExpression() {
ParseBlockId();
} else {
// Otherwise, pretend we saw (void).
- ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(),
- true, false,
+ ParsedAttributes attrs(AttrFactory);
+ ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
SourceLocation(),
0, 0, 0,
true, SourceLocation(),
- false, SourceLocation(),
- false, 0, 0, 0,
+ EST_None,
+ SourceLocation(),
+ 0, 0, 0, 0,
CaretLoc, CaretLoc,
ParamInfo),
- CaretLoc);
+ attrs, CaretLoc);
MaybeParseGNUAttributes(ParamInfo);
@@ -1940,6 +2137,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
}
StmtResult Stmt(ParseCompoundStatementBody());
+ BlockScope.Exit();
if (!Stmt.isInvalid())
Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope());
else
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index d8db711809ed..8bf6f63d3ecd 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -20,6 +20,55 @@
using namespace clang;
+static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
+ switch (Kind) {
+ case tok::kw_template: return 0;
+ case tok::kw_const_cast: return 1;
+ case tok::kw_dynamic_cast: return 2;
+ case tok::kw_reinterpret_cast: return 3;
+ case tok::kw_static_cast: return 4;
+ default:
+ assert(0 && "Unknown type for digraph error message.");
+ return -1;
+ }
+}
+
+// Are the two tokens adjacent in the same source file?
+static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) {
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation());
+ SourceLocation FirstEnd = FirstLoc.getFileLocWithOffset(First.getLength());
+ return FirstEnd == SM.getSpellingLoc(Second.getLocation());
+}
+
+// Suggest fixit for "<::" after a cast.
+static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken,
+ Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) {
+ // Pull '<:' and ':' off token stream.
+ if (!AtDigraph)
+ PP.Lex(DigraphToken);
+ PP.Lex(ColonToken);
+
+ SourceRange Range;
+ Range.setBegin(DigraphToken.getLocation());
+ Range.setEnd(ColonToken.getLocation());
+ P.Diag(DigraphToken.getLocation(), diag::err_missing_whitespace_digraph)
+ << SelectDigraphErrorMessage(Kind)
+ << FixItHint::CreateReplacement(Range, "< ::");
+
+ // Update token information to reflect their change in token type.
+ ColonToken.setKind(tok::coloncolon);
+ ColonToken.setLocation(ColonToken.getLocation().getFileLocWithOffset(-1));
+ ColonToken.setLength(2);
+ DigraphToken.setKind(tok::less);
+ DigraphToken.setLength(1);
+
+ // Push new tokens back to token stream.
+ PP.EnterToken(ColonToken);
+ if (!AtDigraph)
+ PP.EnterToken(DigraphToken);
+}
+
/// \brief Parse global scope or nested-name-specifier if present.
///
/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
@@ -60,7 +109,8 @@ using namespace clang;
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
bool EnteringContext,
- bool *MayBePseudoDestructor) {
+ bool *MayBePseudoDestructor,
+ bool IsTypename) {
assert(getLang().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
@@ -111,7 +161,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Code completion for a nested-name-specifier, where the code
// code completion token follows the '::'.
Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext);
- ConsumeCodeCompletionToken();
+ SourceLocation ccLoc = ConsumeCodeCompletionToken();
+ // Include code completion token into the range of the scope otherwise
+ // when we try to annotate the scope tokens the dangling code completion
+ // token will cause assertion in
+ // Preprocessor::AnnotatePreviousCachedTokens.
+ SS.setEndLoc(ccLoc);
}
}
@@ -173,7 +228,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ObjectType,
EnteringContext,
Template)) {
- if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName,
+ if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
TemplateKWLoc, false))
return true;
} else
@@ -197,35 +252,37 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
- if (TemplateId->Kind == TNK_Type_template ||
- TemplateId->Kind == TNK_Dependent_template_name) {
- AnnotateTemplateIdTokenAsType(&SS);
+ // Consume the template-id token.
+ ConsumeToken();
+
+ assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ SourceLocation CCLoc = ConsumeToken();
- assert(Tok.is(tok::annot_typename) &&
- "AnnotateTemplateIdTokenAsType isn't working");
- Token TypeToken = Tok;
- ConsumeToken();
- assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
- SourceLocation CCLoc = ConsumeToken();
-
- if (!HasScopeSpecifier)
- HasScopeSpecifier = true;
-
- if (ParsedType T = getTypeAnnotation(TypeToken)) {
- if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), T, CCLoc, SS))
- SS.SetInvalid(SourceRange(SS.getBeginLoc(), CCLoc));
-
- continue;
- } else {
- SourceLocation Start = SS.getBeginLoc().isValid()? SS.getBeginLoc()
- : CCLoc;
- SS.SetInvalid(SourceRange(Start, CCLoc));
- }
-
- continue;
+ if (!HasScopeSpecifier)
+ HasScopeSpecifier = true;
+
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+
+ if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
+ /*FIXME:*/SourceLocation(),
+ SS,
+ TemplateId->Template,
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->RAngleLoc,
+ CCLoc,
+ EnteringContext)) {
+ SourceLocation StartLoc
+ = SS.getBeginLoc().isValid()? SS.getBeginLoc()
+ : TemplateId->TemplateNameLoc;
+ SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
-
- assert(false && "FIXME: Only type template names supported here");
+
+ TemplateId->Destroy();
+ continue;
}
@@ -284,6 +341,29 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
continue;
}
+ // Check for '<::' which should be '< ::' instead of '[:' when following
+ // a template name.
+ if (Next.is(tok::l_square) && Next.getLength() == 2) {
+ Token SecondToken = GetLookAheadToken(2);
+ if (SecondToken.is(tok::colon) &&
+ AreTokensAdjacent(PP, Next, SecondToken)) {
+ TemplateTy Template;
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(&II, Tok.getLocation());
+ bool MemberOfUnknownSpecialization;
+ if (Actions.isTemplateName(getCurScope(), SS,
+ /*hasTemplateKeyword=*/false,
+ TemplateName,
+ ObjectType,
+ EnteringContext,
+ Template,
+ MemberOfUnknownSpecialization)) {
+ FixDigraph(*this, PP, Next, SecondToken, tok::kw_template,
+ /*AtDigraph*/false);
+ }
+ }
+ }
+
// nested-name-specifier:
// type-name '<'
if (Next.is(tok::less)) {
@@ -305,19 +385,23 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// specializations) still want to see the original template-id
// token.
ConsumeToken();
- if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName,
+ if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
SourceLocation(), false))
return true;
continue;
}
if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&
- IsTemplateArgumentList(1)) {
+ (IsTypename || IsTemplateArgumentList(1))) {
// We have something like t::getAs<T>, where getAs is a
// member of an unknown specialization. However, this will only
// parse correctly as a template, so suggest the keyword 'template'
// before 'getAs' and treat this as a dependent template name.
- Diag(Tok.getLocation(), diag::err_missing_dependent_template_keyword)
+ unsigned DiagID = diag::err_missing_dependent_template_keyword;
+ if (getLang().Microsoft)
+ DiagID = diag::warn_missing_dependent_template_keyword;
+
+ Diag(Tok.getLocation(), DiagID)
<< II.getName()
<< FixItHint::CreateInsertion(Tok.getLocation(), "template ");
@@ -328,7 +412,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
EnteringContext, Template)) {
// Consume the identifier.
ConsumeToken();
- if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName,
+ if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
SourceLocation(), false))
return true;
}
@@ -446,6 +530,13 @@ ExprResult Parser::ParseCXXCasts() {
SourceLocation OpLoc = ConsumeToken();
SourceLocation LAngleBracketLoc = Tok.getLocation();
+ // 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(PP, Tok, Next))
+ FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true);
+
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
return ExprError();
@@ -525,7 +616,15 @@ ExprResult Parser::ParseCXXTypeid() {
RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
if (RParenLoc.isInvalid())
return ExprError();
-
+
+ // If we are a foo<int> that identifies a single function, resolve it now...
+ Expr* e = Result.get();
+ if (e->getType() == Actions.Context.OverloadTy) {
+ ExprResult er =
+ Actions.ResolveAndFixSingleFunctionTemplateSpecialization(e);
+ if (er.isUsable())
+ Result = er.release();
+ }
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
Result.release(), RParenLoc);
}
@@ -790,7 +889,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
}
// type-specifier-seq
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseSpecifierQualifierList(DS);
// declarator
@@ -846,6 +945,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const {
case tok::annot_typename:
case tok::kw_short:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_void:
@@ -857,8 +957,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_bool:
- // FIXME: C++0x decltype support.
- // GNU typeof support.
+ case tok::kw_decltype:
case tok::kw_typeof:
return true;
@@ -938,6 +1037,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
case tok::kw_long:
DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID);
break;
+ case tok::kw___int64:
+ DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID);
+ break;
case tok::kw_signed:
DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
break;
@@ -1157,7 +1259,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
TemplateArgList TemplateArgs;
if (Tok.is(tok::less) &&
ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
- &SS, true, LAngleLoc,
+ SS, true, LAngleLoc,
TemplateArgs,
RAngleLoc))
return true;
@@ -1180,6 +1282,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
TemplateId->TemplateNameLoc = Id.StartLocation;
}
+ TemplateId->SS = SS;
TemplateId->Template = Template;
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
@@ -1199,7 +1302,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Constructor and destructor names.
TypeResult Type
- = Actions.ActOnTemplateIdType(Template, NameLoc,
+ = Actions.ActOnTemplateIdType(SS, Template, NameLoc,
LAngleLoc, TemplateArgsPtr,
RAngleLoc);
if (Type.isInvalid())
@@ -1380,7 +1483,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// ptr-operator conversion-declarator[opt]
// Parse the type-specifier-seq.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType?
return true;
@@ -1465,7 +1568,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
// We have parsed a constructor name.
Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, getCurScope(),
- &SS, false),
+ &SS, false, false,
+ ParsedType(),
+ /*NonTrivialTypeSourceInfo=*/true),
IdLoc, IdLoc);
} else {
// We have parsed an identifier.
@@ -1503,7 +1608,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
Result.setConstructorName(Actions.getTypeName(*TemplateId->Name,
TemplateId->TemplateNameLoc,
getCurScope(),
- &SS, false),
+ &SS, false, false,
+ ParsedType(),
+ /*NontrivialTypeSourceInfo=*/true),
TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
TemplateId->Destroy();
@@ -1608,6 +1715,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
///
/// new-type-id:
/// type-specifier-seq new-declarator[opt]
+/// [GNU] attributes type-specifier-seq new-declarator[opt]
///
/// new-declarator:
/// ptr-operator new-declarator[opt]
@@ -1629,7 +1737,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
SourceLocation PlacementLParen, PlacementRParen;
SourceRange TypeIdParens;
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
if (Tok.is(tok::l_paren)) {
// If it turns out to be a placement, we change the type location.
@@ -1653,12 +1761,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
// We still need the type.
if (Tok.is(tok::l_paren)) {
TypeIdParens.setBegin(ConsumeParen());
+ MaybeParseGNUAttributes(DeclaratorInfo);
ParseSpecifierQualifierList(DS);
DeclaratorInfo.SetSourceRange(DS.getSourceRange());
ParseDeclarator(DeclaratorInfo);
TypeIdParens.setEnd(MatchRHSPunctuation(tok::r_paren,
TypeIdParens.getBegin()));
} else {
+ MaybeParseGNUAttributes(DeclaratorInfo);
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else {
@@ -1671,6 +1781,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
} else {
// A new-type-id is a simplified type-id, where essentially the
// direct-declarator is replaced by a direct-new-declarator.
+ MaybeParseGNUAttributes(DeclaratorInfo);
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else {
@@ -1731,10 +1842,12 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
first = false;
SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc);
- D.AddTypeInfo(DeclaratorChunk::getArray(0, ParsedAttributes(),
+
+ ParsedAttributes attrs(AttrFactory);
+ D.AddTypeInfo(DeclaratorChunk::getArray(0,
/*static=*/false, /*star=*/false,
Size.release(), LLoc, RLoc),
- RLoc);
+ attrs, RLoc);
if (RLoc.isInvalid())
return;
@@ -1803,23 +1916,48 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
switch(kind) {
- default: llvm_unreachable("Not a known unary type trait");
+ default: assert(false && "Not a known unary type trait.");
case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
- case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
+ case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
- case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
+ case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
case tok::kw___is_abstract: return UTT_IsAbstract;
+ case tok::kw___is_arithmetic: return UTT_IsArithmetic;
+ case tok::kw___is_array: return UTT_IsArray;
case tok::kw___is_class: return UTT_IsClass;
+ case tok::kw___is_complete_type: return UTT_IsCompleteType;
+ case tok::kw___is_compound: return UTT_IsCompound;
+ case tok::kw___is_const: return UTT_IsConst;
case tok::kw___is_empty: return UTT_IsEmpty;
case tok::kw___is_enum: return UTT_IsEnum;
+ case tok::kw___is_floating_point: return UTT_IsFloatingPoint;
+ case tok::kw___is_function: return UTT_IsFunction;
+ case tok::kw___is_fundamental: return UTT_IsFundamental;
+ case tok::kw___is_integral: return UTT_IsIntegral;
+ case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference;
+ case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer;
+ case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer;
+ case tok::kw___is_member_pointer: return UTT_IsMemberPointer;
+ case tok::kw___is_object: return UTT_IsObject;
+ case tok::kw___is_literal: return UTT_IsLiteral;
+ case tok::kw___is_literal_type: return UTT_IsLiteral;
case tok::kw___is_pod: return UTT_IsPOD;
+ case tok::kw___is_pointer: return UTT_IsPointer;
case tok::kw___is_polymorphic: return UTT_IsPolymorphic;
+ case tok::kw___is_reference: return UTT_IsReference;
+ case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference;
+ case tok::kw___is_scalar: return UTT_IsScalar;
+ case tok::kw___is_signed: return UTT_IsSigned;
+ case tok::kw___is_standard_layout: return UTT_IsStandardLayout;
+ case tok::kw___is_trivial: return UTT_IsTrivial;
case tok::kw___is_union: return UTT_IsUnion;
- case tok::kw___is_literal: return UTT_IsLiteral;
+ case tok::kw___is_unsigned: return UTT_IsUnsigned;
+ case tok::kw___is_void: return UTT_IsVoid;
+ case tok::kw___is_volatile: return UTT_IsVolatile;
}
}
@@ -1827,11 +1965,29 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) {
switch(kind) {
default: llvm_unreachable("Not a known binary type trait");
case tok::kw___is_base_of: return BTT_IsBaseOf;
+ case tok::kw___is_convertible: return BTT_IsConvertible;
+ case tok::kw___is_same: return BTT_IsSame;
case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible;
case tok::kw___is_convertible_to: return BTT_IsConvertibleTo;
}
}
+static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) {
+ switch(kind) {
+ default: llvm_unreachable("Not a known binary type trait");
+ case tok::kw___array_rank: return ATT_ArrayRank;
+ case tok::kw___array_extent: return ATT_ArrayExtent;
+ }
+}
+
+static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
+ switch(kind) {
+ default: assert(false && "Not a known unary expression trait.");
+ case tok::kw___is_lvalue_expr: return ET_IsLValueExpr;
+ case tok::kw___is_rvalue_expr: return ET_IsRValueExpr;
+ }
+}
+
/// ParseUnaryTypeTrait - Parse the built-in unary type-trait
/// pseudo-functions that allow implementation of the TR1/C++0x type traits
/// templates.
@@ -1897,6 +2053,72 @@ ExprResult Parser::ParseBinaryTypeTrait() {
return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), RParen);
}
+/// ParseArrayTypeTrait - Parse the built-in array type-trait
+/// pseudo-functions.
+///
+/// primary-expression:
+/// [Embarcadero] '__array_rank' '(' type-id ')'
+/// [Embarcadero] '__array_extent' '(' type-id ',' expression ')'
+///
+ExprResult Parser::ParseArrayTypeTrait() {
+ ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind());
+ SourceLocation Loc = ConsumeToken();
+
+ SourceLocation LParen = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ return ExprError();
+
+ TypeResult Ty = ParseTypeName();
+ if (Ty.isInvalid()) {
+ SkipUntil(tok::comma);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ switch (ATT) {
+ case ATT_ArrayRank: {
+ SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+ return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, RParen);
+ }
+ case ATT_ArrayExtent: {
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ ExprResult DimExpr = ParseExpression();
+ SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+
+ return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), RParen);
+ }
+ default:
+ break;
+ }
+ return ExprError();
+}
+
+/// ParseExpressionTrait - Parse built-in expression-trait
+/// pseudo-functions like __is_lvalue_expr( xxx ).
+///
+/// primary-expression:
+/// [Embarcadero] expression-trait '(' expression ')'
+///
+ExprResult Parser::ParseExpressionTrait() {
+ ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind());
+ SourceLocation Loc = ConsumeToken();
+
+ SourceLocation LParen = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ return ExprError();
+
+ ExprResult Expr = ParseExpression();
+
+ SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+
+ return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), RParen);
+}
+
+
/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
/// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate
/// based on the context past the parens.
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 82dda2b793d3..2c9278a90033 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -354,7 +354,7 @@ ExprResult Parser::ParseBraceInitializer() {
InitExprsOk = false;
// We have two ways to try to recover from this error: if the code looks
- // gramatically ok (i.e. we have a comma coming up) try to continue
+ // grammatically ok (i.e. we have a comma coming up) try to continue
// parsing the rest of the initializer. This allows us to emit
// diagnostics for later elements that we find. If we don't see a comma,
// assume there is a parse error, and just skip to recover.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index f32a322f024a..fdbedc54d1cd 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -41,11 +41,11 @@ Decl *Parser::ParseObjCAtDirectives() {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
case tok::objc_interface: {
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
return ParseObjCAtInterfaceDeclaration(AtLoc, attrs);
}
case tok::objc_protocol: {
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
return ParseObjCAtProtocolDeclaration(AtLoc, attrs);
}
case tok::objc_implementation:
@@ -327,7 +327,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
// If this is a method prototype, parse it.
if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
Decl *methodPrototype =
- ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
+ ParseObjCMethodPrototype(interfaceDecl, MethodImplKind, false);
allMethods.push_back(methodPrototype);
// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
// method definitions.
@@ -340,7 +340,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
ParseObjCMethodDecl(Tok.getLocation(),
tok::minus,
interfaceDecl,
- MethodImplKind);
+ MethodImplKind, false);
continue;
}
// Ignore excess semicolons.
@@ -371,7 +371,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
// FIXME: as the name implies, this rule allows function definitions.
// We could pass a flag or check for functions during semantic analysis.
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
continue;
}
@@ -439,11 +439,10 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
OCDS, AtLoc, MethodImplKind);
// Parse all the comma separated declarators.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseStructDeclaration(DS, Callback);
- ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "",
- tok::at);
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
break;
}
}
@@ -582,12 +581,14 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
/// __attribute__((deprecated))
///
Decl *Parser::ParseObjCMethodPrototype(Decl *IDecl,
- tok::ObjCKeywordKind MethodImplKind) {
+ tok::ObjCKeywordKind MethodImplKind,
+ bool MethodDefinition) {
assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
tok::TokenKind methodType = Tok.getKind();
SourceLocation mLoc = ConsumeToken();
- Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind);
+ Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind,
+ MethodDefinition);
// Since this rule is used for both method declarations and definitions,
// the caller is (optionally) responsible for consuming the ';'.
return MDecl;
@@ -720,10 +721,12 @@ bool Parser::isTokIdentifier_in() const {
/// objc-type-qualifier
/// objc-type-qualifiers objc-type-qualifier
///
-void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) {
+void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
+ ObjCTypeNameContext Context) {
while (1) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCPassingType(getCurScope(), DS, IsParameter);
+ Actions.CodeCompleteObjCPassingType(getCurScope(), DS,
+ Context == OTN_ParameterType);
ConsumeCodeCompletionToken();
}
@@ -760,18 +763,19 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) {
/// '(' objc-type-qualifiers[opt] type-name ')'
/// '(' objc-type-qualifiers[opt] ')'
///
-ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) {
+ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
+ ObjCTypeNameContext Context) {
assert(Tok.is(tok::l_paren) && "expected (");
SourceLocation LParenLoc = ConsumeParen();
SourceLocation TypeStartLoc = Tok.getLocation();
// Parse type qualifiers, in, inout, etc.
- ParseObjCTypeQualifierList(DS, IsParameter);
+ ParseObjCTypeQualifierList(DS, Context);
ParsedType Ty;
if (isTypeSpecifierQualifier()) {
- TypeResult TypeSpec = ParseTypeName();
+ TypeResult TypeSpec = ParseTypeName(0, Declarator::ObjCPrototypeContext);
if (!TypeSpec.isInvalid())
Ty = TypeSpec.get();
}
@@ -821,7 +825,8 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) {
Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
tok::TokenKind mType,
Decl *IDecl,
- tok::ObjCKeywordKind MethodImplKind) {
+ tok::ObjCKeywordKind MethodImplKind,
+ bool MethodDefinition) {
ParsingDeclRAIIObject PD(*this);
if (Tok.is(tok::code_completion)) {
@@ -834,12 +839,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ParsedType ReturnType;
ObjCDeclSpec DSRet;
if (Tok.is(tok::l_paren))
- ReturnType = ParseObjCTypeName(DSRet, false);
+ ReturnType = ParseObjCTypeName(DSRet, OTN_ResultType);
// If attributes exist before the method, parse them.
- ParsedAttributes attrs;
+ ParsedAttributes methodAttrs(AttrFactory);
if (getLang().ObjC2)
- MaybeParseGNUAttributes(attrs);
+ MaybeParseGNUAttributes(methodAttrs);
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
@@ -864,7 +869,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
if (getLang().ObjC2)
- MaybeParseGNUAttributes(attrs);
+ MaybeParseGNUAttributes(methodAttrs);
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
Decl *Result
@@ -872,7 +877,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
mType, IDecl, DSRet, ReturnType, Sel,
0,
CParamInfo.data(), CParamInfo.size(),
- attrs.getList(), MethodImplKind);
+ methodAttrs.getList(), MethodImplKind,
+ false, MethodDefinition);
PD.complete(Result);
return Result;
}
@@ -881,8 +887,11 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
llvm::SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope|Scope::DeclScope);
+
+ AttributePool allParamAttrs(AttrFactory);
while (1) {
+ ParsedAttributes paramAttrs(AttrFactory);
Sema::ObjCArgInfo ArgInfo;
// Each iteration parses a single keyword argument.
@@ -894,14 +903,13 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ArgInfo.Type = ParsedType();
if (Tok.is(tok::l_paren)) // Parse the argument type if present.
- ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, true);
+ ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, OTN_ParameterType);
// If attributes exist before the argument name, parse them.
ArgInfo.ArgAttrs = 0;
if (getLang().ObjC2) {
- ParsedAttributes attrs;
- MaybeParseGNUAttributes(attrs);
- ArgInfo.ArgAttrs = attrs.getList();
+ MaybeParseGNUAttributes(paramAttrs);
+ ArgInfo.ArgAttrs = paramAttrs.getList();
}
// Code completion for the next piece of the selector.
@@ -930,6 +938,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ArgInfos.push_back(ArgInfo);
KeyIdents.push_back(SelIdent);
+ // Make sure the attributes persist.
+ allParamAttrs.takeAllFrom(paramAttrs.getPool());
+
// Code completion for the next piece of the selector.
if (Tok.is(tok::code_completion)) {
ConsumeCodeCompletionToken();
@@ -960,7 +971,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ConsumeToken();
break;
}
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseDeclarationSpecifiers(DS);
// Parse the declarator.
Declarator ParmDecl(DS, Declarator::PrototypeContext);
@@ -977,7 +988,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// FIXME: Add support for optional parameter list...
// If attributes exist after the method, parse them.
if (getLang().ObjC2)
- MaybeParseGNUAttributes(attrs);
+ MaybeParseGNUAttributes(methodAttrs);
if (KeyIdents.size() == 0) {
// Leave prototype scope.
@@ -992,8 +1003,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
mType, IDecl, DSRet, ReturnType, Sel,
&ArgInfos[0],
CParamInfo.data(), CParamInfo.size(),
- attrs.getList(),
- MethodImplKind, isVariadic);
+ methodAttrs.getList(),
+ MethodImplKind, isVariadic, MethodDefinition);
// Leave prototype scope.
PrototypeScope.Exit();
@@ -1165,7 +1176,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
} Callback(*this, interfaceDecl, visibility, AllIvarDecls);
// Parse all the comma separated declarators.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseStructDeclaration(DS, Callback);
if (Tok.is(tok::semi)) {
@@ -1376,7 +1387,7 @@ Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
}
else {
// missing @implementation
- Diag(atEnd.getBegin(), diag::warn_expected_implementation);
+ Diag(atEnd.getBegin(), diag::err_expected_implementation);
}
return Result;
}
@@ -1609,7 +1620,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
ConsumeParen();
ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
if (Tok.isNot(tok::ellipsis)) {
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseDeclarationSpecifiers(DS);
// For some odd reason, the name of the exception variable is
// optional. As a result, we need to use "PrototypeContext", because
@@ -1717,9 +1728,12 @@ Decl *Parser::ParseObjCMethodDefinition() {
// specified Declarator for the method.
Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
- if (PP.isCodeCompletionEnabled())
- if (trySkippingFunctionBodyForCodeCompletion())
+ if (PP.isCodeCompletionEnabled()) {
+ if (trySkippingFunctionBodyForCodeCompletion()) {
+ BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(MDecl, 0);
+ }
+ }
StmtResult FnBody(ParseCompoundStatementBody());
@@ -1728,12 +1742,11 @@ Decl *Parser::ParseObjCMethodDefinition() {
FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
MultiStmtArg(Actions), false);
- // TODO: Pass argument information.
- Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
-
// Leave the function body scope.
BodyScope.Exit();
-
+
+ // TODO: Pass argument information.
+ Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
return MDecl;
}
@@ -1839,7 +1852,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
// typename-specifier
// simple-type-specifier
// expression (that starts with one of the above)
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.is(tok::l_paren)) {
@@ -2337,7 +2350,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
return ExprError(Diag(Tok, diag::err_expected_colon));
++nColons;
- ConsumeToken(); // Eat the ':'.
+ ConsumeToken(); // Eat the ':' or '::'.
if (Tok.is(tok::r_paren))
break;
@@ -2353,7 +2366,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
SourceLocation Loc;
SelIdent = ParseObjCSelectorPiece(Loc);
KeyIdents.push_back(SelIdent);
- if (!SelIdent && Tok.isNot(tok::colon))
+ if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
break;
}
}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index dfd0da079df5..46225c8e7910 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -74,7 +74,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
return;
}
PP.Lex(Tok);
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "visibility";
return;
@@ -168,7 +168,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
SourceLocation RParenLoc = Tok.getLocation();
PP.Lex(Tok);
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
return;
}
@@ -177,6 +177,38 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
LParenLoc, RParenLoc);
}
+// #pragma ms_struct on
+// #pragma ms_struct off
+void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &MSStructTok) {
+ Sema::PragmaMSStructKind Kind = Sema::PMSST_OFF;
+
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct);
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II->isStr("on")) {
+ Kind = Sema::PMSST_ON;
+ PP.Lex(Tok);
+ }
+ else if (II->isStr("off") || II->isStr("reset"))
+ PP.Lex(Tok);
+ else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct);
+ return;
+ }
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "ms_struct";
+ return;
+ }
+ Actions.ActOnPragmaMSStruct(Kind);
+}
+
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
@@ -228,7 +260,7 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
SourceLocation KindLoc = Tok.getLocation();
PP.Lex(Tok);
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< (IsOptions ? "options" : "align");
return;
@@ -302,7 +334,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
}
PP.Lex(Tok);
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
"unused";
return;
@@ -359,7 +391,7 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
PP.Lex(Tok);
}
- if (Tok.isNot(tok::eom)) {
+ if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak";
return;
}
@@ -387,7 +419,7 @@ void
PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
- PP.Lex(Tok);
+ PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) <<
"OPENCL";
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index bee6af3f4cfd..1d3138fa70a8 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -58,6 +58,16 @@ public:
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) {}
+
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken);
+};
class PragmaUnusedHandler : public PragmaHandler {
Sema &Actions;
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 2d9758333f0c..f0ab53108033 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -40,6 +40,7 @@ using namespace clang;
/// jump-statement
/// [C++] declaration-statement
/// [C++] try-block
+/// [MS] seh-try-block
/// [OBC] objc-throw-statement
/// [OBC] objc-try-catch-statement
/// [OBC] objc-synchronized-statement
@@ -81,12 +82,13 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
// Cases in this switch statement should fall through if the parser expects
// the token to end in a semicolon (in which case SemiError should be set),
// or they directly 'return;' if not.
+Retry:
tok::TokenKind Kind = Tok.getKind();
SourceLocation AtLoc;
switch (Kind) {
@@ -101,13 +103,103 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
ConsumeCodeCompletionToken();
return ParseStatementOrDeclaration(Stmts, OnlyStatement);
- case tok::identifier:
- if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
+ case tok::identifier: {
+ Token Next = NextToken();
+ if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
return ParseLabeledStatement(attrs);
}
- // PASS THROUGH.
-
+
+ if (Next.isNot(tok::coloncolon)) {
+ CXXScopeSpec SS;
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = Tok.getLocation();
+ 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:
+ // 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, Id, SourceLocation(),
+ /*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;
+ }
+ }
+
+ // Fall through
+ }
+
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
@@ -121,21 +213,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
return StmtError();
}
- // FIXME: Use the attributes
- // expression[opt] ';'
- ExprResult Expr(ParseExpression());
- if (Expr.isInvalid()) {
- // If the expression is invalid, skip ahead to the next semicolon or '}'.
- // Not doing this opens us up to the possibility of infinite loops if
- // ParseExpression does not consume any tokens.
- SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return StmtError();
- }
- // Otherwise, eat the semicolon.
- ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+ return ParseExprStatement(attrs);
}
case tok::kw_case: // C99 6.8.1: labeled-statement
@@ -146,8 +224,10 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
case tok::l_brace: // C99 6.8.2: compound-statement
return ParseCompoundStatement(attrs);
case tok::semi: { // C99 6.8.3p3: expression[opt] ';'
- bool LeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
- return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacro);
+ SourceLocation LeadingEmptyMacroLoc;
+ if (Tok.hasLeadingEmptyMacro())
+ LeadingEmptyMacroLoc = PP.getLastEmptyMacroInstantiationLoc();
+ return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacroLoc);
}
case tok::kw_if: // C99 6.8.4.1: if-statement
@@ -193,6 +273,9 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
case tok::kw_try: // C++ 15: try-block
return ParseCXXTryBlock(attrs);
+
+ case tok::kw___try:
+ return ParseSEHTryBlock(attrs);
}
// If we reached this code, the statement must end in a semicolon.
@@ -210,6 +293,145 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
return move(Res);
}
+/// \brief Parse an expression statement.
+StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) {
+ // If a case keyword is missing, this is where it should be inserted.
+ Token OldToken = Tok;
+
+ // FIXME: Use the attributes
+ // expression[opt] ';'
+ ExprResult Expr(ParseExpression());
+ if (Expr.isInvalid()) {
+ // If the expression is invalid, skip ahead to the next semicolon or '}'.
+ // Not doing this opens us up to the possibility of infinite loops if
+ // ParseExpression does not consume any tokens.
+ SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return StmtError();
+ }
+
+ if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
+ Actions.CheckCaseExpression(Expr.get())) {
+ // If a constant expression is followed by a colon inside a switch block,
+ // suggest a missing case keyword.
+ Diag(OldToken, diag::err_expected_case_before_expression)
+ << FixItHint::CreateInsertion(OldToken.getLocation(), "case ");
+
+ // Recover parsing as a case statement.
+ return ParseCaseStatement(Attrs, /*MissingCase=*/true, Expr);
+ }
+
+ // Otherwise, eat the semicolon.
+ ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
+ return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+}
+
+StmtResult Parser::ParseSEHTryBlock(ParsedAttributes & Attrs) {
+ assert(Tok.is(tok::kw___try) && "Expected '__try'");
+ SourceLocation Loc = ConsumeToken();
+ return ParseSEHTryBlockCommon(Loc);
+}
+
+/// ParseSEHTryBlockCommon
+///
+/// seh-try-block:
+/// '__try' compound-statement seh-handler
+///
+/// seh-handler:
+/// seh-except-block
+/// seh-finally-block
+///
+StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
+ if(Tok.isNot(tok::l_brace))
+ return StmtError(Diag(Tok,diag::err_expected_lbrace));
+
+ ParsedAttributesWithRange attrs(AttrFactory);
+ StmtResult TryBlock(ParseCompoundStatement(attrs));
+ if(TryBlock.isInvalid())
+ return move(TryBlock);
+
+ StmtResult Handler;
+ if(Tok.is(tok::kw___except)) {
+ SourceLocation Loc = ConsumeToken();
+ Handler = ParseSEHExceptBlock(Loc);
+ } else if (Tok.is(tok::kw___finally)) {
+ SourceLocation Loc = ConsumeToken();
+ Handler = ParseSEHFinallyBlock(Loc);
+ } else {
+ return StmtError(Diag(Tok,diag::err_seh_expected_handler));
+ }
+
+ if(Handler.isInvalid())
+ return move(Handler);
+
+ return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
+ TryLoc,
+ TryBlock.take(),
+ Handler.take());
+}
+
+/// ParseSEHExceptBlock - Handle __except
+///
+/// seh-except-block:
+/// '__except' '(' seh-filter-expression ')' compound-statement
+///
+StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
+ PoisonIdentifierRAIIObject raii(Ident__exception_code, false),
+ raii2(Ident___exception_code, false),
+ raii3(Ident_GetExceptionCode, false);
+
+ if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen))
+ return StmtError();
+
+ ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope);
+
+ if (getLang().Borland) {
+ Ident__exception_info->setIsPoisoned(false);
+ Ident___exception_info->setIsPoisoned(false);
+ Ident_GetExceptionInfo->setIsPoisoned(false);
+ }
+ ExprResult FilterExpr(ParseExpression());
+
+ if (getLang().Borland) {
+ Ident__exception_info->setIsPoisoned(true);
+ Ident___exception_info->setIsPoisoned(true);
+ Ident_GetExceptionInfo->setIsPoisoned(true);
+ }
+
+ if(FilterExpr.isInvalid())
+ return StmtError();
+
+ if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen))
+ return StmtError();
+
+ ParsedAttributesWithRange attrs(AttrFactory);
+ StmtResult Block(ParseCompoundStatement(attrs));
+
+ if(Block.isInvalid())
+ return move(Block);
+
+ return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take());
+}
+
+/// ParseSEHFinallyBlock - Handle __finally
+///
+/// seh-finally-block:
+/// '__finally' compound-statement
+///
+StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) {
+ PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false),
+ raii2(Ident___abnormal_termination, false),
+ raii3(Ident_AbnormalTermination, false);
+
+ ParsedAttributesWithRange attrs(AttrFactory);
+ StmtResult Block(ParseCompoundStatement(attrs));
+ if(Block.isInvalid())
+ return move(Block);
+
+ return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take());
+}
+
/// ParseLabeledStatement - We have an identifier and a ':' after it.
///
/// labeled-statement:
@@ -251,8 +473,9 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) {
/// 'case' constant-expression ':' statement
/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
///
-StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) {
- assert(Tok.is(tok::kw_case) && "Not a case stmt!");
+StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
+ ExprResult Expr) {
+ assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!");
// FIXME: Use attributes?
// It is very very common for code to contain many case statements recursively
@@ -280,7 +503,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) {
// While we have case statements, eat and stack them.
do {
- SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'.
+ SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() :
+ ConsumeToken(); // eat the 'case'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCase(getCurScope());
@@ -292,7 +516,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) {
/// expression.
ColonProtectionRAIIObject ColonProtection(*this);
- ExprResult LHS(ParseConstantExpression());
+ ExprResult LHS(MissingCase ? Expr : ParseConstantExpression());
+ MissingCase = false;
if (LHS.isInvalid()) {
SkipUntil(tok::colon);
return StmtError();
@@ -493,14 +718,14 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
- DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, true));
+ DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc));
if (!Tok.is(tok::comma))
break;
ConsumeToken();
}
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS,
DeclsInGroup.data(), DeclsInGroup.size());
StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation());
@@ -528,7 +753,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
while (Tok.is(tok::kw___extension__))
ConsumeToken();
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
// If this is the start of a declaration, parse it as such.
@@ -775,7 +1000,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
// while, for, and switch statements are local to the if, while, for, or
// switch statement (including the controlled statement).
//
- unsigned ScopeFlags = Scope::BreakScope;
+ unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
ParseScope SwitchScope(this, ScopeFlags);
@@ -977,6 +1202,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
/// [C++] statement
+/// [C++0x] 'for' '(' for-range-declaration : for-range-initializer ) statement
/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
/// [OBJC2] 'for' '(' expr 'in' expr ')' statement
///
@@ -984,6 +1210,11 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
/// [C++] expression-statement
/// [C++] simple-declaration
///
+/// [C++0x] for-range-declaration:
+/// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator
+/// [C++0x] for-range-initializer:
+/// [C++0x] expression
+/// [C++0x] braced-init-list [TODO]
StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
// FIXME: Use attributes?
@@ -1025,11 +1256,12 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
SourceLocation LParenLoc = ConsumeParen();
ExprResult Value;
- bool ForEach = false;
+ bool ForEach = false, ForRange = false;
StmtResult FirstPart;
bool SecondPartIsInvalid = false;
FullExprArg SecondPart(Actions);
ExprResult Collection;
+ ForRangeInit ForRangeInit;
FullExprArg ThirdPart(Actions);
Decl *SecondVar = 0;
@@ -1049,16 +1281,24 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
+ // In C++0x, "for (T NS:a" might not be a typo for ::
+ bool MightBeForRangeStmt = getLang().CPlusPlus;
+ ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
+
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
StmtVector Stmts(Actions);
DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
- DeclEnd, attrs, false);
+ DeclEnd, attrs, false,
+ MightBeForRangeStmt ?
+ &ForRangeInit : 0);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
- if (Tok.is(tok::semi)) { // for (int x = 4;
+ if (ForRangeInit.ParsedForRangeDecl()) {
+ ForRange = true;
+ } else if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
Actions.ActOnForEachDeclStmt(DG);
@@ -1107,7 +1347,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
}
}
}
- if (!ForEach) {
+ if (!ForEach && !ForRange) {
assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
// Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;;
@@ -1149,6 +1389,17 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
// Match the ')'.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ // We need to perform most of the semantic analysis for a C++0x for-range
+ // statememt before parsing the body, in order to be able to deduce the type
+ // of an auto-typed loop variable.
+ StmtResult ForRangeStmt;
+ if (ForRange)
+ ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, LParenLoc,
+ FirstPart.take(),
+ ForRangeInit.ColonLoc,
+ ForRangeInit.RangeExpr.get(),
+ RParenLoc);
+
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases.
@@ -1175,15 +1426,19 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
if (Body.isInvalid())
return StmtError();
- if (!ForEach)
- return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart,
- SecondVar, ThirdPart, RParenLoc, Body.take());
+ if (ForEach)
+ // FIXME: It isn't clear how to communicate the late destruction of
+ // C++ temporaries used to create the collection.
+ return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
+ FirstPart.take(),
+ Collection.take(), RParenLoc,
+ Body.take());
+
+ if (ForRange)
+ return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take());
- // FIXME: It isn't clear how to communicate the late destruction of
- // C++ temporaries used to create the collection.
- return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(),
- Collection.take(), RParenLoc,
- Body.take());
+ return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart,
+ SecondVar, ThirdPart, RParenLoc, Body.take());
}
/// ParseGotoStatement
@@ -1267,7 +1522,16 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) {
return StmtError();
}
- R = ParseExpression();
+ // FIXME: This is a hack to allow something like C++0x's generalized
+ // initializer lists, but only enough of this feature to allow Clang to
+ // parse libstdc++ 4.5's headers.
+ if (Tok.is(tok::l_brace) && getLang().CPlusPlus) {
+ R = ParseInitializer();
+ if (R.isUsable() && !getLang().CPlusPlus0x)
+ Diag(R.get()->getLocStart(), diag::ext_generalized_initializer_lists)
+ << R.get()->getSourceRange();
+ } else
+ R = ParseExpression();
if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
SkipUntil(tok::semi, false, true);
return StmtError();
@@ -1350,7 +1614,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
msAsm = true;
return FuzzyParseMicrosoftAsmStatement(AsmLoc);
}
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
SourceLocation Loc = Tok.getLocation();
ParseTypeQualifierListOpt(DS, true, false);
@@ -1522,14 +1786,17 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
return true;
}
-Decl *Parser::ParseFunctionStatementBody(Decl *Decl) {
+Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
- if (PP.isCodeCompletionEnabled())
- if (trySkippingFunctionBodyForCodeCompletion())
+ if (PP.isCodeCompletionEnabled()) {
+ if (trySkippingFunctionBodyForCodeCompletion()) {
+ BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, 0);
-
+ }
+ }
+
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
"parsing function body");
@@ -1543,6 +1810,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) {
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
+ BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
}
@@ -1551,7 +1819,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) {
/// function-try-block:
/// 'try' ctor-initializer[opt] compound-statement handler-seq
///
-Decl *Parser::ParseFunctionTryBlock(Decl *Decl) {
+Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
@@ -1562,9 +1830,12 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) {
if (Tok.is(tok::colon))
ParseConstructorInitializer(Decl);
- if (PP.isCodeCompletionEnabled())
- if (trySkippingFunctionBodyForCodeCompletion())
+ if (PP.isCodeCompletionEnabled()) {
+ if (trySkippingFunctionBodyForCodeCompletion()) {
+ BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, 0);
+ }
+ }
SourceLocation LBraceLoc = Tok.getLocation();
StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
@@ -1574,6 +1845,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) {
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
+ BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
}
@@ -1622,32 +1894,58 @@ StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) {
/// handler-seq:
/// handler handler-seq[opt]
///
+/// [Borland] try-block:
+/// 'try' compound-statement seh-except-block
+/// 'try' compound-statment seh-finally-block
+///
StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected_lbrace));
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
StmtResult TryBlock(ParseCompoundStatement(attrs));
if (TryBlock.isInvalid())
return move(TryBlock);
- StmtVector Handlers(Actions);
- MaybeParseCXX0XAttributes(attrs);
- ProhibitAttributes(attrs);
-
- if (Tok.isNot(tok::kw_catch))
- return StmtError(Diag(Tok, diag::err_expected_catch));
- while (Tok.is(tok::kw_catch)) {
- StmtResult Handler(ParseCXXCatchBlock());
- if (!Handler.isInvalid())
- Handlers.push_back(Handler.release());
+ // Borland allows SEH-handlers with 'try'
+ if(Tok.is(tok::kw___except) || Tok.is(tok::kw___finally)) {
+ // TODO: Factor into common return ParseSEHHandlerCommon(...)
+ StmtResult Handler;
+ if(Tok.is(tok::kw___except)) {
+ SourceLocation Loc = ConsumeToken();
+ Handler = ParseSEHExceptBlock(Loc);
+ }
+ else {
+ SourceLocation Loc = ConsumeToken();
+ Handler = ParseSEHFinallyBlock(Loc);
+ }
+ if(Handler.isInvalid())
+ return move(Handler);
+
+ return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
+ TryLoc,
+ TryBlock.take(),
+ Handler.take());
}
- // Don't bother creating the full statement if we don't have any usable
- // handlers.
- if (Handlers.empty())
- return StmtError();
+ else {
+ StmtVector Handlers(Actions);
+ MaybeParseCXX0XAttributes(attrs);
+ ProhibitAttributes(attrs);
+
+ if (Tok.isNot(tok::kw_catch))
+ return StmtError(Diag(Tok, diag::err_expected_catch));
+ while (Tok.is(tok::kw_catch)) {
+ StmtResult Handler(ParseCXXCatchBlock());
+ if (!Handler.isInvalid())
+ Handlers.push_back(Handler.release());
+ }
+ // Don't bother creating the full statement if we don't have any usable
+ // handlers.
+ if (Handlers.empty())
+ return StmtError();
- return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers));
+ return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers));
+ }
}
/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
@@ -1679,7 +1977,7 @@ StmtResult Parser::ParseCXXCatchBlock() {
// without default arguments.
Decl *ExceptionDecl = 0;
if (Tok.isNot(tok::ellipsis)) {
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
if (ParseCXXTypeSpecifierSeq(DS))
return StmtError();
Declarator ExDecl(DS, Declarator::CXXCatchContext);
@@ -1695,7 +1993,7 @@ StmtResult Parser::ParseCXXCatchBlock() {
return StmtError(Diag(Tok, diag::err_expected_lbrace));
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
StmtResult Block(ParseCompoundStatement(attrs));
if (Block.isInvalid())
return move(Block);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 59ced8b07fc5..12e38daf0029 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -17,6 +17,8 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTConsumer.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
@@ -196,7 +198,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
return 0;
}
- ParsedAttributesWithRange prefixAttrs;
+ ParsedAttributesWithRange prefixAttrs(AttrFactory);
MaybeParseCXX0XAttributes(prefixAttrs);
if (Tok.is(tok::kw_using))
@@ -205,7 +207,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
// Parse the declaration specifiers, stealing the accumulated
// diagnostics from the template parameters.
- ParsingDeclSpec DS(DiagsFromTParams);
+ ParsingDeclSpec DS(*this, &DiagsFromTParams);
DS.takeAttributesFrom(prefixAttrs);
@@ -598,7 +600,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// Parse the declaration-specifiers (i.e., the type).
// FIXME: The type should probably be restricted in some way... Not all
// declarators (parts of declarators?) are accepted for parameters.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseDeclarationSpecifiers(DS);
// Parse this as a typename.
@@ -661,7 +663,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
bool
Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
SourceLocation TemplateNameLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
@@ -756,7 +758,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
/// formed, this function returns true.
///
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
- const CXXScopeSpec *SS,
+ CXXScopeSpec &SS,
UnqualifiedId &TemplateName,
SourceLocation TemplateKWLoc,
bool AllowTypeAnnotation) {
@@ -790,7 +792,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
TypeResult Type
- = Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
+ = Actions.ActOnTemplateIdType(SS,
+ Template, TemplateNameLoc,
LAngleLoc, TemplateArgsPtr,
RAngleLoc);
if (Type.isInvalid()) {
@@ -803,8 +806,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.get());
- if (SS && SS->isNotEmpty())
- Tok.setLocation(SS->getBeginLoc());
+ if (SS.isNotEmpty())
+ Tok.setLocation(SS.getBeginLoc());
else if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
else
@@ -823,6 +826,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateId->Name = 0;
TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
}
+ TemplateId->SS = SS;
TemplateId->Template = Template;
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
@@ -854,7 +858,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
/// If there was a failure when forming the type from the template-id,
/// a type annotation token will still be created, but will have a
/// NULL type pointer to signify an error.
-void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
+void Parser::AnnotateTemplateIdTokenAsType() {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
TemplateIdAnnotation *TemplateId
@@ -868,7 +872,8 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
TemplateId->NumArgs);
TypeResult Type
- = Actions.ActOnTemplateIdType(TemplateId->Template,
+ = Actions.ActOnTemplateIdType(TemplateId->SS,
+ TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
@@ -876,8 +881,8 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get());
- if (SS && SS->isNotEmpty()) // it was a C++ qualified type name.
- Tok.setLocation(SS->getBeginLoc());
+ if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(TemplateId->SS.getBeginLoc());
// End location stays the same
// Replace the template-id annotation token, and possible the scope-specifier
@@ -1122,3 +1127,125 @@ SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
R.setBegin(ExternLoc);
return R;
}
+
+void Parser::LateTemplateParserCallback(void *P, const FunctionDecl *FD) {
+ ((Parser*)P)->LateTemplateParser(FD);
+}
+
+
+void Parser::LateTemplateParser(const FunctionDecl *FD) {
+ LateParsedTemplatedFunction *LPT = LateParsedTemplateMap[FD];
+ if (LPT) {
+ ParseLateTemplatedFuncDef(*LPT);
+ return;
+ }
+
+ llvm_unreachable("Late templated function without associated lexed tokens");
+}
+
+/// \brief Late parse a C++ function template in Microsoft mode.
+void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
+ if(!LMT.D)
+ return;
+
+ // If this is a member template, introduce the template parameter scope.
+ ParseScope TemplateScope(this, Scope::TemplateParamScope);
+
+ // Get the FunctionDecl.
+ FunctionDecl *FD = 0;
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D))
+ FD = FunTmpl->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(LMT.D);
+
+ // Reinject the template parameters.
+ DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD);
+ if (Declarator && Declarator->getNumTemplateParameterLists() != 0) {
+ Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
+ Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
+ } else {
+ Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
+
+ DeclContext *DD = FD->getLexicalParent();
+ while (DD && DD->isRecord()) {
+ if (ClassTemplatePartialSpecializationDecl* MD =
+ dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(DD))
+ Actions.ActOnReenterTemplateScope(getCurScope(), MD);
+ else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(DD))
+ Actions.ActOnReenterTemplateScope(getCurScope(),
+ MD->getDescribedClassTemplate());
+
+ DD = DD->getLexicalParent();
+ }
+ }
+ assert(!LMT.Toks.empty() && "Empty body!");
+
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ LMT.Toks.push_back(Tok);
+ PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
+ && "Inline method not starting with '{', ':' or 'try'");
+
+ // Parse the method body. Function body parsing code is similar enough
+ // to be re-used for method bodies as well.
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
+
+ // Recreate the DeclContext.
+ Sema::ContextRAII SavedContext(Actions, Actions.getContainingDC(FD));
+
+ if (FunctionTemplateDecl *FunctionTemplate
+ = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D))
+ Actions.ActOnStartOfFunctionDef(getCurScope(),
+ FunctionTemplate->getTemplatedDecl());
+ if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D))
+ Actions.ActOnStartOfFunctionDef(getCurScope(), Function);
+
+
+ if (Tok.is(tok::kw_try)) {
+ ParseFunctionTryBlock(LMT.D, FnScope);
+ return;
+ }
+ if (Tok.is(tok::colon)) {
+ ParseConstructorInitializer(LMT.D);
+
+ // Error recovery.
+ if (!Tok.is(tok::l_brace)) {
+ Actions.ActOnFinishFunctionBody(LMT.D, 0);
+ return;
+ }
+ } else
+ Actions.ActOnDefaultCtorInitializers(LMT.D);
+
+ ParseFunctionStatementBody(LMT.D, FnScope);
+ Actions.MarkAsLateParsedTemplate(FD, false);
+
+ DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D);
+ if (grp)
+ Actions.getASTConsumer().HandleTopLevelDecl(grp.get());
+}
+
+/// \brief Lex a delayed template function for late parsing.
+void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
+ tok::TokenKind kind = Tok.getKind();
+ // We may have a constructor initializer or function-try-block here.
+ if (kind == tok::colon || kind == tok::kw_try)
+ ConsumeAndStoreUntil(tok::l_brace, Toks);
+ else {
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ }
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
+
+ // If we're in a function-try-block, we need to store all the catch blocks.
+ if (kind == tok::kw_try) {
+ while (Tok.is(tok::kw_catch)) {
+ ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
+ }
+ }
+}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index a603c37a53e5..1c4e2b3ddc8b 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -58,6 +58,7 @@ bool Parser::isCXXDeclarationStatement() {
case tok::kw_using:
// static_assert-declaration
case tok::kw_static_assert:
+ case tok::kw__Static_assert:
return true;
// simple-declaration
default:
@@ -658,10 +659,12 @@ 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_literal:
+ case tok::kw___is_literal_type:
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
+ case tok::kw___is_trivial:
case tok::kw___is_union:
- case tok::kw___is_literal:
case tok::kw___uuidof:
return TPResult::True();
@@ -673,6 +676,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_float:
case tok::kw_int:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_restrict:
case tok::kw_short:
case tok::kw_signed:
@@ -907,7 +911,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
if (TemplateId->Kind != TNK_Type_template)
return TPResult::False();
CXXScopeSpec SS;
- AnnotateTemplateIdTokenAsType(&SS);
+ AnnotateTemplateIdTokenAsType();
assert(Tok.is(tok::annot_typename));
goto case_typename;
}
@@ -968,6 +972,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_short:
case tok::kw_int:
case tok::kw_long:
+ case tok::kw___int64:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_float:
@@ -1151,7 +1156,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() {
return TPResult::True(); // '...' is a sign of a function declarator.
}
- ParsedAttributes attrs;
+ ParsedAttributes attrs(AttrFactory);
MaybeParseMicrosoftAttributes(attrs);
// decl-specifier-seq
@@ -1238,6 +1243,16 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
if (!SkipUntil(tok::r_paren))
return TPResult::Error();
}
+ if (Tok.is(tok::kw_noexcept)) {
+ ConsumeToken();
+ // Possibly an expression as well.
+ if (Tok.is(tok::l_paren)) {
+ // Find the matching rparen.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ }
+ }
return TPResult::Ambiguous();
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 07e592cdb05b..4d08699bdd39 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -19,10 +19,11 @@
#include "llvm/Support/raw_ostream.h"
#include "RAIIObjectsForParser.h"
#include "ParsePragma.h"
+#include "clang/AST/DeclTemplate.h"
using namespace clang;
Parser::Parser(Preprocessor &pp, Sema &actions)
- : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
+ : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
GreaterThanIsOperator(true), ColonIsSacred(false),
InMessageExpression(false), TemplateParameterDepth(0) {
Tok.setKind(tok::eof);
@@ -44,6 +45,9 @@ Parser::Parser(Preprocessor &pp, Sema &actions)
PackHandler.reset(new PragmaPackHandler(actions));
PP.AddPragmaHandler(PackHandler.get());
+
+ MSStructHandler.reset(new PragmaMSStructHandler(actions));
+ PP.AddPragmaHandler(MSStructHandler.get());
UnusedHandler.reset(new PragmaUnusedHandler(actions, *this));
PP.AddPragmaHandler(UnusedHandler.get());
@@ -362,6 +366,11 @@ Parser::~Parser() {
for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
delete ScopeCache[i];
+ // Free LateParsedTemplatedFunction nodes.
+ for (LateParsedTemplateMapT::iterator it = LateParsedTemplateMap.begin();
+ it != LateParsedTemplateMap.end(); ++it)
+ delete it->second;
+
// Remove the pragma handlers we installed.
PP.RemovePragmaHandler(AlignHandler.get());
AlignHandler.reset();
@@ -371,6 +380,8 @@ Parser::~Parser() {
OptionsHandler.reset();
PP.RemovePragmaHandler(PackHandler.get());
PackHandler.reset();
+ PP.RemovePragmaHandler(MSStructHandler.get());
+ MSStructHandler.reset();
PP.RemovePragmaHandler(UnusedHandler.get());
UnusedHandler.reset();
PP.RemovePragmaHandler(WeakHandler.get());
@@ -422,6 +433,37 @@ void Parser::Initialize() {
Ident_vector = &PP.getIdentifierTable().get("vector");
Ident_pixel = &PP.getIdentifierTable().get("pixel");
}
+
+ Ident_introduced = 0;
+ Ident_deprecated = 0;
+ Ident_obsoleted = 0;
+ Ident_unavailable = 0;
+
+ Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0;
+ Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0;
+ Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0;
+
+ if(getLang().Borland) {
+ Ident__exception_info = PP.getIdentifierInfo("_exception_info");
+ Ident___exception_info = PP.getIdentifierInfo("__exception_info");
+ Ident_GetExceptionInfo = PP.getIdentifierInfo("GetExceptionInformation");
+ Ident__exception_code = PP.getIdentifierInfo("_exception_code");
+ Ident___exception_code = PP.getIdentifierInfo("__exception_code");
+ Ident_GetExceptionCode = PP.getIdentifierInfo("GetExceptionCode");
+ Ident__abnormal_termination = PP.getIdentifierInfo("_abnormal_termination");
+ Ident___abnormal_termination = PP.getIdentifierInfo("__abnormal_termination");
+ Ident_AbnormalTermination = PP.getIdentifierInfo("AbnormalTermination");
+
+ PP.SetPoisonReason(Ident__exception_code,diag::err_seh___except_block);
+ PP.SetPoisonReason(Ident___exception_code,diag::err_seh___except_block);
+ PP.SetPoisonReason(Ident_GetExceptionCode,diag::err_seh___except_block);
+ PP.SetPoisonReason(Ident__exception_info,diag::err_seh___except_filter);
+ PP.SetPoisonReason(Ident___exception_info,diag::err_seh___except_filter);
+ PP.SetPoisonReason(Ident_GetExceptionInfo,diag::err_seh___except_filter);
+ PP.SetPoisonReason(Ident__abnormal_termination,diag::err_seh___finally_block);
+ PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block);
+ PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block);
+ }
}
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
@@ -433,11 +475,15 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
Result = DeclGroupPtrTy();
if (Tok.is(tok::eof)) {
+ // Late template parsing can begin.
+ if (getLang().DelayedTemplateParsing)
+ Actions.SetLateTemplateParser(LateTemplateParserCallback, this);
+
Actions.ActOnEndOfTranslationUnit();
return true;
}
- ParsedAttributesWithRange attrs;
+ ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
@@ -513,14 +559,16 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::kw_asm: {
ProhibitAttributes(attrs);
- ExprResult Result(ParseSimpleAsm());
+ SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+ ExprResult Result(ParseSimpleAsm(&EndLoc));
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
"top-level asm block");
if (Result.isInvalid())
return DeclGroupPtrTy();
- SingleDecl = Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), Result.get());
+ SingleDecl = Actions.ActOnFileScopeAsmDecl(Result.get(), StartLoc, EndLoc);
break;
}
case tok::at:
@@ -550,6 +598,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::kw_template:
case tok::kw_export: // As in 'export template'
case tok::kw_static_assert:
+ case tok::kw__Static_assert:
// A function definition cannot start with a these keywords.
{
SourceLocation DeclEnd;
@@ -743,6 +792,8 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
///
Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo) {
+ // Poison the SEH identifiers so they are flagged as illegal in function bodies
+ PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
// If this is C90 and the declspecs were completely missing, fudge in an
@@ -778,6 +829,44 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return 0;
}
+ // In delayed template parsing mode, for function template we consume the
+ // tokens and store them for late parsing at the end of the translation unit.
+ if (getLang().DelayedTemplateParsing &&
+ TemplateInfo.Kind == ParsedTemplateInfo::Template) {
+ MultiTemplateParamsArg TemplateParameterLists(Actions,
+ TemplateInfo.TemplateParams->data(),
+ TemplateInfo.TemplateParams->size());
+
+ ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+ Scope *ParentScope = getCurScope()->getParent();
+
+ Decl *DP = Actions.HandleDeclarator(ParentScope, D,
+ move(TemplateParameterLists),
+ /*IsFunctionDefinition=*/true);
+ D.complete(DP);
+ D.getMutableDeclSpec().abort();
+
+ if (DP) {
+ LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(this, DP);
+
+ FunctionDecl *FnD = 0;
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP))
+ FnD = FunTmpl->getTemplatedDecl();
+ else
+ FnD = cast<FunctionDecl>(DP);
+ Actions.CheckForFunctionRedefinition(FnD);
+
+ LateParsedTemplateMap[FnD] = LPT;
+ Actions.MarkAsLateParsedTemplate(FnD);
+ LexTemplateFunctionForLateParsing(LPT->Toks);
+ } else {
+ CachedTokens Toks;
+ LexTemplateFunctionForLateParsing(Toks);
+ }
+ return DP;
+ }
+
+
// Enter a scope for the function body.
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
@@ -799,7 +888,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
D.getMutableDeclSpec().abort();
if (Tok.is(tok::kw_try))
- return ParseFunctionTryBlock(Res);
+ return ParseFunctionTryBlock(Res, BodyScope);
// If we have a colon, then we're probably parsing a C++
// ctor-initializer.
@@ -808,13 +897,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Recover from error.
if (!Tok.is(tok::l_brace)) {
+ BodyScope.Exit();
Actions.ActOnFinishFunctionBody(Res, 0);
return Res;
}
} else
Actions.ActOnDefaultCtorInitializers(Res);
- return ParseFunctionStatementBody(Res);
+ return ParseFunctionStatementBody(Res, BodyScope);
}
/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
@@ -832,7 +922,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
SourceLocation DSStart = Tok.getLocation();
// Parse the common declaration-specifiers piece.
- DeclSpec DS;
+ DeclSpec DS(AttrFactory);
ParseDeclarationSpecifiers(DS);
// C99 6.9.1p6: 'each declaration in the declaration list shall have at
@@ -1029,10 +1119,14 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
// simple-template-id
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false))
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false,
+ 0, /*IsTypename*/true))
return true;
if (!SS.isSet()) {
- Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
+ if (getLang().Microsoft)
+ Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename);
+ else
+ Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
return true;
}
@@ -1051,15 +1145,18 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
return true;
}
- AnnotateTemplateIdTokenAsType(0);
- assert(Tok.is(tok::annot_typename) &&
- "AnnotateTemplateIdTokenAsType isn't working properly");
- if (Tok.getAnnotationValue())
- Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
- SourceLocation(),
- getTypeAnnotation(Tok));
- else
- Ty = true;
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+
+ Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
+ /*FIXME:*/SourceLocation(),
+ TemplateId->Template,
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->RAngleLoc);
+ TemplateId->Destroy();
} else {
Diag(Tok, diag::err_expected_type_name_after_typename)
<< SS.getRange();
@@ -1088,7 +1185,9 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope(),
&SS, false,
- NextToken().is(tok::period))) {
+ NextToken().is(tok::period),
+ ParsedType(),
+ /*NonTrivialTypeSourceInfo*/true)) {
// This is a typename. Replace the current token in-place with an
// annotation type token.
Tok.setKind(tok::annot_typename);
@@ -1124,7 +1223,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
Template, MemberOfUnknownSpecialization)) {
// Consume the identifier.
ConsumeToken();
- if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) {
+ if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName)) {
// If an unrecoverable error occurred, we need to return true here,
// because the token stream is in a damaged state. We may not return
// a valid identifier.
@@ -1147,7 +1246,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
// template-id annotation in a context where we weren't allowed
// to produce a type annotation token. Update the template-id
// annotation token to a type annotation token now.
- AnnotateTemplateIdTokenAsType(&SS);
+ AnnotateTemplateIdTokenAsType();
return false;
}
}
@@ -1184,7 +1283,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
assert(getLang().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
- assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
+ assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)))&&
"Cannot be a type or scope token!");
CXXScopeSpec SS;
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 583f18428d68..3765f92348ea 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -112,7 +112,31 @@ namespace clang {
P.BraceCount = BraceCount;
}
};
-
+
+ class PoisonSEHIdentifiersRAIIObject {
+ PoisonIdentifierRAIIObject Ident_AbnormalTermination;
+ PoisonIdentifierRAIIObject Ident_GetExceptionCode;
+ PoisonIdentifierRAIIObject Ident_GetExceptionInfo;
+ PoisonIdentifierRAIIObject Ident__abnormal_termination;
+ PoisonIdentifierRAIIObject Ident__exception_code;
+ PoisonIdentifierRAIIObject Ident__exception_info;
+ PoisonIdentifierRAIIObject Ident___abnormal_termination;
+ PoisonIdentifierRAIIObject Ident___exception_code;
+ PoisonIdentifierRAIIObject Ident___exception_info;
+ public:
+ PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue)
+ : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue),
+ Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue),
+ Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue),
+ Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue),
+ Ident__exception_code(Self.Ident__exception_code, NewValue),
+ Ident__exception_info(Self.Ident__exception_info, NewValue),
+ Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue),
+ Ident___exception_code(Self.Ident___exception_code, NewValue),
+ Ident___exception_info(Self.Ident___exception_info, NewValue) {
+ }
+ };
+
} // end namespace clang
#endif
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index 0263f657a6e3..d6e34ef8fa46 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -1426,7 +1426,8 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
RecName += "_IMPL";
IdentifierInfo *II = &Context->Idents.get(RecName);
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), II);
+ SourceLocation(), SourceLocation(),
+ II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
@@ -1472,7 +1473,8 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
RecName += "_IMPL";
IdentifierInfo *II = &Context->Idents.get(RecName);
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), II);
+ SourceLocation(), SourceLocation(),
+ II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
@@ -2109,7 +2111,8 @@ Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
std::string StrEncoding;
Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);
Expr *Replacement = StringLiteral::Create(*Context,StrEncoding.c_str(),
- StrEncoding.length(), false,StrType,
+ StrEncoding.length(),
+ false, false, StrType,
SourceLocation());
ReplaceStmt(Exp, Replacement);
@@ -2128,7 +2131,8 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
SelExprs.push_back(StringLiteral::Create(*Context,
Exp->getSelector().getAsString().c_str(),
Exp->getSelector().getAsString().size(),
- false, argType, SourceLocation()));
+ false, false, argType,
+ SourceLocation()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size());
ReplaceStmt(Exp, SelExp);
@@ -2361,6 +2365,7 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
SelGetUidIdent, getFuncType, 0,
SC_Extern,
SC_None, false);
@@ -2457,6 +2462,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
&ArgTys[0], ArgTys.size());
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
msgSendIdent, msgSendType, 0,
SC_Extern,
SC_None, false);
@@ -2477,6 +2483,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
true /*isVariadic*/);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
msgSendIdent, msgSendType, 0,
SC_Extern,
SC_None, false);
@@ -2487,7 +2494,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
llvm::SmallVector<QualType, 16> ArgTys;
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Context->Idents.get("objc_super"));
QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
@@ -2500,6 +2507,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
true /*isVariadic*/);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
msgSendIdent, msgSendType, 0,
SC_Extern,
SC_None, false);
@@ -2520,6 +2528,7 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
true /*isVariadic*/);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
msgSendIdent, msgSendType, 0,
SC_Extern,
SC_None, false);
@@ -2532,7 +2541,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
&Context->Idents.get("objc_msgSendSuper_stret");
llvm::SmallVector<QualType, 16> ArgTys;
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Context->Idents.get("objc_super"));
QualType argT = Context->getPointerType(Context->getTagDeclType(RD));
assert(!argT.isNull() && "Can't build 'struct objc_super *' type");
@@ -2545,6 +2554,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
true /*isVariadic*/);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
msgSendIdent, msgSendType, 0,
SC_Extern,
SC_None, false);
@@ -2565,6 +2575,7 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
true /*isVariadic*/);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
msgSendIdent, msgSendType, 0,
SC_Extern,
SC_None, false);
@@ -2579,6 +2590,7 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
&ArgTys[0], ArgTys.size());
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
getClassIdent, getClassType, 0,
SC_Extern,
SC_None, false);
@@ -2594,6 +2606,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
&ArgTys[0], ArgTys.size());
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
getSuperClassIdent,
getClassType, 0,
SC_Extern,
@@ -2610,6 +2623,7 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
&ArgTys[0], ArgTys.size());
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
+ SourceLocation(),
getClassIdent, getClassType, 0,
SC_Extern,
SC_None, false);
@@ -2645,8 +2659,8 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- &Context->Idents.get(S), strType, 0,
- SC_Static, SC_None);
+ SourceLocation(), &Context->Idents.get(S),
+ strType, 0, SC_Static, SC_None);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -2665,7 +2679,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
QualType RewriteObjC::getSuperStructType() {
if (!SuperStructDecl) {
SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Context->Idents.get("objc_super"));
QualType FieldTypes[2];
@@ -2677,6 +2691,7 @@ QualType RewriteObjC::getSuperStructType() {
// Create fields
for (unsigned i = 0; i < 2; ++i) {
SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
@@ -2691,7 +2706,7 @@ QualType RewriteObjC::getSuperStructType() {
QualType RewriteObjC::getConstantStringStructType() {
if (!ConstantStringDecl) {
ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Context->Idents.get("__NSConstantStringImpl"));
QualType FieldTypes[4];
@@ -2708,6 +2723,7 @@ QualType RewriteObjC::getConstantStringStructType() {
for (unsigned i = 0; i < 4; ++i) {
ConstantStringDecl->addDecl(FieldDecl::Create(*Context,
ConstantStringDecl,
+ SourceLocation(),
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
@@ -2782,7 +2798,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getNameStart(),
ClassDecl->getIdentifier()->getLength(),
- false, argType, SourceLocation()));
+ false, false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2861,8 +2877,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ClsExprs.push_back(StringLiteral::Create(*Context,
clsName->getNameStart(),
clsName->getLength(),
- false, argType,
- SourceLocation()));
+ false, false,
+ argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2893,7 +2909,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getNameStart(),
ClassDecl->getIdentifier()->getLength(),
- false, argType, SourceLocation()));
+ false, false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2975,7 +2991,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SelExprs.push_back(StringLiteral::Create(*Context,
Exp->getSelector().getAsString().c_str(),
Exp->getSelector().getAsString().size(),
- false, argType, SourceLocation()));
+ false, false, argType, SourceLocation()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
StartLoc,
@@ -3102,10 +3118,11 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation());
// Build sizeof(returnType)
- SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true,
- Context->getTrivialTypeSourceInfo(returnType),
- Context->getSizeType(),
- SourceLocation(), SourceLocation());
+ UnaryExprOrTypeTraitExpr *sizeofExpr =
+ new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf,
+ Context->getTrivialTypeSourceInfo(returnType),
+ Context->getSizeType(), SourceLocation(),
+ SourceLocation());
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
// FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
// For X86 it is more complicated and some kind of target specific routine
@@ -3149,7 +3166,7 @@ QualType RewriteObjC::getProtocolType() {
TypeSourceInfo *TInfo
= Context->getTrivialTypeSourceInfo(Context->getObjCIdType());
ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl,
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Context->Idents.get("Protocol"),
TInfo);
}
@@ -3164,7 +3181,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString();
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- ID, getProtocolType(), 0,
+ SourceLocation(), ID, getProtocolType(), 0,
SC_Extern, SC_None);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), VK_LValue,
SourceLocation());
@@ -3745,7 +3762,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
std::string &Result) {
ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
- // Explictly declared @interface's are already synthesized.
+ // Explicitly declared @interface's are already synthesized.
if (CDecl->isImplicitInterfaceDecl()) {
// FIXME: Implementation of a class with no @interface (legacy) doese not
// produce correct synthesis as yet.
@@ -4315,20 +4332,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += " ";
std::string FieldName = (*I)->getNameAsString();
std::string ArgName = "_" + FieldName;
- // Handle nested closure invocation. For example:
- //
- // void (^myImportedBlock)(void);
- // myImportedBlock = ^(void) { setGlobalInt(x + y); };
- //
- // void (^anotherBlock)(void);
- // anotherBlock = ^(void) {
- // myImportedBlock(); // import and invoke the closure
- // };
- //
- if (isTopLevelBlockPointerType((*I)->getType())) {
- S += "struct __block_impl *";
- Constructor += ", void *" + ArgName;
- } else {
+ {
std::string TypeString;
RewriteByRefString(TypeString, FieldName, (*I));
TypeString += " *";
@@ -4366,11 +4370,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
}
else
Constructor += ", ";
- if (isTopLevelBlockPointerType((*I)->getType()))
- Constructor += Name + "((struct __block_impl *)_"
- + Name + "->__forwarding)";
- else
- Constructor += Name + "(_" + Name + "->__forwarding)";
+ Constructor += Name + "(_" + Name + "->__forwarding)";
}
Constructor += " {\n";
@@ -4601,7 +4601,7 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
/// convertFunctionTypeOfBlocks - This routine converts a function type
/// whose result type may be a block pointer or whose argument type(s)
-/// might be block pointers to an equivalent funtion type replacing
+/// might be block pointers to an equivalent function type replacing
/// all block pointers to function pointers.
QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
@@ -4672,7 +4672,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
// FTP will be null for closures that don't take arguments.
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&Context->Idents.get("__block_impl"));
QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
@@ -4706,7 +4706,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
//PE->dump();
FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
- &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0,
+ SourceLocation(),
+ &Context->Idents.get("FuncPtr"),
+ Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
@@ -4758,6 +4760,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
}
FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
&Context->Idents.get("__forwarding"),
Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
@@ -4767,7 +4770,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
OK_Ordinary);
llvm::StringRef Name = VD->getName();
- FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
@@ -4777,7 +4780,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
// Need parens to enforce precedence.
- ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
+ DeclRefExp->getExprLoc(),
ME);
ReplaceStmt(DeclRefExp, PE);
return PE;
@@ -4949,7 +4953,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
QualType DeclT;
if (VarDecl *VD = dyn_cast<VarDecl>(ND))
DeclT = VD->getType();
- else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND))
+ else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND))
DeclT = TDD->getUnderlyingType();
else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
DeclT = FD->getType();
@@ -5053,7 +5057,7 @@ std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD,
unsigned VoidPtrSize =
static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy));
- unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/8;
+ unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth();
S += " _Block_object_assign((char*)dst + ";
S += utostr(offset);
S += ", *(void * *) ((char*)src + ";
@@ -5124,8 +5128,11 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
}
-
- Ty.getAsStringInternal(Name, Context->PrintingPolicy);
+
+ QualType T = Ty;
+ (void)convertBlockPointerToFunctionPointer(T);
+ T.getAsStringInternal(Name, Context->PrintingPolicy);
+
ByrefType += " " + Name + ";\n";
ByrefType += "};\n";
// Insert this type in global scope. It is needed by helper function.
@@ -5183,7 +5190,12 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += utostr(flag);
}
ByrefType += "};\n";
- ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), ByrefType);
+ unsigned nameSize = Name.size();
+ // for block or function pointer declaration. Name is aleady
+ // part of the declaration.
+ if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
+ nameSize = 1;
+ ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType);
}
else {
SourceLocation startLoc;
@@ -5263,8 +5275,8 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(llvm::StringRef name) {
IdentifierInfo *ID = &Context->Idents.get(name);
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
- return FunctionDecl::Create(*Context, TUDecl,SourceLocation(),
- ID, FType, 0, SC_Extern,
+ return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
+ SourceLocation(), ID, FType, 0, SC_Extern,
SC_None, false, false);
}
@@ -5345,10 +5357,11 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
// Initialize the block descriptor.
std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA";
- VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- &Context->Idents.get(DescData.c_str()),
- Context->VoidPtrTy, 0,
- SC_Static, SC_None);
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get(DescData.c_str()),
+ Context->VoidPtrTy, 0,
+ SC_Static, SC_None);
UnaryOperator *DescRefExpr =
new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD,
Context->VoidPtrTy,
@@ -5407,7 +5420,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
IdentifierInfo *II = &Context->Idents.get(RecName.c_str()
+ sizeof("struct"));
RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), II);
+ SourceLocation(), SourceLocation(),
+ II);
assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
@@ -5507,27 +5521,34 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
Stmt *newStmt;
- Stmt *S = (*CI);
- if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ Stmt *ChildStmt = (*CI);
+ if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(ChildStmt)) {
Expr *OldBase = IvarRefExpr->getBase();
bool replaced = false;
- newStmt = RewriteObjCNestedIvarRefExpr(S, replaced);
+ newStmt = RewriteObjCNestedIvarRefExpr(ChildStmt, replaced);
if (replaced) {
if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt))
ReplaceStmt(OldBase, IRE->getBase());
else
- ReplaceStmt(S, newStmt);
+ ReplaceStmt(ChildStmt, newStmt);
}
}
else
- newStmt = RewriteFunctionBodyOrGlobalInitializer(S);
- if (newStmt)
- *CI = newStmt;
+ newStmt = RewriteFunctionBodyOrGlobalInitializer(ChildStmt);
+ if (newStmt) {
+ if (Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(ChildStmt))
+ if (PropSetters[PropOrImplicitRefExpr] == S) {
+ S = newStmt;
+ newStmt = 0;
+ }
+ if (newStmt)
+ *CI = newStmt;
+ }
// If dealing with an assignment with LHS being a property reference
// expression, the entire assignment tree is rewritten into a property
// setter messaging. This involvs the RHS too. Do not attempt to rewrite
// RHS again.
- if (Expr *Exp = dyn_cast<Expr>(S))
+ if (Expr *Exp = dyn_cast<Expr>(ChildStmt))
if (isa<ObjCPropertyRefExpr>(Exp)) {
if (PropSetters[Exp]) {
++CI;
@@ -5546,13 +5567,14 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// Rewrite the block body in place.
Stmt *SaveCurrentBody = CurrentBody;
CurrentBody = BE->getBody();
+ CollectPropertySetters(CurrentBody);
PropParentMap = 0;
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
CurrentBody = SaveCurrentBody;
PropParentMap = 0;
ImportedLocalExternalDecls.clear();
// Now we snarf the rewritten text and stash it away for later use.
- std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
+ std::string Str = Rewrite.ConvertToString(BE->getBody());
RewrittenBlockExprs[BE] = Str;
Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs);
@@ -5714,7 +5736,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteTypeOfDecl(VD);
}
}
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
@@ -5884,7 +5906,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
}
return;
}
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 92e2b03f76ff..51fe379fee0d 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -26,7 +26,23 @@ llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const {
return os;
}
-void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
+/// \brief Return true if this character is non-new-line whitespace:
+/// ' ', '\t', '\f', '\v', '\r'.
+static inline bool isWhitespace(unsigned char c) {
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ case '\r':
+ return true;
+ default:
+ return false;
+ }
+}
+
+void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
+ bool removeLineIfEmpty) {
// Nothing to remove, exit early.
if (Size == 0) return;
@@ -38,6 +54,34 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
// Add a delta so that future changes are offset correctly.
AddReplaceDelta(OrigOffset, -Size);
+
+ if (removeLineIfEmpty) {
+ // Find the line that the remove occurred and if it is completely empty
+ // remove the line as well.
+
+ iterator curLineStart = begin();
+ unsigned curLineStartOffs = 0;
+ iterator posI = begin();
+ for (unsigned i = 0; i != RealOffset; ++i) {
+ if (*posI == '\n') {
+ curLineStart = posI;
+ ++curLineStart;
+ curLineStartOffs = i + 1;
+ }
+ ++posI;
+ }
+
+ unsigned lineSize = 0;
+ posI = curLineStart;
+ while (posI != end() && isWhitespace(*posI)) {
+ ++posI;
+ ++lineSize;
+ }
+ if (posI != end() && *posI == '\n') {
+ Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/);
+ AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/));
+ }
+ }
}
void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str,
@@ -72,7 +116,8 @@ void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
/// getRangeSize - Return the size in bytes of the specified range if they
/// are in the same file. If not, this returns -1.
-int Rewriter::getRangeSize(const CharSourceRange &Range) const {
+int Rewriter::getRangeSize(const CharSourceRange &Range,
+ RewriteOptions opts) const {
if (!isRewritable(Range.getBegin()) ||
!isRewritable(Range.getEnd())) return -1;
@@ -91,8 +136,8 @@ int Rewriter::getRangeSize(const CharSourceRange &Range) const {
RewriteBuffers.find(StartFileID);
if (I != RewriteBuffers.end()) {
const RewriteBuffer &RB = I->second;
- EndOff = RB.getMappedOffset(EndOff, true);
- StartOff = RB.getMappedOffset(StartOff);
+ EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange);
+ StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange);
}
@@ -104,8 +149,8 @@ int Rewriter::getRangeSize(const CharSourceRange &Range) const {
return EndOff-StartOff;
}
-int Rewriter::getRangeSize(SourceRange Range) const {
- return getRangeSize(CharSourceRange::getTokenRange(Range));
+int Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const {
+ return getRangeSize(CharSourceRange::getTokenRange(Range), opts);
}
@@ -194,12 +239,24 @@ bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
return false;
}
+bool Rewriter::InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str) {
+ if (!isRewritable(Loc)) return true;
+ FileID FID;
+ unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
+ RewriteOptions rangeOpts;
+ rangeOpts.IncludeInsertsAtBeginOfRange = false;
+ StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts);
+ getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true);
+ return false;
+}
+
/// RemoveText - Remove the specified text region.
-bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) {
+bool Rewriter::RemoveText(SourceLocation Start, unsigned Length,
+ RewriteOptions opts) {
if (!isRewritable(Start)) return true;
FileID FID;
unsigned StartOffs = getLocationOffsetAndFileID(Start, FID);
- getEditBuffer(FID).RemoveText(StartOffs, Length);
+ getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty);
return false;
}
@@ -216,6 +273,20 @@ bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
return false;
}
+bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) {
+ if (!isRewritable(range.getBegin())) return true;
+ if (!isRewritable(range.getEnd())) return true;
+ if (replacementRange.isInvalid()) return true;
+ SourceLocation start = range.getBegin();
+ unsigned origLength = getRangeSize(range);
+ unsigned newLength = getRangeSize(replacementRange);
+ FileID FID;
+ unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(),
+ FID);
+ llvm::StringRef MB = SourceMgr->getBufferData(FID);
+ return ReplaceText(start, origLength, MB.substr(newOffs, newLength));
+}
+
/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
/// printer to generate the replacement code. This returns true if the input
/// could not be rewritten, or false if successful.
@@ -234,3 +305,93 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
ReplaceText(From->getLocStart(), Size, Str);
return false;
}
+
+std::string Rewriter::ConvertToString(Stmt *From) {
+ std::string SStr;
+ llvm::raw_string_ostream S(SStr);
+ From->printPretty(S, 0, PrintingPolicy(*LangOpts));
+ return S.str();
+}
+
+bool Rewriter::IncreaseIndentation(CharSourceRange range,
+ SourceLocation parentIndent) {
+ using llvm::StringRef;
+
+ if (!isRewritable(range.getBegin())) return true;
+ if (!isRewritable(range.getEnd())) return true;
+ if (!isRewritable(parentIndent)) return true;
+
+ FileID StartFileID, EndFileID, parentFileID;
+ unsigned StartOff, EndOff, parentOff;
+
+ StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID);
+ EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID);
+ parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID);
+
+ if (StartFileID != EndFileID || StartFileID != parentFileID)
+ return true;
+ if (StartOff >= EndOff || parentOff >= StartOff)
+ return true;
+
+ FileID FID = StartFileID;
+ StringRef MB = SourceMgr->getBufferData(FID);
+
+ unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1;
+ unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1;
+ unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1;
+
+ const SrcMgr::ContentCache *
+ Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
+
+ // Find where the line starts for the three offsets.
+ unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
+ unsigned startLineOffs = Content->SourceLineCache[startLineNo];
+ unsigned endLineOffs = Content->SourceLineCache[endLineNo];
+
+ if (startLineOffs == endLineOffs || startLineOffs == parentLineOffs)
+ return true;
+
+ // Find the whitespace at the start of each line.
+ StringRef parentSpace, startSpace, endSpace;
+ {
+ unsigned i = parentLineOffs;
+ while (isWhitespace(MB[i]))
+ ++i;
+ parentSpace = MB.substr(parentLineOffs, i-parentLineOffs);
+
+ i = startLineOffs;
+ while (isWhitespace(MB[i]))
+ ++i;
+ startSpace = MB.substr(startLineOffs, i-startLineOffs);
+
+ i = endLineOffs;
+ while (isWhitespace(MB[i]))
+ ++i;
+ endSpace = MB.substr(endLineOffs, i-endLineOffs);
+ }
+ if (parentSpace.size() >= startSpace.size())
+ return true;
+ if (!startSpace.startswith(parentSpace))
+ return true;
+
+ llvm::StringRef indent = startSpace.substr(parentSpace.size());
+
+ // Indent the lines between start/end offsets.
+ RewriteBuffer &RB = getEditBuffer(FID);
+ for (unsigned i = startLineOffs; i != endLineOffs; ++i) {
+ if (MB[i] == '\n') {
+ unsigned startOfLine = i+1;
+ if (startOfLine == endLineOffs)
+ break;
+ StringRef origIndent;
+ unsigned ws = startOfLine;
+ while (isWhitespace(MB[ws]))
+ ++ws;
+ origIndent = MB.substr(startOfLine, ws-startOfLine);
+ if (origIndent.startswith(startSpace))
+ RB.InsertText(startOfLine, indent, /*InsertAfter=*/false);
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 6a422242a9d4..e482172ca3eb 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -24,12 +24,13 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
#include "clang/Analysis/CFGStmtMap.h"
-#include "clang/Analysis/Analyses/UninitializedValuesV2.h"
+#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Casting.h"
@@ -129,12 +130,27 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
// normal. We need to look pass the destructors for the return
// statement (if it exists).
CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
+ bool hasNoReturnDtor = false;
+
for ( ; ri != re ; ++ri) {
CFGElement CE = *ri;
+
+ // FIXME: The right solution is to just sever the edges in the
+ // CFG itself.
+ if (const CFGImplicitDtor *iDtor = ri->getAs<CFGImplicitDtor>())
+ if (iDtor->isNoReturn(AC.getASTContext())) {
+ hasNoReturnDtor = true;
+ HasFakeEdge = true;
+ break;
+ }
+
if (isa<CFGStmt>(CE))
break;
}
+ if (hasNoReturnDtor)
+ continue;
+
// No more CFGElements in the block?
if (ri == re) {
if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
@@ -363,17 +379,145 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
//===----------------------------------------------------------------------===//
namespace {
+/// ContainsReference - A visitor class to search for references to
+/// a particular declaration (the needle) within any evaluated component of an
+/// expression (recursively).
+class ContainsReference : public EvaluatedExprVisitor<ContainsReference> {
+ bool FoundReference;
+ const DeclRefExpr *Needle;
+
+public:
+ ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)
+ : EvaluatedExprVisitor<ContainsReference>(Context),
+ FoundReference(false), Needle(Needle) {}
+
+ void VisitExpr(Expr *E) {
+ // Stop evaluating if we already have a reference.
+ if (FoundReference)
+ return;
+
+ EvaluatedExprVisitor<ContainsReference>::VisitExpr(E);
+ }
+
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ if (E == Needle)
+ FoundReference = true;
+ else
+ EvaluatedExprVisitor<ContainsReference>::VisitDeclRefExpr(E);
+ }
+
+ bool doesContainReference() const { return FoundReference; }
+};
+}
+
+/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
+/// uninitialized variable. This manages the different forms of diagnostic
+/// emitted for particular types of uses. Returns true if the use was diagnosed
+/// as a warning. If a pariticular use is one we omit warnings for, returns
+/// false.
+static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
+ const Expr *E, bool isAlwaysUninit) {
+ bool isSelfInit = false;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (isAlwaysUninit) {
+ // Inspect the initializer of the variable declaration which is
+ // being referenced prior to its initialization. We emit
+ // specialized diagnostics for self-initialization, and we
+ // specifically avoid warning about self references which take the
+ // form of:
+ //
+ // int x = x;
+ //
+ // This is used to indicate to GCC that 'x' is intentionally left
+ // uninitialized. Proven code paths which access 'x' in
+ // an uninitialized state after this will still warn.
+ //
+ // TODO: Should we suppress maybe-uninitialized warnings for
+ // variables initialized in this way?
+ if (const Expr *Initializer = VD->getInit()) {
+ if (DRE == Initializer->IgnoreParenImpCasts())
+ return false;
+
+ ContainsReference CR(S.Context, DRE);
+ CR.Visit(const_cast<Expr*>(Initializer));
+ isSelfInit = CR.doesContainReference();
+ }
+ if (isSelfInit) {
+ S.Diag(DRE->getLocStart(),
+ diag::warn_uninit_self_reference_in_init)
+ << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange();
+ } else {
+ S.Diag(DRE->getLocStart(), diag::warn_uninit_var)
+ << VD->getDeclName() << DRE->getSourceRange();
+ }
+ } else {
+ S.Diag(DRE->getLocStart(), diag::warn_maybe_uninit_var)
+ << VD->getDeclName() << DRE->getSourceRange();
+ }
+ } else {
+ const BlockExpr *BE = cast<BlockExpr>(E);
+ S.Diag(BE->getLocStart(),
+ isAlwaysUninit ? diag::warn_uninit_var_captured_by_block
+ : diag::warn_maybe_uninit_var_captured_by_block)
+ << VD->getDeclName();
+ }
+
+ // Report where the variable was declared when the use wasn't within
+ // the initializer of that declaration.
+ if (!isSelfInit)
+ S.Diag(VD->getLocStart(), diag::note_uninit_var_def)
+ << VD->getDeclName();
+
+ return true;
+}
+
+static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
+ // Don't issue a fixit if there is already an initializer.
+ if (VD->getInit())
+ return;
+
+ // Suggest possible initialization (if any).
+ const char *initialization = 0;
+ QualType VariableTy = VD->getType().getCanonicalType();
+
+ if (VariableTy->getAs<ObjCObjectPointerType>()) {
+ // Check if 'nil' is defined.
+ if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
+ initialization = " = nil";
+ else
+ initialization = " = 0";
+ }
+ else if (VariableTy->isRealFloatingType())
+ initialization = " = 0.0";
+ else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus)
+ initialization = " = false";
+ else if (VariableTy->isEnumeralType())
+ return;
+ else if (VariableTy->isScalarType())
+ initialization = " = 0";
+
+ if (initialization) {
+ SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
+ S.Diag(loc, diag::note_var_fixit_add_initialization)
+ << FixItHint::CreateInsertion(loc, initialization);
+ }
+}
+
+typedef std::pair<const Expr*, bool> UninitUse;
+
+namespace {
struct SLocSort {
- bool operator()(const Expr *a, const Expr *b) {
- SourceLocation aLoc = a->getLocStart();
- SourceLocation bLoc = b->getLocStart();
+ bool operator()(const UninitUse &a, const UninitUse &b) {
+ SourceLocation aLoc = a.first->getLocStart();
+ SourceLocation bLoc = b.first->getLocStart();
return aLoc.getRawEncoding() < bLoc.getRawEncoding();
}
};
class UninitValsDiagReporter : public UninitVariablesHandler {
Sema &S;
- typedef llvm::SmallVector<const Expr *, 2> UsesVec;
+ typedef llvm::SmallVector<UninitUse, 2> UsesVec;
typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap;
UsesMap *uses;
@@ -383,7 +527,8 @@ public:
flushDiagnostics();
}
- void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) {
+ void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd,
+ bool isAlwaysUninit) {
if (!uses)
uses = new UsesMap();
@@ -391,7 +536,7 @@ public:
if (!vec)
vec = new UsesVec();
- vec->push_back(ex);
+ vec->push_back(std::make_pair(ex, isAlwaysUninit));
}
void flushDiagnostics() {
@@ -409,54 +554,19 @@ public:
// a stable ordering.
std::sort(vec->begin(), vec->end(), SLocSort());
- for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi)
- {
- if (const DeclRefExpr *dr = dyn_cast<DeclRefExpr>(*vi)) {
- S.Diag(dr->getLocStart(), diag::warn_uninit_var)
- << vd->getDeclName() << dr->getSourceRange();
- }
- else {
- const BlockExpr *be = cast<BlockExpr>(*vi);
- S.Diag(be->getLocStart(), diag::warn_uninit_var_captured_by_block)
- << vd->getDeclName();
- }
-
- // Report where the variable was declared.
- S.Diag(vd->getLocStart(), diag::note_uninit_var_def)
- << vd->getDeclName();
-
- // Only report the fixit once.
- if (fixitIssued)
+ for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve;
+ ++vi) {
+ if (!DiagnoseUninitializedUse(S, vd, vi->first,
+ /*isAlwaysUninit=*/vi->second))
continue;
-
- fixitIssued = true;
-
- // Suggest possible initialization (if any).
- const char *initialization = 0;
- QualType vdTy = vd->getType().getCanonicalType();
-
- if (vdTy->getAs<ObjCObjectPointerType>()) {
- // Check if 'nil' is defined.
- if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
- initialization = " = nil";
- else
- initialization = " = 0";
- }
- else if (vdTy->isRealFloatingType())
- initialization = " = 0.0";
- else if (vdTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus)
- initialization = " = false";
- else if (vdTy->isEnumeralType())
- continue;
- else if (vdTy->isScalarType())
- initialization = " = 0";
-
- if (initialization) {
- SourceLocation loc = S.PP.getLocForEndOfToken(vd->getLocEnd());
- S.Diag(loc, diag::note_var_fixit_add_initialization)
- << FixItHint::CreateInsertion(loc, initialization);
+
+ // Suggest a fixit hint the first time we diagnose a use of a variable.
+ if (!fixitIssued) {
+ SuggestInitializationFixit(S, vd);
+ fixitIssued = true;
}
}
+
delete vec;
}
delete uses;
@@ -531,25 +641,41 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Emit delayed diagnostics.
if (!fscope->PossiblyUnreachableDiags.empty()) {
bool analyzed = false;
- if (CFGReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis())
- if (CFGStmtMap *csm = AC.getCFGStmtMap()) {
- analyzed = true;
- for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
- i = fscope->PossiblyUnreachableDiags.begin(),
- e = fscope->PossiblyUnreachableDiags.end();
- i != e; ++i) {
- const sema::PossiblyUnreachableDiag &D = *i;
- if (const CFGBlock *blk = csm->getBlock(D.stmt)) {
+
+ // Register the expressions with the CFGBuilder.
+ for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ i = fscope->PossiblyUnreachableDiags.begin(),
+ e = fscope->PossiblyUnreachableDiags.end();
+ i != e; ++i) {
+ if (const Stmt *stmt = i->stmt)
+ AC.registerForcedBlockExpression(stmt);
+ }
+
+ if (AC.getCFG()) {
+ analyzed = true;
+ for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
+ i = fscope->PossiblyUnreachableDiags.begin(),
+ e = fscope->PossiblyUnreachableDiags.end();
+ i != e; ++i)
+ {
+ const sema::PossiblyUnreachableDiag &D = *i;
+ bool processed = false;
+ if (const Stmt *stmt = i->stmt) {
+ const CFGBlock *block = AC.getBlockForRegisteredExpression(stmt);
+ assert(block);
+ if (CFGReverseBlockReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis()) {
// Can this block be reached from the entrance?
- if (cra->isReachable(&AC.getCFG()->getEntry(), blk))
+ if (cra->isReachable(&AC.getCFG()->getEntry(), block))
S.Diag(D.Loc, D.PD);
- }
- else {
- // Emit the warning anyway if we cannot map to a basic block.
- S.Diag(D.Loc, D.PD);
+ processed = true;
}
}
+ if (!processed) {
+ // Emit the warning anyway if we cannot map to a basic block.
+ S.Diag(D.Loc, D.PD);
+ }
}
+ }
if (!analyzed)
flushDiagnostics(S, fscope);
@@ -569,25 +695,10 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
CheckUnreachable(S, AC);
if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
+ != Diagnostic::Ignored ||
+ Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart())
!= Diagnostic::Ignored) {
- ASTContext &ctx = D->getASTContext();
- llvm::OwningPtr<CFG> tmpCFG;
- bool useAlternateCFG = false;
- if (ctx.getLangOptions().CPlusPlus) {
- // Temporary workaround: implicit dtors in the CFG can confuse
- // the path-sensitivity in the uninitialized values analysis.
- // For now create (if necessary) a separate CFG without implicit dtors.
- // FIXME: We should not need to do this, as it results in multiple
- // CFGs getting constructed.
- CFG::BuildOptions B;
- B.AddEHEdges = false;
- B.AddImplicitDtors = false;
- B.AddInitializers = true;
- tmpCFG.reset(CFG::buildCFG(D, AC.getBody(), &ctx, B));
- useAlternateCFG = true;
- }
- CFG *cfg = useAlternateCFG ? tmpCFG.get() : AC.getCFG();
- if (cfg) {
+ if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
reporter);
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index c0a305365afc..619a5b961bfe 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -12,28 +12,89 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/AttributeList.h"
+#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
-AttributeList::AttributeList(llvm::BumpPtrAllocator &Alloc,
- IdentifierInfo *aName, SourceLocation aLoc,
- IdentifierInfo *sName, SourceLocation sLoc,
- IdentifierInfo *pName, SourceLocation pLoc,
- Expr **ExprList, unsigned numArgs,
- bool declspec, bool cxx0x)
- : AttrName(aName), AttrLoc(aLoc), ScopeName(sName),
- ScopeLoc(sLoc),
- ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(0),
- DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) {
-
- if (numArgs == 0)
- Args = 0;
- else {
- // Allocate the Args array using the BumpPtrAllocator.
- Args = Alloc.Allocate<Expr*>(numArgs);
- memcpy(Args, ExprList, numArgs*sizeof(Args[0]));
+size_t AttributeList::allocated_size() const {
+ if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
+ return (sizeof(AttributeList) + NumArgs * sizeof(Expr*));
+}
+
+AttributeFactory::AttributeFactory() {
+ // Go ahead and configure all the inline capacity. This is just a memset.
+ FreeLists.resize(InlineFreeListsCapacity);
+}
+AttributeFactory::~AttributeFactory() {}
+
+static size_t getFreeListIndexForSize(size_t size) {
+ assert(size >= sizeof(AttributeList));
+ assert((size % sizeof(void*)) == 0);
+ return ((size - sizeof(AttributeList)) / sizeof(void*));
+}
+
+void *AttributeFactory::allocate(size_t size) {
+ // Check for a previously reclaimed attribute.
+ size_t index = getFreeListIndexForSize(size);
+ if (index < FreeLists.size()) {
+ if (AttributeList *attr = FreeLists[index]) {
+ FreeLists[index] = attr->NextInPool;
+ return attr;
+ }
}
+
+ // Otherwise, allocate something new.
+ return Alloc.Allocate(size, llvm::AlignOf<AttributeFactory>::Alignment);
+}
+
+void AttributeFactory::reclaimPool(AttributeList *cur) {
+ assert(cur && "reclaiming empty pool!");
+ do {
+ // Read this here, because we're going to overwrite NextInPool
+ // when we toss 'cur' into the appropriate queue.
+ AttributeList *next = cur->NextInPool;
+
+ size_t size = cur->allocated_size();
+ size_t freeListIndex = getFreeListIndexForSize(size);
+
+ // Expand FreeLists to the appropriate size, if required.
+ if (freeListIndex >= FreeLists.size())
+ FreeLists.resize(freeListIndex+1);
+
+ // Add 'cur' to the appropriate free-list.
+ cur->NextInPool = FreeLists[freeListIndex];
+ FreeLists[freeListIndex] = cur;
+
+ cur = next;
+ } while (cur);
+}
+
+void AttributePool::takePool(AttributeList *pool) {
+ assert(pool);
+
+ // Fast path: this pool is empty.
+ if (!Head) {
+ Head = pool;
+ return;
+ }
+
+ // Reverse the pool onto the current head. This optimizes for the
+ // pattern of pulling a lot of pools into a single pool.
+ do {
+ AttributeList *next = pool->NextInPool;
+ pool->NextInPool = Head;
+ Head = pool;
+ pool = next;
+ } while (pool);
+}
+
+AttributeList *
+AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
+ SourceLocation TokLoc, int Arg) {
+ Expr *IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg),
+ C.IntTy, TokLoc);
+ return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1, 0);
}
AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
@@ -83,6 +144,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("may_alias", AT_may_alias)
.Case("base_check", AT_base_check)
.Case("deprecated", AT_deprecated)
+ .Case("availability", AT_availability)
.Case("visibility", AT_visibility)
.Case("destructor", AT_destructor)
.Case("format_arg", AT_format_arg)
@@ -94,10 +156,12 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("unavailable", AT_unavailable)
.Case("overloadable", AT_overloadable)
.Case("address_space", AT_address_space)
+ .Case("opencl_image_access", AT_opencl_image_access)
.Case("always_inline", AT_always_inline)
.Case("returns_twice", IgnoredAttribute)
.Case("vec_type_hint", IgnoredAttribute)
.Case("objc_exception", AT_objc_exception)
+ .Case("objc_method_family", AT_objc_method_family)
.Case("ext_vector_type", AT_ext_vector_type)
.Case("neon_vector_type", AT_neon_vector_type)
.Case("neon_polyvector_type", AT_neon_polyvector_type)
@@ -137,5 +201,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("nocommon", AT_nocommon)
.Case("opencl_kernel_function", AT_opencl_kernel_function)
.Case("uuid", AT_uuid)
+ .Case("pcs", AT_pcs)
+ .Case("ms_struct", AT_MsStruct)
.Default(UnknownAttribute);
}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 0d66e259d484..0a670197d7ef 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -5,8 +5,10 @@ add_clang_library(clangSema
AttributeList.cpp
CodeCompleteConsumer.cpp
DeclSpec.cpp
+ DelayedDiagnostic.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
+ Scope.cpp
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index b7037ce83e7f..2334ab5128a7 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -375,12 +375,21 @@ void CodeCompletionResult::computeCursorKindAndAvailability() {
switch (Kind) {
case RK_Declaration:
// Set the availability based on attributes.
- Availability = CXAvailability_Available;
- if (Declaration->getAttr<UnavailableAttr>())
- Availability = CXAvailability_NotAvailable;
- else if (Declaration->getAttr<DeprecatedAttr>())
+ switch (Declaration->getAvailability()) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ Availability = CXAvailability_Available;
+ break;
+
+ case AR_Deprecated:
Availability = CXAvailability_Deprecated;
+ break;
+ case AR_Unavailable:
+ Availability = CXAvailability_NotAvailable;
+ break;
+ }
+
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Declaration))
if (Function->isDeleted())
Availability = CXAvailability_NotAvailable;
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 037594a44a1c..0f20d10b076a 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -47,278 +47,130 @@ void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) {
EndLocation = TemplateId->RAngleLoc;
}
-CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &Other)
- : Range(Other.Range), ScopeRep(Other.ScopeRep), Buffer(0),
- BufferSize(Other.BufferSize), BufferCapacity(Other.BufferSize)
-{
- if (BufferSize) {
- Buffer = static_cast<char *>(malloc(BufferSize));
- memcpy(Buffer, Other.Buffer, BufferSize);
- }
-}
-
-CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &Other) {
- Range = Other.Range;
- ScopeRep = Other.ScopeRep;
- if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {
- // Re-use our storage.
- BufferSize = Other.BufferSize;
- memcpy(Buffer, Other.Buffer, BufferSize);
- return *this;
- }
-
- if (BufferCapacity)
- free(Buffer);
- if (Other.Buffer) {
- BufferSize = Other.BufferSize;
- BufferCapacity = BufferSize;
- Buffer = static_cast<char *>(malloc(BufferSize));
- memcpy(Buffer, Other.Buffer, BufferSize);
- } else {
- Buffer = 0;
- BufferSize = 0;
- BufferCapacity = 0;
- }
- return *this;
-}
-
-CXXScopeSpec::~CXXScopeSpec() {
- if (BufferCapacity)
- free(Buffer);
-}
-
-namespace {
- void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
- unsigned &BufferCapacity) {
- if (BufferSize + (End - Start) > BufferCapacity) {
- // Reallocate the buffer.
- unsigned NewCapacity
- = std::max((unsigned)(BufferCapacity? BufferCapacity * 2
- : sizeof(void*) * 2),
- (unsigned)(BufferSize + (End - Start)));
- char *NewBuffer = static_cast<char *>(malloc(NewCapacity));
- memcpy(NewBuffer, Buffer, BufferSize);
-
- if (BufferCapacity)
- free(Buffer);
- Buffer = NewBuffer;
- BufferCapacity = NewCapacity;
- }
-
- memcpy(Buffer + BufferSize, Start, End - Start);
- BufferSize += End-Start;
- }
-
- /// \brief Save a source location to the given buffer.
- void SaveSourceLocation(SourceLocation Loc, char *&Buffer,
- unsigned &BufferSize, unsigned &BufferCapacity) {
- unsigned Raw = Loc.getRawEncoding();
- Append(reinterpret_cast<char *>(&Raw),
- reinterpret_cast<char *>(&Raw) + sizeof(unsigned),
- Buffer, BufferSize, BufferCapacity);
- }
-
- /// \brief Save a pointer to the given buffer.
- void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,
- unsigned &BufferCapacity) {
- Append(reinterpret_cast<char *>(&Ptr),
- reinterpret_cast<char *>(&Ptr) + sizeof(void *),
- Buffer, BufferSize, BufferCapacity);
- }
-}
void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc,
TypeLoc TL, SourceLocation ColonColonLoc) {
- ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep,
- TemplateKWLoc.isValid(),
- TL.getTypePtr());
+ Builder.Extend(Context, TemplateKWLoc, TL, ColonColonLoc);
if (Range.getBegin().isInvalid())
Range.setBegin(TL.getBeginLoc());
Range.setEnd(ColonColonLoc);
- // Push source-location info into the buffer.
- SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
- SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
-
- assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ assert(Range == Builder.getSourceRange() &&
"NestedNameSpecifierLoc range computation incorrect");
}
void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier,
SourceLocation IdentifierLoc,
SourceLocation ColonColonLoc) {
- ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Identifier);
+ Builder.Extend(Context, Identifier, IdentifierLoc, ColonColonLoc);
+
if (Range.getBegin().isInvalid())
Range.setBegin(IdentifierLoc);
Range.setEnd(ColonColonLoc);
- // Push source-location info into the buffer.
- SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
- SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
-
- assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ assert(Range == Builder.getSourceRange() &&
"NestedNameSpecifierLoc range computation incorrect");
}
void CXXScopeSpec::Extend(ASTContext &Context, NamespaceDecl *Namespace,
SourceLocation NamespaceLoc,
SourceLocation ColonColonLoc) {
- ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Namespace);
+ Builder.Extend(Context, Namespace, NamespaceLoc, ColonColonLoc);
+
if (Range.getBegin().isInvalid())
Range.setBegin(NamespaceLoc);
Range.setEnd(ColonColonLoc);
- // Push source-location info into the buffer.
- SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
- SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
-
- assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ assert(Range == Builder.getSourceRange() &&
"NestedNameSpecifierLoc range computation incorrect");
}
void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
SourceLocation AliasLoc,
SourceLocation ColonColonLoc) {
- ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Alias);
+ Builder.Extend(Context, Alias, AliasLoc, ColonColonLoc);
+
if (Range.getBegin().isInvalid())
Range.setBegin(AliasLoc);
Range.setEnd(ColonColonLoc);
- // Push source-location info into the buffer.
- SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity);
- SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
-
- assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ assert(Range == Builder.getSourceRange() &&
"NestedNameSpecifierLoc range computation incorrect");
}
void CXXScopeSpec::MakeGlobal(ASTContext &Context,
SourceLocation ColonColonLoc) {
- assert(!ScopeRep && "Already have a nested-name-specifier!?");
- ScopeRep = NestedNameSpecifier::GlobalSpecifier(Context);
- Range = SourceRange(ColonColonLoc);
+ Builder.MakeGlobal(Context, ColonColonLoc);
- // Push source-location info into the buffer.
- SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+ Range = SourceRange(ColonColonLoc);
- assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+ assert(Range == Builder.getSourceRange() &&
"NestedNameSpecifierLoc range computation incorrect");
}
void CXXScopeSpec::MakeTrivial(ASTContext &Context,
NestedNameSpecifier *Qualifier, SourceRange R) {
- ScopeRep = Qualifier;
+ Builder.MakeTrivial(Context, Qualifier, R);
Range = R;
-
- // Construct bogus (but well-formed) source information for the
- // nested-name-specifier.
- BufferSize = 0;
- llvm::SmallVector<NestedNameSpecifier *, 4> Stack;
- for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
- Stack.push_back(NNS);
- while (!Stack.empty()) {
- NestedNameSpecifier *NNS = Stack.back();
- Stack.pop_back();
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::NamespaceAlias:
- SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
- break;
-
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate: {
- TypeSourceInfo *TSInfo
- = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
- R.getBegin());
- SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,
- BufferCapacity);
- break;
- }
-
- case NestedNameSpecifier::Global:
- break;
- }
-
- // Save the location of the '::'.
- SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(),
- Buffer, BufferSize, BufferCapacity);
- }
}
void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) {
if (!Other) {
Range = SourceRange();
- ScopeRep = 0;
+ Builder.Clear();
return;
}
-
- if (BufferCapacity)
- free(Buffer);
-
- // Rather than copying the data (which is wasteful), "adopt" the
- // pointer (which points into the ASTContext) but set the capacity to zero to
- // indicate that we don't own it.
+
Range = Other.getSourceRange();
- ScopeRep = Other.getNestedNameSpecifier();
- Buffer = static_cast<char *>(Other.getOpaqueData());
- BufferSize = Other.getDataLength();
- BufferCapacity = 0;
+ Builder.Adopt(Other);
}
NestedNameSpecifierLoc
CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
- if (isEmpty() || isInvalid())
+ if (!Builder.getRepresentation())
return NestedNameSpecifierLoc();
- // If we adopted our data pointer from elsewhere in the AST context, there's
- // no need to copy the memory.
- if (BufferCapacity == 0)
- return NestedNameSpecifierLoc(ScopeRep, Buffer);
-
- void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>());
- memcpy(Mem, Buffer, BufferSize);
- return NestedNameSpecifierLoc(ScopeRep, Mem);
+ return Builder.getWithLocInContext(Context);
}
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
-DeclaratorChunk DeclaratorChunk::getFunction(const ParsedAttributes &attrs,
- bool hasProto, bool isVariadic,
+DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
SourceLocation EllipsisLoc,
ParamInfo *ArgInfo,
unsigned NumArgs,
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
- bool hasExceptionSpec,
- SourceLocation ThrowLoc,
- bool hasAnyExceptionSpec,
+ ExceptionSpecificationType
+ ESpecType,
+ SourceLocation ESpecLoc,
ParsedType *Exceptions,
SourceRange *ExceptionRanges,
unsigned NumExceptions,
- SourceLocation LPLoc,
- SourceLocation RPLoc,
+ Expr *NoexceptExpr,
+ SourceLocation LocalRangeBegin,
+ SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
ParsedType TrailingReturnType) {
DeclaratorChunk I;
- I.Kind = Function;
- I.Loc = LPLoc;
- I.EndLoc = RPLoc;
- I.Fun.AttrList = attrs.getList();
- I.Fun.hasPrototype = hasProto;
- I.Fun.isVariadic = isVariadic;
- I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
- I.Fun.DeleteArgInfo = false;
- I.Fun.TypeQuals = TypeQuals;
- I.Fun.NumArgs = NumArgs;
- I.Fun.ArgInfo = 0;
+ I.Kind = Function;
+ I.Loc = LocalRangeBegin;
+ I.EndLoc = LocalRangeEnd;
+ I.Fun.AttrList = 0;
+ I.Fun.hasPrototype = hasProto;
+ I.Fun.isVariadic = isVariadic;
+ I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ I.Fun.DeleteArgInfo = false;
+ I.Fun.TypeQuals = TypeQuals;
+ I.Fun.NumArgs = NumArgs;
+ I.Fun.ArgInfo = 0;
I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef;
- I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
- I.Fun.hasExceptionSpec = hasExceptionSpec;
- I.Fun.ThrowLoc = ThrowLoc.getRawEncoding();
- I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec;
- I.Fun.NumExceptions = NumExceptions;
- I.Fun.Exceptions = 0;
+ I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
+ I.Fun.ExceptionSpecType = ESpecType;
+ I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding();
+ I.Fun.NumExceptions = 0;
+ I.Fun.Exceptions = 0;
+ I.Fun.NoexceptExpr = 0;
I.Fun.TrailingReturnType = TrailingReturnType.getAsOpaquePtr();
// new[] an argument array if needed.
@@ -338,13 +190,25 @@ DeclaratorChunk DeclaratorChunk::getFunction(const ParsedAttributes &attrs,
}
memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs);
}
- // new[] an exception array if needed
- if (NumExceptions) {
- I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
- for (unsigned i = 0; i != NumExceptions; ++i) {
- I.Fun.Exceptions[i].Ty = Exceptions[i];
- I.Fun.Exceptions[i].Range = ExceptionRanges[i];
+
+ // Check what exception specification information we should actually store.
+ switch (ESpecType) {
+ default: break; // By default, save nothing.
+ case EST_Dynamic:
+ // new[] an exception array if needed
+ if (NumExceptions) {
+ I.Fun.NumExceptions = NumExceptions;
+ I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
+ for (unsigned i = 0; i != NumExceptions; ++i) {
+ I.Fun.Exceptions[i].Ty = Exceptions[i];
+ I.Fun.Exceptions[i].Range = ExceptionRanges[i];
+ }
}
+ break;
+
+ case EST_ComputedNoexcept:
+ I.Fun.NoexceptExpr = NoexceptExpr;
+ break;
}
return I;
}
@@ -445,6 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_typeofExpr: return "typeof";
case DeclSpec::TST_auto: return "auto";
case DeclSpec::TST_decltype: return "(decltype)";
+ case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_error: return "(error)";
}
llvm_unreachable("Unknown typespec!");
@@ -515,12 +380,14 @@ bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID) {
- if (TypeSpecWidth != TSW_unspecified &&
- // Allow turning long -> long long.
- (W != TSW_longlong || TypeSpecWidth != TSW_long))
+ // Overwrite TSWLoc only if TypeSpecWidth was unspecified, so that
+ // for 'long long' we will keep the source location of the first 'long'.
+ if (TypeSpecWidth == TSW_unspecified)
+ TSWLoc = Loc;
+ // Allow turning long -> long long.
+ else if (W != TSW_longlong || TypeSpecWidth != TSW_long)
return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID);
TypeSpecWidth = W;
- TSWLoc = Loc;
if (TypeAltiVecVector && !TypeAltiVecBool &&
((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
@@ -554,6 +421,14 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
ParsedType Rep) {
+ return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep);
+}
+
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
+ SourceLocation TagNameLoc,
+ const char *&PrevSpec,
+ unsigned &DiagID,
+ ParsedType Rep) {
assert(isTypeRep(T) && "T does not store a type");
assert(Rep && "no type provided!");
if (TypeSpecType != TST_unspecified) {
@@ -563,7 +438,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
}
TypeSpecType = T;
TypeRep = Rep;
- TSTLoc = Loc;
+ TSTLoc = TagKwLoc;
+ TSTNameLoc = TagNameLoc;
TypeSpecOwned = false;
return false;
}
@@ -582,6 +458,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
TypeSpecType = T;
ExprRep = Rep;
TSTLoc = Loc;
+ TSTNameLoc = Loc;
TypeSpecOwned = false;
return false;
}
@@ -590,6 +467,14 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
Decl *Rep, bool Owned) {
+ return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep, Owned);
+}
+
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
+ SourceLocation TagNameLoc,
+ const char *&PrevSpec,
+ unsigned &DiagID,
+ Decl *Rep, bool Owned) {
assert(isDeclRep(T) && "T does not store a decl");
// Unlike the other cases, we don't assert that we actually get a decl.
@@ -600,7 +485,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
}
TypeSpecType = T;
DeclRep = Rep;
- TSTLoc = Loc;
+ TSTLoc = TagKwLoc;
+ TSTNameLoc = TagNameLoc;
TypeSpecOwned = Owned;
return false;
}
@@ -615,13 +501,13 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
DiagID = diag::err_invalid_decl_spec_combination;
return true;
}
+ TSTLoc = Loc;
+ TSTNameLoc = Loc;
if (TypeAltiVecVector && (T == TST_bool) && !TypeAltiVecBool) {
TypeAltiVecBool = true;
- TSTLoc = Loc;
return false;
}
TypeSpecType = T;
- TSTLoc = Loc;
TypeSpecOwned = false;
if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
@@ -653,6 +539,7 @@ bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
}
TypeAltiVecPixel = isAltiVecPixel;
TSTLoc = Loc;
+ TSTNameLoc = Loc;
return false;
}
@@ -660,6 +547,7 @@ bool DeclSpec::SetTypeSpecError() {
TypeSpecType = TST_error;
TypeSpecOwned = false;
TSTLoc = SourceLocation();
+ TSTNameLoc = SourceLocation();
return false;
}
@@ -929,6 +817,8 @@ void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc,
bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
const char *&PrevSpec) {
+ LastLocation = Loc;
+
if (Specifiers & VS) {
PrevSpec = getSpecifierName(VS);
return true;
@@ -940,7 +830,6 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc,
default: assert(0 && "Unknown specifier!");
case VS_Override: VS_overrideLoc = Loc; break;
case VS_Final: VS_finalLoc = Loc; break;
- case VS_New: VS_newLoc = Loc; break;
}
return false;
@@ -951,33 +840,5 @@ const char *VirtSpecifiers::getSpecifierName(Specifier VS) {
default: assert(0 && "Unknown specifier");
case VS_Override: return "override";
case VS_Final: return "final";
- case VS_New: return "new";
}
}
-
-bool ClassVirtSpecifiers::SetSpecifier(Specifier CVS, SourceLocation Loc,
- const char *&PrevSpec) {
- if (Specifiers & CVS) {
- PrevSpec = getSpecifierName(CVS);
- return true;
- }
-
- Specifiers |= CVS;
-
- switch (CVS) {
- default: assert(0 && "Unknown specifier!");
- case CVS_Final: CVS_finalLoc = Loc; break;
- case CVS_Explicit: CVS_explicitLoc = Loc; break;
- }
-
- return false;
-}
-
-const char *ClassVirtSpecifiers::getSpecifierName(Specifier CVS) {
- switch (CVS) {
- default: assert(0 && "Unknown specifier");
- case CVS_Final: return "final";
- case CVS_Explicit: return "explicit";
- }
-}
-
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
new file mode 100644
index 000000000000..af548fe13460
--- /dev/null
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -0,0 +1,51 @@
+//===--- DelayedDiagnostic.cpp - Delayed declarator diagnostics -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DelayedDiagnostic class implementation, which
+// is used to record diagnostics that are being conditionally produced
+// during declarator parsing.
+//
+// This file also defines AccessedEntity.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/DelayedDiagnostic.h"
+#include <string.h>
+using namespace clang;
+using namespace sema;
+
+DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
+ const NamedDecl *D,
+ llvm::StringRef Msg) {
+ DelayedDiagnostic DD;
+ DD.Kind = Deprecation;
+ DD.Triggered = false;
+ DD.Loc = Loc;
+ DD.DeprecationData.Decl = D;
+ char *MessageData = 0;
+ if (Msg.size()) {
+ MessageData = new char [Msg.size()];
+ memcpy(MessageData, Msg.data(), Msg.size());
+ }
+
+ DD.DeprecationData.Message = MessageData;
+ DD.DeprecationData.MessageLen = Msg.size();
+ return DD;
+}
+
+void DelayedDiagnostic::Destroy() {
+ switch (Kind) {
+ case Access:
+ getAccessData().~AccessedEntity();
+ break;
+
+ case Deprecation:
+ delete [] DeprecationData.Message;
+ break;
+ }
+}
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 3f16ed772352..95420a316ad0 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -104,7 +104,8 @@ IdentifierResolver::~IdentifierResolver() {
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
- ASTContext &Context, Scope *S) const {
+ ASTContext &Context, Scope *S,
+ bool ExplicitInstantiationOrSpecialization) const {
Ctx = Ctx->getRedeclContext();
if (Ctx->isFunctionOrMethod()) {
@@ -135,7 +136,10 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
return false;
}
- return D->getDeclContext()->getRedeclContext()->Equals(Ctx);
+ DeclContext *DCtx = D->getDeclContext()->getRedeclContext();
+ return ExplicitInstantiationOrSpecialization
+ ? Ctx->InEnclosingNamespaceSetOf(DCtx)
+ : Ctx->Equals(DCtx);
}
/// AddDecl - Link the decl to its shadowed decl chain.
@@ -164,6 +168,44 @@ void IdentifierResolver::AddDecl(NamedDecl *D) {
IDI->AddDecl(D);
}
+void IdentifierResolver::InsertDeclAfter(iterator Pos, NamedDecl *D) {
+ DeclarationName Name = D->getDeclName();
+ void *Ptr = Name.getFETokenInfo<void>();
+
+ if (!Ptr) {
+ AddDecl(D);
+ return;
+ }
+
+ if (isDeclPtr(Ptr)) {
+ // We only have a single declaration: insert before or after it,
+ // as appropriate.
+ if (Pos == iterator()) {
+ // Add the new declaration before the existing declaration.
+ NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
+ RemoveDecl(PrevD);
+ AddDecl(D);
+ AddDecl(PrevD);
+ } else {
+ // Add new declaration after the existing declaration.
+ AddDecl(D);
+ }
+
+ return;
+ }
+
+ if (IdentifierInfo *II = Name.getAsIdentifierInfo())
+ II->setIsFromAST(false);
+
+ // General case: insert the declaration at the appropriate point in the
+ // list, which already has at least two elements.
+ IdDeclInfo *IDI = toIdDeclInfo(Ptr);
+ if (Pos.isIterator()) {
+ IDI->InsertDecl(Pos.getIterator() + 1, D);
+ } else
+ IDI->InsertDecl(IDI->decls_begin(), D);
+}
+
/// RemoveDecl - Unlink the decl from its shadowed decl chain.
/// The decl must already be part of the decl chain.
void IdentifierResolver::RemoveDecl(NamedDecl *D) {
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index b73f0e9f1452..867d78fef6a7 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -149,6 +149,11 @@ static std::pair<unsigned,unsigned>
return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
}
+ if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) {
+ if (TD->getUnderlyingType()->isVariablyModifiedType())
+ return std::make_pair((unsigned) diag::note_protected_by_vla_type_alias, 0);
+ }
+
return std::make_pair(0U, 0U);
}
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
new file mode 100644
index 000000000000..833a59fdceea
--- /dev/null
+++ b/lib/Sema/Scope.cpp
@@ -0,0 +1,57 @@
+//===- Scope.cpp - Lexical scope information --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Scope class, which is used for recording
+// information about a lexical scope.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Scope.h"
+
+using namespace clang;
+
+void Scope::Init(Scope *parent, unsigned flags) {
+ AnyParent = parent;
+ Flags = flags;
+
+ if (parent) {
+ Depth = parent->Depth + 1;
+ PrototypeDepth = parent->PrototypeDepth;
+ PrototypeIndex = 0;
+ FnParent = parent->FnParent;
+ BreakParent = parent->BreakParent;
+ ContinueParent = parent->ContinueParent;
+ ControlParent = parent->ControlParent;
+ BlockParent = parent->BlockParent;
+ TemplateParamParent = parent->TemplateParamParent;
+ } else {
+ Depth = 0;
+ PrototypeDepth = 0;
+ PrototypeIndex = 0;
+ FnParent = BreakParent = ContinueParent = BlockParent = 0;
+ ControlParent = 0;
+ TemplateParamParent = 0;
+ }
+
+ // If this scope is a function or contains breaks/continues, remember it.
+ if (flags & FnScope) FnParent = this;
+ if (flags & BreakScope) BreakParent = this;
+ if (flags & ContinueScope) ContinueParent = this;
+ if (flags & ControlScope) ControlParent = this;
+ if (flags & BlockScope) BlockParent = this;
+ if (flags & TemplateParamScope) TemplateParamParent = this;
+
+ // If this is a prototype scope, record that.
+ if (flags & FunctionPrototypeScope) PrototypeDepth++;
+
+ DeclsInScope.clear();
+ UsingDirectives.clear();
+ Entity = 0;
+ ErrorTrap.reset();
+}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 0c39e1325393..7707fb1104be 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -67,12 +67,14 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty);
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
SourceLocation(),
+ SourceLocation(),
&Context.Idents.get("__int128_t"),
TInfo), TUScope);
TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty);
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
SourceLocation(),
+ SourceLocation(),
&Context.Idents.get("__uint128_t"),
TInfo), TUScope);
Context.setInt128Installed();
@@ -87,7 +89,8 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy);
TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT);
TypedefDecl *SelTypedef
- = TypedefDecl::Create(Context, CurContext, SourceLocation(),
+ = TypedefDecl::Create(Context, CurContext,
+ SourceLocation(), SourceLocation(),
&Context.Idents.get("SEL"), SelInfo);
PushOnScopeChains(SelTypedef, TUScope);
Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
@@ -109,7 +112,8 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
T = Context.getObjCObjectPointerType(T);
TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T);
TypedefDecl *IdTypedef
- = TypedefDecl::Create(Context, CurContext, SourceLocation(),
+ = TypedefDecl::Create(Context, CurContext,
+ SourceLocation(), SourceLocation(),
&Context.Idents.get("id"), IdInfo);
PushOnScopeChains(IdTypedef, TUScope);
Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
@@ -121,7 +125,8 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
T = Context.getObjCObjectPointerType(T);
TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T);
TypedefDecl *ClassTypedef
- = TypedefDecl::Create(Context, CurContext, SourceLocation(),
+ = TypedefDecl::Create(Context, CurContext,
+ SourceLocation(), SourceLocation(),
&Context.Idents.get("Class"), ClassInfo);
PushOnScopeChains(ClassTypedef, TUScope);
Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
@@ -136,7 +141,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
- PackContext(0), VisContext(0),
+ PackContext(0), MSStructPragmaOn(false), VisContext(0),
+ LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -178,7 +184,7 @@ Sema::~Sema() {
if (PackContext) FreePackedContext();
if (VisContext) FreeVisContext();
delete TheTargetAttributesSema;
-
+ MSStructPragmaOn = false;
// Kill all the active scopes.
for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I)
delete FunctionScopes[I];
@@ -195,39 +201,58 @@ Sema::~Sema() {
ExternalSema->ForgetSema();
}
+ASTMutationListener *Sema::getASTMutationListener() const {
+ return getASTConsumer().GetASTMutationListener();
+}
+
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// The result is of the given category.
-void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
- CastKind Kind, ExprValueKind VK,
- const CXXCastPath *BasePath) {
- QualType ExprTy = Context.getCanonicalType(Expr->getType());
+ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
+ CastKind Kind, ExprValueKind VK,
+ const CXXCastPath *BasePath) {
+ QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
if (ExprTy == TypeTy)
- return;
+ return Owned(E);
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
if (Kind == CK_DerivedToBase &&
BasePathInvolvesVirtualBase(*BasePath)) {
- QualType T = Expr->getType();
+ QualType T = E->getType();
if (const PointerType *Pointer = T->getAs<PointerType>())
T = Pointer->getPointeeType();
if (const RecordType *RecordTy = T->getAs<RecordType>())
- MarkVTableUsed(Expr->getLocStart(),
+ MarkVTableUsed(E->getLocStart(),
cast<CXXRecordDecl>(RecordTy->getDecl()));
}
- if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
+ if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) {
ImpCast->setType(Ty);
ImpCast->setValueKind(VK);
- return;
+ return Owned(E);
}
}
- Expr = ImplicitCastExpr::Create(Context, Ty, Kind, Expr, BasePath, VK);
+ return Owned(ImplicitCastExpr::Create(Context, Ty, Kind, E, BasePath, VK));
+}
+
+/// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
+/// to the conversion from scalar type ScalarTy to the Boolean type.
+CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) {
+ switch (ScalarTy->getScalarTypeKind()) {
+ case Type::STK_Bool: return CK_NoOp;
+ case Type::STK_Pointer: return CK_PointerToBoolean;
+ case Type::STK_MemberPointer: return CK_MemberPointerToBoolean;
+ case Type::STK_Integral: return CK_IntegralToBoolean;
+ case Type::STK_Floating: return CK_FloatingToBoolean;
+ case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean;
+ case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean;
+ }
+ return CK_Invalid;
}
ExprValueKind Sema::CastCategory(Expr *E) {
@@ -352,22 +377,30 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
- // If DefinedUsedVTables ends up marking any virtual member functions it
- // might lead to more pending template instantiations, which we then need
- // to instantiate.
- DefineUsedVTables();
-
- // C++: Perform implicit template instantiations.
- //
- // FIXME: When we perform these implicit instantiations, we do not
- // carefully keep track of the point of instantiation (C++ [temp.point]).
- // This means that name lookup that occurs within the template
- // instantiation will always happen at the end of the translation unit,
- // so it will find some names that should not be found. Although this is
- // common behavior for C++ compilers, it is technically wrong. In the
- // future, we either need to be able to filter the results of name lookup
- // or we need to perform template instantiations earlier.
- PerformPendingInstantiations();
+ bool SomethingChanged;
+ do {
+ SomethingChanged = false;
+
+ // If DefinedUsedVTables ends up marking any virtual member functions it
+ // might lead to more pending template instantiations, which we then need
+ // to instantiate.
+ if (DefineUsedVTables())
+ SomethingChanged = true;
+
+ // C++: Perform implicit template instantiations.
+ //
+ // FIXME: When we perform these implicit instantiations, we do not
+ // carefully keep track of the point of instantiation (C++ [temp.point]).
+ // This means that name lookup that occurs within the template
+ // instantiation will always happen at the end of the translation unit,
+ // so it will find some names that should not be found. Although this is
+ // common behavior for C++ compilers, it is technically wrong. In the
+ // future, we either need to be able to filter the results of name lookup
+ // or we need to perform template instantiations earlier.
+ if (PerformPendingInstantiations())
+ SomethingChanged = true;
+
+ } while (SomethingChanged);
}
// Remove file scoped decls that turned out to be used.
@@ -451,16 +484,32 @@ void Sema::ActOnEndOfTranslationUnit() {
const FunctionDecl *DiagD;
if (!FD->hasBody(DiagD))
DiagD = FD;
- Diag(DiagD->getLocation(),
- isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
- : diag::warn_unused_function)
- << DiagD->getDeclName();
+ if (DiagD->isDeleted())
+ continue; // Deleted functions are supposed to be unused.
+ if (DiagD->isReferenced()) {
+ if (isa<CXXMethodDecl>(DiagD))
+ Diag(DiagD->getLocation(), diag::warn_unneeded_member_function)
+ << DiagD->getDeclName();
+ else
+ Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
+ << /*function*/0 << DiagD->getDeclName();
+ } else {
+ Diag(DiagD->getLocation(),
+ isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
+ : diag::warn_unused_function)
+ << DiagD->getDeclName();
+ }
} else {
const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition();
if (!DiagD)
DiagD = cast<VarDecl>(*I);
- Diag(DiagD->getLocation(), diag::warn_unused_variable)
- << DiagD->getDeclName();
+ if (DiagD->isReferenced()) {
+ Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
+ << /*variable*/1 << DiagD->getDeclName();
+ } else {
+ Diag(DiagD->getLocation(), diag::warn_unused_variable)
+ << DiagD->getDeclName();
+ }
}
}
@@ -585,6 +634,27 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
return Builder;
}
+/// \brief Looks through the macro-instantiation chain for the given
+/// location, looking for a macro instantiation with the given name.
+/// If one is found, returns true and sets the location to that
+/// instantiation loc.
+bool Sema::findMacroSpelling(SourceLocation &locref, llvm::StringRef name) {
+ SourceLocation loc = locref;
+ if (!loc.isMacroID()) return false;
+
+ // There's no good way right now to look at the intermediate
+ // instantiations, so just jump to the instantiation location.
+ loc = getSourceManager().getInstantiationLoc(loc);
+
+ // If that's written with the name, stop here.
+ llvm::SmallVector<char, 16> buffer;
+ if (getPreprocessor().getSpelling(loc, buffer) == name) {
+ locref = loc;
+ return true;
+ }
+ return false;
+}
+
/// \brief Determines the active Scope associated with the given declaration
/// context.
///
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 4f9bf1c5edd7..411d424dd8df 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -1011,16 +1011,16 @@ static void DiagnoseAccessPath(Sema &S,
// Find an original declaration.
while (D->isOutOfLine()) {
NamedDecl *PrevDecl = 0;
- if (isa<VarDecl>(D))
- PrevDecl = cast<VarDecl>(D)->getPreviousDeclaration();
- else if (isa<FunctionDecl>(D))
- PrevDecl = cast<FunctionDecl>(D)->getPreviousDeclaration();
- else if (isa<TypedefDecl>(D))
- PrevDecl = cast<TypedefDecl>(D)->getPreviousDeclaration();
- else if (isa<TagDecl>(D)) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ PrevDecl = VD->getPreviousDeclaration();
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ PrevDecl = FD->getPreviousDeclaration();
+ else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
+ PrevDecl = TND->getPreviousDeclaration();
+ else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
break;
- PrevDecl = cast<TagDecl>(D)->getPreviousDeclaration();
+ PrevDecl = TD->getPreviousDeclaration();
}
if (!PrevDecl) break;
D = PrevDecl;
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 794b0b1f1cfa..53dd297aebb3 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -129,6 +129,12 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
}
}
+void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
+ if (!MSStructPragmaOn)
+ return;
+ RD->addAttr(::new (Context) MsStructAttr(SourceLocation(), Context));
+}
+
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc,
SourceLocation KindLoc) {
@@ -263,6 +269,10 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
}
}
+void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
+ MSStructPragmaOn = (Kind == PMSST_ON);
+}
+
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
SourceLocation PragmaLoc) {
@@ -297,7 +307,7 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) {
if (!VisContext)
return;
- if (D->hasAttr<VisibilityAttr>())
+ if (isa<NamedDecl>(D) && cast<NamedDecl>(D)->getExplicitVisibility())
return;
VisStack *Stack = static_cast<VisStack*>(VisContext);
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 506d2612ffbc..ed54f0f54425 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -42,21 +42,21 @@ enum CastType {
-static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+static void CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
ExprValueKind &VK,
const SourceRange &OpRange,
const SourceRange &DestRange);
-static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+static void CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
ExprValueKind &VK,
const SourceRange &OpRange,
const SourceRange &DestRange,
CastKind &Kind);
-static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+static void CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
ExprValueKind &VK,
const SourceRange &OpRange,
CastKind &Kind,
CXXCastPath &BasePath);
-static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
ExprValueKind &VK,
const SourceRange &OpRange,
const SourceRange &DestRange,
@@ -100,7 +100,7 @@ static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType,
QualType OrigDestType, unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath);
-static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr,
+static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr,
QualType SrcType,
QualType DestType,bool CStyle,
const SourceRange &OpRange,
@@ -108,12 +108,12 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr,
CastKind &Kind,
CXXCastPath &BasePath);
-static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr,
+static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind);
-static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
@@ -121,24 +121,13 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
CXXCastPath &BasePath);
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, unsigned &msg);
-static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
+static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind);
-static ExprResult
-ResolveAndFixSingleFunctionTemplateSpecialization(
- Sema &Self, Expr *SrcExpr,
- bool DoFunctionPointerConverion = false,
- bool Complain = false,
- const SourceRange& OpRangeForComplaining = SourceRange(),
- QualType DestTypeForComplaining = QualType(),
- unsigned DiagIDForComplaining = 0);
-
-
-
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
ExprResult
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
@@ -159,8 +148,9 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
ExprResult
Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
- TypeSourceInfo *DestTInfo, Expr *Ex,
+ TypeSourceInfo *DestTInfo, Expr *E,
SourceRange AngleBrackets, SourceRange Parens) {
+ ExprResult Ex = Owned(E);
QualType DestType = DestTInfo->getType();
SourceRange OpRange(OpLoc, Parens.getEnd());
@@ -168,11 +158,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
// If the type is dependent, we won't do the semantic analysis now.
// FIXME: should we check this in a more fine-grained manner?
- bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent();
-
- if (Ex->isBoundMemberFunction(Context))
- Diag(Ex->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << Ex->getSourceRange();
+ bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent();
ExprValueKind VK = VK_RValue;
if (TypeDependent)
@@ -182,42 +168,54 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
default: llvm_unreachable("Unknown C++ cast!");
case tok::kw_const_cast:
- if (!TypeDependent)
+ if (!TypeDependent) {
CheckConstCast(*this, Ex, DestType, VK, OpRange, DestRange);
+ if (Ex.isInvalid())
+ return ExprError();
+ }
return Owned(CXXConstCastExpr::Create(Context,
DestType.getNonLValueExprType(Context),
- VK, Ex, DestTInfo, OpLoc,
+ VK, Ex.take(), DestTInfo, OpLoc,
Parens.getEnd()));
case tok::kw_dynamic_cast: {
CastKind Kind = CK_Dependent;
CXXCastPath BasePath;
- if (!TypeDependent)
+ if (!TypeDependent) {
CheckDynamicCast(*this, Ex, DestType, VK, OpRange, DestRange,
Kind, BasePath);
+ if (Ex.isInvalid())
+ return ExprError();
+ }
return Owned(CXXDynamicCastExpr::Create(Context,
DestType.getNonLValueExprType(Context),
- VK, Kind, Ex, &BasePath, DestTInfo,
+ VK, Kind, Ex.take(), &BasePath, DestTInfo,
OpLoc, Parens.getEnd()));
}
case tok::kw_reinterpret_cast: {
CastKind Kind = CK_Dependent;
- if (!TypeDependent)
+ if (!TypeDependent) {
CheckReinterpretCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind);
+ if (Ex.isInvalid())
+ return ExprError();
+ }
return Owned(CXXReinterpretCastExpr::Create(Context,
DestType.getNonLValueExprType(Context),
- VK, Kind, Ex, 0,
+ VK, Kind, Ex.take(), 0,
DestTInfo, OpLoc, Parens.getEnd()));
}
case tok::kw_static_cast: {
CastKind Kind = CK_Dependent;
CXXCastPath BasePath;
- if (!TypeDependent)
+ if (!TypeDependent) {
CheckStaticCast(*this, Ex, DestType, VK, OpRange, Kind, BasePath);
+ if (Ex.isInvalid())
+ return ExprError();
+ }
return Owned(CXXStaticCastExpr::Create(Context,
DestType.getNonLValueExprType(Context),
- VK, Kind, Ex, &BasePath,
+ VK, Kind, Ex.take(), &BasePath,
DestTInfo, OpLoc, Parens.getEnd()));
}
}
@@ -303,6 +301,11 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
/// Diagnose a failed cast.
static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
SourceRange opRange, Expr *src, QualType destType) {
+ if (src->getType() == S.Context.BoundMemberTy) {
+ (void) S.CheckPlaceholderExpr(src); // will always fail
+ return;
+ }
+
if (msg == diag::err_bad_cxx_cast_generic &&
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType))
return;
@@ -388,15 +391,17 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
UnwrappedDestType = Self.Context.getCanonicalType(DestType);
llvm::SmallVector<Qualifiers, 8> cv1, cv2;
- // Find the qualifications.
+ // Find the qualifiers. We only care about cvr-qualifiers for the
+ // purpose of this check, because other qualifiers (address spaces,
+ // Objective-C GC, etc.) are part of the type's identity.
while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
Qualifiers SrcQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
- cv1.push_back(SrcQuals);
+ cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()));
Qualifiers DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
- cv2.push_back(DestQuals);
+ cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()));
}
if (cv1.empty())
return false;
@@ -424,11 +429,11 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
/// checked downcasts in class hierarchies.
static void
-CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
ExprValueKind &VK, const SourceRange &OpRange,
const SourceRange &DestRange, CastKind &Kind,
CXXCastPath &BasePath) {
- QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
+ QualType OrigDestType = DestType, OrigSrcType = SrcExpr.get()->getType();
DestType = Self.Context.getCanonicalType(DestType);
// C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
@@ -475,11 +480,11 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
SrcPointee = SrcPointer->getPointeeType();
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
- << OrigSrcType << SrcExpr->getSourceRange();
+ << OrigSrcType << SrcExpr.get()->getSourceRange();
return;
}
} else if (DestReference->isLValueReferenceType()) {
- if (!SrcExpr->isLValue()) {
+ if (!SrcExpr.get()->isLValue()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
<< CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
}
@@ -492,11 +497,11 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
Self.PDiag(diag::err_bad_dynamic_cast_incomplete)
- << SrcExpr->getSourceRange()))
+ << SrcExpr.get()->getSourceRange()))
return;
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
- << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
+ << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange();
return;
}
@@ -508,7 +513,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
<< CT_Dynamic << OrigSrcType << OrigDestType << OpRange;
return;
}
@@ -543,7 +548,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
assert(SrcDecl && "Definition missing");
if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
- << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
+ << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange();
}
Self.MarkVTableUsed(OpRange.getBegin(),
cast<CXXRecordDecl>(SrcRecord->getDecl()));
@@ -558,17 +563,20 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
/// const char *str = "literal";
/// legacy_function(const_cast\<char*\>(str));
void
-CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, ExprValueKind &VK,
+CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK,
const SourceRange &OpRange, const SourceRange &DestRange) {
VK = Expr::getValueKindForType(DestType);
- if (VK == VK_RValue)
- Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
+ if (VK == VK_RValue) {
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
+ }
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
+ if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success
&& msg != 0)
Self.Diag(OpRange.getBegin(), msg) << CT_Const
- << SrcExpr->getType() << DestType << OpRange;
+ << SrcExpr.get()->getType() << DestType << OpRange;
}
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
@@ -577,27 +585,32 @@ CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, ExprValueKind &VK,
/// like this:
/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
void
-CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
ExprValueKind &VK, const SourceRange &OpRange,
const SourceRange &DestRange, CastKind &Kind) {
VK = Expr::getValueKindForType(DestType);
- if (VK == VK_RValue)
- Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
+ if (VK == VK_RValue) {
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
+ }
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
msg, Kind)
!= TC_Success && msg != 0)
{
- if (SrcExpr->getType() == Self.Context.OverloadTy) {
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
+ if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
//FIXME: &f<int>; is overloaded and resolvable
Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload)
- << OverloadExpr::find(SrcExpr).Expression->getName()
+ << OverloadExpr::find(SrcExpr.get()).Expression->getName()
<< DestType << OpRange;
- Self.NoteAllOverloadCandidates(SrcExpr);
+ Self.NoteAllOverloadCandidates(SrcExpr.get());
} else {
- diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType);
+ diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType);
}
}
}
@@ -607,23 +620,25 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making
/// implicit conversions explicit and getting rid of data loss warnings.
void
-CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
ExprValueKind &VK, const SourceRange &OpRange,
CastKind &Kind, CXXCastPath &BasePath) {
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
if (DestType->isVoidType()) {
- Self.IgnoredValueConversions(SrcExpr);
- if (SrcExpr->getType() == Self.Context.OverloadTy) {
+ SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
+ if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
ExprResult SingleFunctionExpression =
- ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr,
+ Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(),
false, // Decay Function to ptr
true, // Complain
OpRange, DestType, diag::err_bad_static_cast_overload);
if (SingleFunctionExpression.isUsable())
{
- SrcExpr = SingleFunctionExpression.release();
+ SrcExpr = SingleFunctionExpression;
Kind = CK_ToVoid;
}
}
@@ -633,29 +648,35 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
}
VK = Expr::getValueKindForType(DestType);
- if (VK == VK_RValue && !DestType->isRecordType())
- Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
+ if (VK == VK_RValue && !DestType->isRecordType()) {
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
+ }
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
Kind, BasePath) != TC_Success && msg != 0) {
- if (SrcExpr->getType() == Self.Context.OverloadTy) {
- OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
+ if (SrcExpr.isInvalid())
+ return;
+ if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
+ OverloadExpr* oe = OverloadExpr::find(SrcExpr.get()).Expression;
Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload)
- << oe->getName() << DestType << OpRange << oe->getQualifierRange();
- Self.NoteAllOverloadCandidates(SrcExpr);
+ << oe->getName() << DestType << OpRange
+ << oe->getQualifierLoc().getSourceRange();
+ Self.NoteAllOverloadCandidates(SrcExpr.get());
} else {
- diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType);
+ diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType);
}
}
else if (Kind == CK_BitCast)
- Self.CheckCastAlign(SrcExpr, DestType, OpRange);
+ Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
}
/// TryStaticCast - Check if a static cast can be performed, and do so if
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
-static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind,
@@ -680,7 +701,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// C++ 5.2.9p5, reference downcast.
// See the function for details.
// DR 427 specifies that this is to be applied before paragraph 2.
- tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange,
+ tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle, OpRange,
msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
@@ -688,7 +709,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// C++0x [expr.static.cast]p3:
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2
// T2" if "cv2 T2" is reference-compatible with "cv1 T1".
- tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, CStyle, Kind, BasePath,
+ tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, BasePath,
msg);
if (tcr != TC_NotApplicable)
return tcr;
@@ -697,6 +718,8 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
Kind);
+ if (SrcExpr.isInvalid())
+ return TC_Failed;
if (tcr != TC_NotApplicable)
return tcr;
@@ -708,7 +731,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// In the CStyle case, the earlier attempt to const_cast should have taken
// care of reverse qualification conversions.
- QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType());
+ QualType SrcType = Self.Context.getCanonicalType(SrcExpr.get()->getType());
// C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly
// converted to an integral type. [...] A value of a scoped enumeration type
@@ -772,7 +795,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// This is definitely the intended conversion, but it might fail due
// to a const violation.
if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
Kind = CK_BitCast;
@@ -963,7 +986,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
// Must preserve cv, as always, unless we're in C-style mode.
if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1038,7 +1061,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
/// where B is a base class of D [...].
///
TryCastResult
-TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
+TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg, CastKind &Kind,
@@ -1049,9 +1072,9 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
bool WasOverloadedFunction = false;
DeclAccessPair FoundOverload;
- if (SrcExpr->getType() == Self.Context.OverloadTy) {
+ if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
if (FunctionDecl *Fn
- = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false,
+ = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), DestType, false,
FoundOverload)) {
CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
SrcType = Self.Context.getMemberPointerType(Fn->getType(),
@@ -1122,7 +1145,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
if (WasOverloadedFunction) {
// Resolve the address of the overloaded function again, this time
// allowing complaints if something goes wrong.
- FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr,
+ FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(),
DestType,
true,
FoundOverload);
@@ -1132,7 +1155,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
}
SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn);
- if (!SrcExpr) {
+ if (!SrcExpr.isUsable()) {
msg = 0;
return TC_Failed;
}
@@ -1149,7 +1172,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
/// An expression e can be explicitly converted to a type T using a
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
-TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
+TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange, unsigned &msg,
CastKind &Kind) {
if (DestType->isRecordType()) {
@@ -1163,7 +1186,8 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
= InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle);
- InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
+ Expr *SrcExprRaw = SrcExpr.get();
+ InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1);
// At this point of CheckStaticCast, if the destination is a reference,
// or the expression is an overload expression this has to work.
@@ -1176,7 +1200,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return TC_NotApplicable;
ExprResult Result
- = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExpr, 1));
+ = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExprRaw, 1));
if (Result.isInvalid()) {
msg = 0;
return TC_Failed;
@@ -1187,7 +1211,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
else
Kind = CK_NoOp;
- SrcExpr = Result.takeAs<Expr>();
+ SrcExpr = move(Result);
return TC_Success;
}
@@ -1240,16 +1264,21 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// Unwrap the pointers. Ignore qualifiers. Terminate early if the types are
// completely equal.
- // FIXME: const_cast should probably not be able to convert between pointers
- // to different address spaces.
// C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers
// in multi-level pointers may change, but the level count must be the same,
// as must be the final pointee type.
while (SrcType != DestType &&
Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) {
- Qualifiers Quals;
- SrcType = Self.Context.getUnqualifiedArrayType(SrcType, Quals);
- DestType = Self.Context.getUnqualifiedArrayType(DestType, Quals);
+ Qualifiers SrcQuals, DestQuals;
+ SrcType = Self.Context.getUnqualifiedArrayType(SrcType, SrcQuals);
+ DestType = Self.Context.getUnqualifiedArrayType(DestType, DestQuals);
+
+ // const_cast is permitted to strip cvr-qualifiers, only. Make sure that
+ // the other qualifiers (e.g., address spaces) are identical.
+ SrcQuals.removeCVRQualifiers();
+ DestQuals.removeCVRQualifiers();
+ if (SrcQuals != DestQuals)
+ return TC_NotApplicable;
}
// Since we're dealing in canonical types, the remainder must be the same.
@@ -1259,43 +1288,8 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TC_Success;
}
-// A helper function to resolve and fix an overloaded expression that
-// can be resolved because it identifies a single function
-// template specialization
-// Last three arguments should only be supplied if Complain = true
-static ExprResult ResolveAndFixSingleFunctionTemplateSpecialization(
- Sema &Self, Expr *SrcExpr,
- bool DoFunctionPointerConverion,
- bool Complain,
- const SourceRange& OpRangeForComplaining,
- QualType DestTypeForComplaining,
- unsigned DiagIDForComplaining) {
- assert(SrcExpr->getType() == Self.Context.OverloadTy);
- DeclAccessPair Found;
- Expr* SingleFunctionExpression = 0;
- if (FunctionDecl* Fn = Self.ResolveSingleFunctionTemplateSpecialization(
- SrcExpr, false, // false -> Complain
- &Found)) {
- if (!Self.DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) {
- // mark the expression as resolved to Fn
- SingleFunctionExpression = Self.FixOverloadedFunctionReference(SrcExpr,
- Found, Fn);
-
- if (DoFunctionPointerConverion)
- Self.DefaultFunctionArrayLvalueConversion(SingleFunctionExpression);
- }
- }
- if (!SingleFunctionExpression && Complain) {
- OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
- Self.Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
- << oe->getName() << DestTypeForComplaining << OpRangeForComplaining
- << oe->getQualifierRange();
- Self.NoteAllOverloadCandidates(SrcExpr);
- }
- return SingleFunctionExpression;
-}
-static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
+static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
@@ -1303,19 +1297,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
bool IsLValueCast = false;
DestType = Self.Context.getCanonicalType(DestType);
- QualType SrcType = SrcExpr->getType();
+ QualType SrcType = SrcExpr.get()->getType();
// Is the source an overloaded name? (i.e. &foo)
// If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ...
if (SrcType == Self.Context.OverloadTy) {
// ... unless foo<int> resolves to an lvalue unambiguously
ExprResult SingleFunctionExpr =
- ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr,
+ Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(),
Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
);
if (SingleFunctionExpr.isUsable()) {
- SrcExpr = SingleFunctionExpr.release();
- SrcType = SrcExpr->getType();
+ SrcExpr = move(SingleFunctionExpr);
+ SrcType = SrcExpr.get()->getType();
}
else
return TC_NotApplicable;
@@ -1323,7 +1317,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
bool LValue = DestTypeTmp->isLValueReferenceType();
- if (LValue && !SrcExpr->isLValue()) {
+ if (LValue && !SrcExpr.get()->isLValue()) {
// Cannot cast non-lvalue to lvalue reference type. See the similar
// comment in const_cast.
msg = diag::err_bad_cxx_cast_rvalue;
@@ -1333,6 +1327,23 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
// C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
// same effect as the conversion *reinterpret_cast<T*>(&x) with the
// built-in & and * operators.
+
+ const char *inappropriate = 0;
+ switch (SrcExpr.get()->getObjectKind()) {
+ case OK_Ordinary:
+ break;
+ case OK_BitField: inappropriate = "bit-field"; break;
+ case OK_VectorComponent: inappropriate = "vector element"; break;
+ case OK_ObjCProperty: inappropriate = "property expression"; break;
+ }
+ if (inappropriate) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_reference)
+ << inappropriate << DestType
+ << OpRange << SrcExpr.get()->getSourceRange();
+ msg = 0; SrcExpr = ExprError();
+ return TC_NotApplicable;
+ }
+
// This code does this transformation for the checked types.
DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
SrcType = Self.Context.getPointerType(SrcType);
@@ -1359,7 +1370,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
// A reinterpret_cast followed by a const_cast can, though, so in C-style,
// we accept it.
if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1472,7 +1483,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
// C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
// The C-style cast operator can.
if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
- msg = diag::err_bad_cxx_cast_const_away;
+ msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1525,39 +1536,39 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr,
return TC_Success;
}
-bool
+ExprResult
Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
- Expr *&CastExpr, CastKind &Kind,
+ Expr *CastExpr, CastKind &Kind,
CXXCastPath &BasePath,
bool FunctionalStyle) {
- if (CastExpr->isBoundMemberFunction(Context))
- return Diag(CastExpr->getLocStart(),
- diag::err_invalid_use_of_bound_member_func)
- << CastExpr->getSourceRange();
-
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
if (CastTy->isVoidType()) {
- IgnoredValueConversions(CastExpr);
- bool ret = false; // false is 'able to convert'
+ Kind = CK_ToVoid;
+
+ ExprResult CastExprRes = IgnoredValueConversions(CastExpr);
+ if (CastExprRes.isInvalid())
+ return ExprError();
+ CastExpr = CastExprRes.take();
+
+ if (CastExpr->getType() == Context.BoundMemberTy)
+ return CheckPlaceholderExpr(CastExpr); // will always fail
+
if (CastExpr->getType() == Context.OverloadTy) {
ExprResult SingleFunctionExpr =
- ResolveAndFixSingleFunctionTemplateSpecialization(*this,
- CastExpr,
- /* Decay Function to ptr */ false,
- /* Complain */ true,
- R, CastTy, diag::err_bad_cstyle_cast_overload);
- if (SingleFunctionExpr.isUsable()) {
- CastExpr = SingleFunctionExpr.release();
- Kind = CK_ToVoid;
- }
- else
- ret = true;
+ ResolveAndFixSingleFunctionTemplateSpecialization(
+ CastExpr, /* Decay Function to ptr */ false,
+ /* Complain */ true, R, CastTy,
+ diag::err_bad_cstyle_cast_overload);
+ if (SingleFunctionExpr.isInvalid())
+ return ExprError();
+ CastExpr = SingleFunctionExpr.take();
}
- else
- Kind = CK_ToVoid;
- return ret;
+
+ assert(!CastExpr->getType()->isPlaceholderType());
+
+ return Owned(CastExpr);
}
// Make sure we determine the value kind before we bail out for
@@ -1567,11 +1578,24 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
// If the type is dependent, we won't do any other semantic analysis now.
if (CastTy->isDependentType() || CastExpr->isTypeDependent()) {
Kind = CK_Dependent;
- return false;
+ return Owned(CastExpr);
+ }
+
+ if (VK == VK_RValue && !CastTy->isRecordType()) {
+ ExprResult CastExprRes = DefaultFunctionArrayLvalueConversion(CastExpr);
+ if (CastExprRes.isInvalid())
+ return ExprError();
+ CastExpr = CastExprRes.take();
}
- if (VK == VK_RValue && !CastTy->isRecordType())
- DefaultFunctionArrayLvalueConversion(CastExpr);
+ // AltiVec vector initialization with a single literal.
+ if (const VectorType *vecTy = CastTy->getAs<VectorType>())
+ if (vecTy->getVectorKind() == VectorType::AltiVecVector
+ && (CastExpr->getType()->isIntegerType()
+ || CastExpr->getType()->isFloatingType())) {
+ Kind = CK_VectorSplat;
+ return Owned(CastExpr);
+ }
// C++ [expr.cast]p5: The conversions performed by
// - a const_cast,
@@ -1592,25 +1616,32 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
- tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind,
- BasePath);
+ ExprResult CastExprRes = Owned(CastExpr);
+ tcr = TryStaticCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, msg,
+ Kind, BasePath);
+ if (CastExprRes.isInvalid())
+ return ExprError();
+ CastExpr = CastExprRes.take();
if (tcr == TC_NotApplicable) {
// ... and finally a reinterpret_cast, ignoring const.
- tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
- Kind);
+ CastExprRes = Owned(CastExpr);
+ tcr = TryReinterpretCast(*this, CastExprRes, CastTy, /*CStyle*/true, R,
+ msg, Kind);
+ if (CastExprRes.isInvalid())
+ return ExprError();
+ CastExpr = CastExprRes.take();
}
}
if (tcr != TC_Success && msg != 0) {
if (CastExpr->getType() == Context.OverloadTy) {
DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr,
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr,
CastTy,
/* Complain */ true,
Found);
- assert(!Fn
- && "cast failed but able to resolve overload expression!!");
+ assert(!Fn && "cast failed but able to resolve overload expression!!");
(void)Fn;
} else {
@@ -1621,5 +1652,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
else if (Kind == CK_BitCast)
CheckCastAlign(CastExpr, CastTy, R);
- return tcr != TC_Success;
+ if (tcr != TC_Success)
+ return ExprError();
+
+ return Owned(CastExpr);
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 7ad4b459451d..7049f6b01d26 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -255,7 +255,7 @@ bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
if (T->isDependentType())
return true;
- else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
if (TD->getUnderlyingType()->isRecordType() ||
(Context.getLangOptions().CPlusPlus0x &&
TD->getUnderlyingType()->isEnumeralType()))
@@ -549,7 +549,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
} else if (isa<RecordDecl>(SD)) {
RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T);
RecordTL.setNameLoc(IdentifierLoc);
- } else if (isa<TypedefDecl>(SD)) {
+ } else if (isa<TypedefNameDecl>(SD)) {
TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T);
TypedefTL.setNameLoc(IdentifierLoc);
} else if (isa<EnumDecl>(SD)) {
@@ -641,20 +641,87 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
}
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- ParsedType Type,
+ SourceLocation TemplateLoc,
+ CXXScopeSpec &SS,
+ TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation RAngleLoc,
SourceLocation CCLoc,
- CXXScopeSpec &SS) {
+ bool EnteringContext) {
if (SS.isInvalid())
return true;
- TypeSourceInfo *TSInfo;
- QualType T = GetTypeFromParser(Type, &TSInfo);
+ // Translate the parser's template argument list in our AST format.
+ TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
+ translateTemplateArguments(TemplateArgsIn, TemplateArgs);
+
+ if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){
+ // Handle a dependent template specialization for which we cannot resolve
+ // the template name.
+ assert(DTN->getQualifier()
+ == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
+ QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ TemplateArgs);
+
+ // Create source-location information for this type.
+ TypeLocBuilder Builder;
+ DependentTemplateSpecializationTypeLoc SpecTL
+ = Builder.push<DependentTemplateSpecializationTypeLoc>(T);
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ SpecTL.setKeywordLoc(SourceLocation());
+ SpecTL.setNameLoc(TemplateNameLoc);
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
+
+ SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T),
+ CCLoc);
+ return false;
+ }
+
+
+ if (Template.get().getAsOverloadedTemplate() ||
+ isa<FunctionTemplateDecl>(Template.get().getAsTemplateDecl())) {
+ SourceRange R(TemplateNameLoc, RAngleLoc);
+ if (SS.getRange().isValid())
+ R.setBegin(SS.getRange().getBegin());
+
+ Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)
+ << Template.get() << R;
+ NoteAllFoundTemplates(Template.get());
+ return true;
+ }
+
+ // We were able to resolve the template name to an actual template.
+ // Build an appropriate nested-name-specifier.
+ QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc,
+ TemplateArgs);
if (T.isNull())
return true;
- assert(TSInfo && "Not TypeSourceInfo in nested-name-specifier?");
- // FIXME: location of the 'template' keyword?
- SS.Extend(Context, SourceLocation(), TSInfo->getTypeLoc(), CCLoc);
+ // FIXME: Template aliases will need to check the resulting type to make
+ // sure that it's either dependent or a tag type.
+
+ // Provide source-location information for the template specialization
+ // type.
+ TypeLocBuilder Builder;
+ TemplateSpecializationTypeLoc SpecTL
+ = Builder.push<TemplateSpecializationTypeLoc>(T);
+
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ SpecTL.setTemplateNameLoc(TemplateNameLoc);
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
+
+
+ SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T),
+ CCLoc);
return false;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index d83809d70897..dcfb7cc5214a 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -180,6 +180,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_lock_test_and_set:
case Builtin::BI__sync_lock_release:
+ case Builtin::BI__sync_swap:
return SemaBuiltinAtomicOverloaded(move(TheCallResult));
}
@@ -313,9 +314,14 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
for (specific_attr_iterator<NonNullAttr>
i = FDecl->specific_attr_begin<NonNullAttr>(),
e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- CheckNonNullArguments(*i, TheCall);
+ CheckNonNullArguments(*i, TheCall->getArgs(),
+ TheCall->getCallee()->getLocStart());
}
+ // Memset handling
+ if (FnInfo->isStr("memset"))
+ CheckMemsetArguments(TheCall);
+
return false;
}
@@ -414,7 +420,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
BUILTIN_ROW(__sync_val_compare_and_swap),
BUILTIN_ROW(__sync_bool_compare_and_swap),
BUILTIN_ROW(__sync_lock_test_and_set),
- BUILTIN_ROW(__sync_lock_release)
+ BUILTIN_ROW(__sync_lock_release),
+ BUILTIN_ROW(__sync_swap)
};
#undef BUILTIN_ROW
@@ -467,6 +474,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
NumFixed = 0;
ResultType = Context.VoidTy;
break;
+ case Builtin::BI__sync_swap: BuiltinIndex = 14; break;
}
// Now that we know how many fixed arguments we expect, first check that we
@@ -491,14 +499,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
for (unsigned i = 0; i != NumFixed; ++i) {
- Expr *Arg = TheCall->getArg(i+1);
+ ExprResult Arg = TheCall->getArg(i+1);
// If the argument is an implicit cast, then there was a promotion due to
// "...", just remove it now.
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg.get())) {
Arg = ICE->getSubExpr();
ICE->setSubExpr(0);
- TheCall->setArg(i+1, Arg);
+ TheCall->setArg(i+1, Arg.get());
}
// GCC does an implicit conversion to the pointer or integer ValType. This
@@ -506,7 +514,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
CastKind Kind = CK_Invalid;
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
- if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, VK, BasePath))
+ Arg = CheckCastTypes(Arg.get()->getSourceRange(), ValType, Arg.take(), Kind, VK, BasePath);
+ if (Arg.isInvalid())
return ExprError();
// Okay, we have something that *can* be converted to the right type. Check
@@ -515,8 +524,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
// FIXME: Do this check.
- ImpCastExprToType(Arg, ValType, Kind, VK, &BasePath);
- TheCall->setArg(i+1, Arg);
+ Arg = ImpCastExprToType(Arg.take(), ValType, Kind, VK, &BasePath);
+ TheCall->setArg(i+1, Arg.get());
}
// Switch the DeclRefExpr to refer to the new decl.
@@ -525,9 +534,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// Set the callee in the CallExpr.
// FIXME: This leaks the original parens and implicit casts.
- Expr *PromotedCall = DRE;
- UsualUnaryConversions(PromotedCall);
- TheCall->setCallee(PromotedCall);
+ ExprResult PromotedCall = UsualUnaryConversions(DRE);
+ if (PromotedCall.isInvalid())
+ return ExprError();
+ TheCall->setCallee(PromotedCall.take());
// Change the result type of the call to match the original value type. This
// is arbitrary, but the codegen for these builtins ins design to handle it
@@ -552,12 +562,6 @@ bool Sema::CheckObjCString(Expr *Arg) {
return true;
}
- size_t NulPos = Literal->getString().find('\0');
- if (NulPos != llvm::StringRef::npos) {
- Diag(getLocationOfStringLiteralByte(Literal, NulPos),
- diag::warn_cfstring_literal_contains_nul_character)
- << Arg->getSourceRange();
- }
if (Literal->containsNonAsciiOrNull()) {
llvm::StringRef String = Literal->getString();
unsigned NumBytes = String.size();
@@ -650,29 +654,31 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
- Expr *OrigArg0 = TheCall->getArg(0);
- Expr *OrigArg1 = TheCall->getArg(1);
+ ExprResult OrigArg0 = TheCall->getArg(0);
+ ExprResult OrigArg1 = TheCall->getArg(1);
// Do standard promotions between the two arguments, returning their common
// type.
QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false);
+ if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
+ return true;
// Make sure any conversions are pushed back into the call; this is
// type safe since unordered compare builtins are declared as "_Bool
// foo(...)".
- TheCall->setArg(0, OrigArg0);
- TheCall->setArg(1, OrigArg1);
+ TheCall->setArg(0, OrigArg0.get());
+ TheCall->setArg(1, OrigArg1.get());
- if (OrigArg0->isTypeDependent() || OrigArg1->isTypeDependent())
+ if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent())
return false;
// If the common type isn't a real floating type, then the arguments were
// invalid for this operation.
if (!Res->isRealFloatingType())
- return Diag(OrigArg0->getLocStart(),
+ return Diag(OrigArg0.get()->getLocStart(),
diag::err_typecheck_call_invalid_ordered_compare)
- << OrigArg0->getType() << OrigArg1->getType()
- << SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd());
+ << OrigArg0.get()->getType() << OrigArg1.get()->getType()
+ << SourceRange(OrigArg0.get()->getLocStart(), OrigArg1.get()->getLocEnd());
return false;
}
@@ -860,7 +866,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
/// int type). This simply type checks that type is one of the defined
/// constants (0-3).
-// For compatability check 0-3, llvm only handles 0 and 2.
+// For compatibility check 0-3, llvm only handles 0 and 2.
bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
llvm::APSInt Result;
@@ -903,6 +909,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
if (E->isTypeDependent() || E->isValueDependent())
return false;
+ E = E->IgnoreParens();
+
switch (E->getStmtClass()) {
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
@@ -925,11 +933,6 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
goto tryAgain;
}
- case Stmt::ParenExprClass: {
- E = cast<ParenExpr>(E)->getSubExpr();
- goto tryAgain;
- }
-
case Stmt::OpaqueValueExprClass:
if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
E = src;
@@ -1036,15 +1039,15 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
void
Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
- const CallExpr *TheCall) {
+ const Expr * const *ExprArgs,
+ SourceLocation CallSiteLoc) {
for (NonNullAttr::args_iterator i = NonNull->args_begin(),
e = NonNull->args_end();
i != e; ++i) {
- const Expr *ArgExpr = TheCall->getArg(*i);
+ const Expr *ArgExpr = ExprArgs[*i];
if (ArgExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull))
- Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
- << ArgExpr->getSourceRange();
+ Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
}
}
@@ -1218,10 +1221,12 @@ void CheckFormatHandler::HandleZeroPosition(const char *startPos,
}
void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
- // The presence of a null character is likely an error.
- S.Diag(getLocationOfByte(nullCharacter),
- diag::warn_printf_format_string_contains_null_char)
- << getFormatStringRange();
+ if (!IsObjCLiteral) {
+ // The presence of a null character is likely an error.
+ S.Diag(getLocationOfByte(nullCharacter),
+ diag::warn_printf_format_string_contains_null_char)
+ << getFormatStringRange();
+ }
}
const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
@@ -1790,6 +1795,54 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
}
}
+//===--- CHECK: Standard memory functions ---------------------------------===//
+
+/// \brief Check for dangerous or invalid arguments to memset().
+///
+/// This issues warnings on known problematic or dangerous or unspecified
+/// arguments to the standard 'memset' function call.
+///
+/// \param Call The call expression to diagnose.
+void Sema::CheckMemsetArguments(const CallExpr *Call) {
+ // It is possible to have a non-standard definition of memset. Validate
+ // we have the proper number of arguments, and if not, abort further
+ // checking.
+ if (Call->getNumArgs() != 3)
+ return;
+
+ const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts();
+
+ // The type checking for this warning is moderately expensive, only do it
+ // when enabled.
+ if (getDiagnostics().getDiagnosticLevel(diag::warn_non_pod_memset,
+ Dest->getExprLoc()) ==
+ Diagnostic::Ignored)
+ return;
+
+ QualType DestTy = Dest->getType();
+ if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
+ QualType PointeeTy = DestPtrTy->getPointeeType();
+ if (PointeeTy->isVoidType())
+ return;
+
+ // Check the C++11 POD definition regardless of language mode; it is more
+ // relaxed than earlier definitions and we don't want spurrious warnings.
+ if (PointeeTy->isCXX11PODType())
+ return;
+
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_non_pod_memset)
+ << PointeeTy << Call->getCallee()->getSourceRange());
+
+ SourceRange ArgRange = Call->getArg(0)->getSourceRange();
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::note_non_pod_memset_silence)
+ << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ }
+}
+
//===--- CHECK: Return Address of Stack Variable --------------------------===//
static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars);
@@ -1893,14 +1946,12 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
E->getType()->isObjCQualifiedIdType()) &&
"EvalAddr only works on pointers");
+ E = E->IgnoreParens();
+
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
switch (E->getStmtClass()) {
- case Stmt::ParenExprClass:
- // Ignore parentheses.
- return EvalAddr(cast<ParenExpr>(E)->getSubExpr(), refVars);
-
case Stmt::DeclRefExprClass: {
DeclRefExpr *DR = cast<DeclRefExpr>(E);
@@ -2030,6 +2081,8 @@ do {
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
+
+ E = E->IgnoreParens();
switch (E->getStmtClass()) {
case Stmt::ImplicitCastExprClass: {
ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
@@ -2063,12 +2116,6 @@ do {
return NULL;
}
- case Stmt::ParenExprClass: {
- // Ignore parentheses.
- E = cast<ParenExpr>(E)->getSubExpr();
- continue;
- }
-
case Stmt::UnaryOperatorClass: {
// The only unary operator that make sense to handle here
// is Deref. All others don't resolve to a "name." This includes
@@ -2747,10 +2794,48 @@ void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
+void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
+ SourceLocation CContext, unsigned diag) {
+ S.Diag(E->getExprLoc(), diag)
+ << SourceType << T << E->getSourceRange() << SourceRange(CContext);
+}
+
+/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext,
unsigned diag) {
- S.Diag(E->getExprLoc(), diag)
- << E->getType() << T << E->getSourceRange() << SourceRange(CContext);
+ DiagnoseImpCast(S, E, E->getType(), T, CContext, diag);
+}
+
+/// Diagnose an implicit cast from a literal expression. Also attemps to supply
+/// fixit hints when the cast wouldn't lose information to simply write the
+/// expression with the expected type.
+void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
+ SourceLocation CContext) {
+ // Emit the primary warning first, then try to emit a fixit hint note if
+ // reasonable.
+ S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer)
+ << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext);
+
+ const llvm::APFloat &Value = FL->getValue();
+
+ // Don't attempt to fix PPC double double literals.
+ if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble)
+ return;
+
+ // Try to convert this exactly to an 64-bit integer. FIXME: It would be
+ // nice to support arbitrarily large integers here.
+ bool isExact = false;
+ uint64_t IntegerPart;
+ if (Value.convertToInteger(&IntegerPart, 64, /*isSigned=*/true,
+ llvm::APFloat::rmTowardZero, &isExact)
+ != llvm::APFloat::opOK || !isExact)
+ return;
+
+ llvm::APInt IntegerValue(64, IntegerPart, /*isSigned=*/true);
+
+ std::string LiteralValue = IntegerValue.toString(10, /*isSigned=*/true);
+ S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer)
+ << FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue);
}
std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
@@ -2762,6 +2847,11 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
return ValueInRange.toString(10);
}
+static bool isFromSystemMacro(Sema &S, SourceLocation loc) {
+ SourceManager &smgr = S.Context.getSourceManager();
+ return loc.isMacroID() && smgr.isInSystemHeader(smgr.getSpellingLoc(loc));
+}
+
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = 0) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -2771,11 +2861,12 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (Source == Target) return;
if (Target->isDependentType()) return;
- // If the conversion context location is invalid or instantiated
- // from a system macro, don't complain.
- if (CC.isInvalid() ||
- (CC.isMacroID() && S.Context.getSourceManager().isInSystemHeader(
- S.Context.getSourceManager().getSpellingLoc(CC))))
+ // If the conversion context location is invalid don't complain.
+ // We also don't want to emit a warning if the issue occurs from the
+ // instantiation of a system macro. The problem is that 'getSpellingLoc()'
+ // is slow, so we delay this check as long as possible. Once we detect
+ // we are in that scenario, we just return.
+ if (CC.isInvalid())
return;
// Never diagnose implicit casts to bool.
@@ -2784,8 +2875,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Strip vector types.
if (isa<VectorType>(Source)) {
- if (!isa<VectorType>(Target))
+ if (!isa<VectorType>(Target)) {
+ if (isFromSystemMacro(S, CC))
+ return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar);
+ }
Source = cast<VectorType>(Source)->getElementType().getTypePtr();
Target = cast<VectorType>(Target)->getElementType().getTypePtr();
@@ -2793,8 +2887,12 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Strip complex types.
if (isa<ComplexType>(Source)) {
- if (!isa<ComplexType>(Target))
+ if (!isa<ComplexType>(Target)) {
+ if (isFromSystemMacro(S, CC))
+ return;
+
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar);
+ }
Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
@@ -2822,17 +2920,22 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
+ if (isFromSystemMacro(S, CC))
+ return;
+
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision);
}
return;
}
- // If the target is integral, always warn.
+ // If the target is integral, always warn.
if ((TargetBT && TargetBT->isInteger())) {
+ if (isFromSystemMacro(S, CC))
+ return;
+
Expr *InnerE = E->IgnoreParenImpCasts();
- if (FloatingLiteral *LiteralExpr = dyn_cast<FloatingLiteral>(InnerE)) {
- DiagnoseImpCast(S, LiteralExpr, T, CC,
- diag::warn_impcast_literal_float_to_integer);
+ if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) {
+ DiagnoseFloatingLiteralImpCast(S, FL, T, CC);
} else {
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer);
}
@@ -2852,6 +2955,9 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// TODO: this should happen for bitfield stores, too.
llvm::APSInt Value(32);
if (E->isIntegerConstantExpr(Value, S.Context)) {
+ if (isFromSystemMacro(S, CC))
+ return;
+
std::string PrettySourceValue = Value.toString(10);
std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
@@ -2863,6 +2969,10 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// People want to build with -Wshorten-64-to-32 and not -Wconversion
// and by god we'll let them.
+
+ if (isFromSystemMacro(S, CC))
+ return;
+
if (SourceRange.Width == 64 && TargetRange.Width == 32)
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32);
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision);
@@ -2871,6 +2981,10 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if ((TargetRange.NonNegative && !SourceRange.NonNegative) ||
(!TargetRange.NonNegative && SourceRange.NonNegative &&
SourceRange.Width == TargetRange.Width)) {
+
+ if (isFromSystemMacro(S, CC))
+ return;
+
unsigned DiagID = diag::warn_impcast_integer_sign;
// Traditionally, gcc has warned about this under -Wsign-compare.
@@ -2887,15 +3001,31 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
// Diagnose conversions between different enumeration types.
+ // In C, we pretend that the type of an EnumConstantDecl is its enumeration
+ // type, to give us better diagnostics.
+ QualType SourceType = E->getType();
+ if (!S.getLangOptions().CPlusPlus) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ if (EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
+ SourceType = S.Context.getTypeDeclType(Enum);
+ Source = S.Context.getCanonicalType(SourceType).getTypePtr();
+ }
+ }
+
if (const EnumType *SourceEnum = Source->getAs<EnumType>())
if (const EnumType *TargetEnum = Target->getAs<EnumType>())
if ((SourceEnum->getDecl()->getIdentifier() ||
- SourceEnum->getDecl()->getTypedefForAnonDecl()) &&
+ SourceEnum->getDecl()->getTypedefNameForAnonDecl()) &&
(TargetEnum->getDecl()->getIdentifier() ||
- TargetEnum->getDecl()->getTypedefForAnonDecl()) &&
- SourceEnum != TargetEnum)
- return DiagnoseImpCast(S, E, T, CC,
+ TargetEnum->getDecl()->getTypedefNameForAnonDecl()) &&
+ SourceEnum != TargetEnum) {
+ if (isFromSystemMacro(S, CC))
+ return;
+
+ return DiagnoseImpCast(S, E, SourceType, T, CC,
diag::warn_impcast_different_enum_types);
+ }
return;
}
@@ -3004,7 +3134,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
if (isa<StmtExpr>(E)) return;
// Don't descend into unevaluated contexts.
- if (isa<SizeOfAlignOfExpr>(E)) return;
+ if (isa<UnaryExprOrTypeTraitExpr>(E)) return;
// Now just recurse over the expression's children.
CC = E->getExprLoc();
@@ -3134,10 +3264,11 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
<< TRange << Op->getSourceRange();
}
-void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) {
+static void CheckArrayAccess_Check(Sema &S,
+ const clang::ArraySubscriptExpr *E) {
const Expr *BaseExpr = E->getBase()->IgnoreParenImpCasts();
const ConstantArrayType *ArrayTy =
- Context.getAsConstantArrayType(BaseExpr->getType());
+ S.Context.getAsConstantArrayType(BaseExpr->getType());
if (!ArrayTy)
return;
@@ -3145,7 +3276,7 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) {
if (IndexExpr->isValueDependent())
return;
llvm::APSInt index;
- if (!IndexExpr->isIntegerConstantExpr(index, Context))
+ if (!IndexExpr->isIntegerConstantExpr(index, S.Context))
return;
if (index.isUnsigned() || !index.isNegative()) {
@@ -3160,15 +3291,16 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) {
if (index.slt(size))
return;
- DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
- PDiag(diag::warn_array_index_exceeds_bounds)
- << index.toString(10, true) << size.toString(10, true)
- << IndexExpr->getSourceRange());
+ S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
+ S.PDiag(diag::warn_array_index_exceeds_bounds)
+ << index.toString(10, true)
+ << size.toString(10, true)
+ << IndexExpr->getSourceRange());
} else {
- DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
- PDiag(diag::warn_array_index_precedes_bounds)
- << index.toString(10, true)
- << IndexExpr->getSourceRange());
+ S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
+ S.PDiag(diag::warn_array_index_precedes_bounds)
+ << index.toString(10, true)
+ << IndexExpr->getSourceRange());
}
const NamedDecl *ND = NULL;
@@ -3177,8 +3309,28 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) {
if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
ND = dyn_cast<NamedDecl>(ME->getMemberDecl());
if (ND)
- DiagRuntimeBehavior(ND->getLocStart(), BaseExpr,
- PDiag(diag::note_array_index_out_of_bounds)
- << ND->getDeclName());
+ S.DiagRuntimeBehavior(ND->getLocStart(), BaseExpr,
+ S.PDiag(diag::note_array_index_out_of_bounds)
+ << ND->getDeclName());
}
+void Sema::CheckArrayAccess(const Expr *expr) {
+ while (true) {
+ expr = expr->IgnoreParens();
+ switch (expr->getStmtClass()) {
+ case Stmt::ArraySubscriptExprClass:
+ CheckArrayAccess_Check(*this, cast<ArraySubscriptExpr>(expr));
+ return;
+ case Stmt::ConditionalOperatorClass: {
+ const ConditionalOperator *cond = cast<ConditionalOperator>(expr);
+ if (const Expr *lhs = cond->getLHS())
+ CheckArrayAccess(lhs);
+ if (const Expr *rhs = cond->getRHS())
+ CheckArrayAccess(rhs);
+ return;
+ }
+ default:
+ return;
+ }
+ }
+}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index bab665a38da7..cc8726de9df8 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -667,8 +667,39 @@ QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) {
T = Value->getType();
else
return QualType();
-
- return T.getNonReferenceType();
+
+ // Dig through references, function pointers, and block pointers to
+ // get down to the likely type of an expression when the entity is
+ // used.
+ do {
+ if (const ReferenceType *Ref = T->getAs<ReferenceType>()) {
+ T = Ref->getPointeeType();
+ continue;
+ }
+
+ if (const PointerType *Pointer = T->getAs<PointerType>()) {
+ if (Pointer->getPointeeType()->isFunctionType()) {
+ T = Pointer->getPointeeType();
+ continue;
+ }
+
+ break;
+ }
+
+ if (const BlockPointerType *Block = T->getAs<BlockPointerType>()) {
+ T = Block->getPointeeType();
+ continue;
+ }
+
+ if (const FunctionType *Function = T->getAs<FunctionType>()) {
+ T = Function->getResultType();
+ continue;
+ }
+
+ break;
+ } while (true);
+
+ return T;
}
void ResultBuilder::AdjustResultPriorityForDecl(Result &R) {
@@ -1482,7 +1513,8 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
case Sema::PCC_Statement: {
AddTypedefResult(Results);
- if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
+ if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns() &&
+ SemaRef.getLangOptions().CXXExceptions) {
Builder.AddTypedTextChunk("try");
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
Builder.AddPlaceholderChunk("statements");
@@ -1655,15 +1687,17 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Results.AddResult(Result("true"));
Results.AddResult(Result("false"));
- // dynamic_cast < type-id > ( expression )
- Builder.AddTypedTextChunk("dynamic_cast");
- Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
- Builder.AddPlaceholderChunk("type");
- Builder.AddChunk(CodeCompletionString::CK_RightAngle);
- Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- Builder.AddPlaceholderChunk("expression");
- Builder.AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Builder.TakeString()));
+ if (SemaRef.getLangOptions().RTTI) {
+ // dynamic_cast < type-id > ( expression )
+ Builder.AddTypedTextChunk("dynamic_cast");
+ Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
+ Builder.AddPlaceholderChunk("type");
+ Builder.AddChunk(CodeCompletionString::CK_RightAngle);
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("expression");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
+ }
// static_cast < type-id > ( expression )
Builder.AddTypedTextChunk("static_cast");
@@ -1695,13 +1729,15 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(Result(Builder.TakeString()));
- // typeid ( expression-or-type )
- Builder.AddTypedTextChunk("typeid");
- Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- Builder.AddPlaceholderChunk("expression-or-type");
- Builder.AddChunk(CodeCompletionString::CK_RightParen);
- Results.AddResult(Result(Builder.TakeString()));
-
+ if (SemaRef.getLangOptions().RTTI) {
+ // typeid ( expression-or-type )
+ Builder.AddTypedTextChunk("typeid");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("expression-or-type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
+ }
+
// new T ( ... )
Builder.AddTypedTextChunk("new");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
@@ -1738,11 +1774,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Builder.AddPlaceholderChunk("expression");
Results.AddResult(Result(Builder.TakeString()));
- // throw expression
- Builder.AddTypedTextChunk("throw");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddPlaceholderChunk("expression");
- Results.AddResult(Result(Builder.TakeString()));
+ if (SemaRef.getLangOptions().CXXExceptions) {
+ // throw expression
+ Builder.AddTypedTextChunk("throw");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
// FIXME: Rethrow?
}
@@ -1785,9 +1823,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
///
/// This routine provides a fast path where we provide constant strings for
/// common type names.
-const char *GetCompletionTypeString(QualType T,
- ASTContext &Context,
- CodeCompletionAllocator &Allocator) {
+static const char *GetCompletionTypeString(QualType T,
+ ASTContext &Context,
+ CodeCompletionAllocator &Allocator) {
PrintingPolicy Policy(Context.PrintingPolicy);
Policy.AnonymousTagLocations = false;
@@ -1799,7 +1837,7 @@ const char *GetCompletionTypeString(QualType T,
// Anonymous tag types are constant strings.
if (const TagType *TagT = dyn_cast<TagType>(T))
if (TagDecl *Tag = TagT->getDecl())
- if (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl()) {
+ if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
switch (Tag->getTagKind()) {
case TTK_Struct: return "struct <anonymous>";
case TTK_Class: return "class <anonymous>";
@@ -1902,7 +1940,7 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// Look through typedefs.
if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
if (TypeSourceInfo *InnerTSInfo
- = TypedefTL->getTypedefDecl()->getTypeSourceInfo()) {
+ = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) {
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
continue;
}
@@ -2602,6 +2640,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
case Decl::ParmVar: return CXCursor_ParmDecl;
case Decl::Typedef: return CXCursor_TypedefDecl;
+ case Decl::TypeAlias: return CXCursor_TypeAliasDecl;
case Decl::Var: return CXCursor_VarDecl;
case Decl::Namespace: return CXCursor_Namespace;
case Decl::NamespaceAlias: return CXCursor_NamespaceAlias;
@@ -4816,8 +4855,12 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- if (RecExpr)
- DefaultFunctionArrayLvalueConversion(RecExpr);
+ if (RecExpr) {
+ ExprResult Conv = DefaultFunctionArrayLvalueConversion(RecExpr);
+ if (Conv.isInvalid()) // conversion failed. bail.
+ return;
+ RecExpr = Conv.take();
+ }
QualType ReceiverType = RecExpr? RecExpr->getType()
: Super? Context.getObjCObjectPointerType(
Context.getObjCInterfaceType(Super))
@@ -5327,16 +5370,65 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
Class = cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl()
->getClassInterface();
+ // Determine the type of the property we're synthesizing.
+ QualType PropertyType = Context.getObjCIdType();
+ if (Class) {
+ if (ObjCPropertyDecl *Property
+ = Class->FindPropertyDeclaration(PropertyName)) {
+ PropertyType
+ = Property->getType().getNonReferenceType().getUnqualifiedType();
+
+ // Give preference to ivars
+ Results.setPreferredType(PropertyType);
+ }
+ }
+
// Add all of the instance variables in this class and its superclasses.
Results.EnterNewScope();
+ bool SawSimilarlyNamedIvar = false;
+ std::string NameWithPrefix;
+ NameWithPrefix += '_';
+ NameWithPrefix += PropertyName->getName().str();
+ std::string NameWithSuffix = PropertyName->getName().str();
+ NameWithSuffix += '_';
for(; Class; Class = Class->getSuperClass()) {
- // FIXME: We could screen the type of each ivar for compatibility with
- // the property, but is that being too paternal?
- for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(),
- IVarEnd = Class->ivar_end();
- IVar != IVarEnd; ++IVar)
- Results.AddResult(Result(*IVar, 0), CurContext, 0, false);
+ for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar;
+ Ivar = Ivar->getNextIvar()) {
+ Results.AddResult(Result(Ivar, 0), CurContext, 0, false);
+
+ // Determine whether we've seen an ivar with a name similar to the
+ // property.
+ if ((PropertyName == Ivar->getIdentifier() ||
+ NameWithPrefix == Ivar->getName() ||
+ NameWithSuffix == Ivar->getName())) {
+ SawSimilarlyNamedIvar = true;
+
+ // Reduce the priority of this result by one, to give it a slight
+ // advantage over other results whose names don't match so closely.
+ if (Results.size() &&
+ Results.data()[Results.size() - 1].Kind
+ == CodeCompletionResult::RK_Declaration &&
+ Results.data()[Results.size() - 1].Declaration == Ivar)
+ Results.data()[Results.size() - 1].Priority--;
+ }
+ }
+ }
+
+ if (!SawSimilarlyNamedIvar) {
+ // Create ivar result _propName, that the user can use to synthesize
+ // an ivar of the appropriate type.
+ unsigned Priority = CCP_MemberDeclaration + 1;
+ typedef CodeCompletionResult Result;
+ CodeCompletionAllocator &Allocator = Results.getAllocator();
+ CodeCompletionBuilder Builder(Allocator, Priority,CXAvailability_Available);
+
+ Builder.AddResultTypeChunk(GetCompletionTypeString(PropertyType, Context,
+ Allocator));
+ Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix));
+ Results.AddResult(Result(Builder.TakeString(), Priority,
+ CXCursor_ObjCIvarDecl));
}
+
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d6efd7a6c9dd..7214988bdafc 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -17,6 +17,7 @@
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -24,6 +25,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/CharUnits.h"
@@ -61,7 +63,8 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) {
ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec *SS,
bool isClassName, bool HasTrailingDot,
- ParsedType ObjectTypePtr) {
+ ParsedType ObjectTypePtr,
+ bool WantNontrivialTypeSourceInfo) {
// Determine where we will perform name lookup.
DeclContext *LookupCtx = 0;
if (ObjectTypePtr) {
@@ -87,10 +90,15 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// We know from the grammar that this name refers to a type,
// so build a dependent node to describe the type.
+ if (WantNontrivialTypeSourceInfo)
+ return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get();
+
+ NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context);
QualType T =
- CheckTypenameType(ETK_None, SS->getScopeRep(), II,
- SourceLocation(), SS->getRange(), NameLoc);
- return ParsedType::make(T);
+ CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc,
+ II, NameLoc);
+
+ return ParsedType::make(T);
}
return ParsedType();
@@ -189,10 +197,23 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
if (T.isNull())
T = Context.getTypeDeclType(TD);
- if (SS)
- T = getElaboratedType(ETK_None, *SS, T);
-
+ if (SS && SS->isNotEmpty()) {
+ if (WantNontrivialTypeSourceInfo) {
+ // Construct a type with type-source information.
+ TypeLocBuilder Builder;
+ Builder.pushTypeSpec(T).setNameLoc(NameLoc);
+
+ T = getElaboratedType(ETK_None, *SS, T);
+ ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
+ ElabTL.setKeywordLoc(SourceLocation());
+ ElabTL.setQualifierLoc(SS->getWithLocInContext(Context));
+ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+ } else {
+ T = getElaboratedType(ETK_None, *SS, T);
+ }
+ }
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
+ (void)DiagnoseUseOfDecl(IDecl, NameLoc);
if (!HasTrailingDot)
T = Context.getObjCInterfaceType(IDecl);
}
@@ -229,6 +250,33 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
return DeclSpec::TST_unspecified;
}
+/// isMicrosoftMissingTypename - In Microsoft mode, within class scope,
+/// if a CXXScopeSpec's type is equal to the type of one of the base classes
+/// then downgrade the missing typename error to a warning.
+/// This is needed for MSVC compatibility; Example:
+/// @code
+/// template<class T> class A {
+/// public:
+/// typedef int TYPE;
+/// };
+/// template<class T> class B : public A<T> {
+/// public:
+/// A<T>::TYPE a; // no typename required because A<T> is a base class.
+/// };
+/// @endcode
+bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) {
+ if (CurContext->isRecord()) {
+ const Type *Ty = SS->getScopeRep()->getAsType();
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext);
+ for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
+ BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base)
+ if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base->getType()))
+ return true;
+ }
+ return false;
+}
+
bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
@@ -263,7 +311,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
Diag(Result->getLocation(), diag::note_previous_decl)
<< Result->getDeclName();
- SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS);
+ SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
+ false, false, ParsedType(),
+ /*NonTrivialTypeSourceInfo=*/true);
return true;
}
} else if (Lookup.empty()) {
@@ -304,7 +354,11 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
Diag(IILoc, diag::err_typename_nested_not_found)
<< &II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
- Diag(SS->getRange().getBegin(), diag::err_typename_missing)
+ unsigned DiagID = diag::err_typename_missing;
+ if (getLangOptions().Microsoft && isMicrosoftMissingTypename(SS))
+ DiagID = diag::warn_typename_missing;
+
+ Diag(SS->getRange().getBegin(), DiagID)
<< (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
<< SourceRange(SS->getRange().getBegin(), IILoc)
<< FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
@@ -317,6 +371,328 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
return true;
}
+/// \brief Determine whether the given result set contains either a type name
+/// or
+static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) {
+ bool CheckTemplate = R.getSema().getLangOptions().CPlusPlus &&
+ NextToken.is(tok::less);
+
+ for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) {
+ if (isa<TypeDecl>(*I) || isa<ObjCInterfaceDecl>(*I))
+ return true;
+
+ if (CheckTemplate && isa<TemplateDecl>(*I))
+ return true;
+ }
+
+ return false;
+}
+
+Sema::NameClassification Sema::ClassifyName(Scope *S,
+ CXXScopeSpec &SS,
+ IdentifierInfo *&Name,
+ SourceLocation NameLoc,
+ const Token &NextToken) {
+ DeclarationNameInfo NameInfo(Name, NameLoc);
+ ObjCMethodDecl *CurMethod = getCurMethodDecl();
+
+ if (NextToken.is(tok::coloncolon)) {
+ BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(),
+ QualType(), false, SS, 0, false);
+
+ }
+
+ LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
+ LookupParsedName(Result, S, &SS, !CurMethod);
+
+ // Perform lookup for Objective-C instance variables (including automatically
+ // synthesized instance variables), if we're in an Objective-C method.
+ // FIXME: This lookup really, really needs to be folded in to the normal
+ // unqualified lookup mechanism.
+ if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
+ ExprResult E = LookupInObjCMethod(Result, S, Name, true);
+ if (E.get() || E.isInvalid())
+ return E;
+
+ // Synthesize ivars lazily.
+ if (getLangOptions().ObjCDefaultSynthProperties &&
+ getLangOptions().ObjCNonFragileABI2) {
+ if (SynthesizeProvisionalIvar(Result, Name, NameLoc)) {
+ if (const ObjCPropertyDecl *Property =
+ canSynthesizeProvisionalIvar(Name)) {
+ Diag(NameLoc, diag::warn_synthesized_ivar_access) << Name;
+ Diag(Property->getLocation(), diag::note_property_declare);
+ }
+
+ // FIXME: This is strange. Shouldn't we just take the ivar returned
+ // from SynthesizeProvisionalIvar and continue with that?
+ E = LookupInObjCMethod(Result, S, Name, true);
+ if (E.get() || E.isInvalid())
+ return E;
+ }
+ }
+ }
+
+ bool SecondTry = false;
+ bool IsFilteredTemplateName = false;
+
+Corrected:
+ switch (Result.getResultKind()) {
+ case LookupResult::NotFound:
+ // If an unqualified-id is followed by a '(', then we have a function
+ // call.
+ if (!SS.isSet() && NextToken.is(tok::l_paren)) {
+ // In C++, this is an ADL-only call.
+ // FIXME: Reference?
+ if (getLangOptions().CPlusPlus)
+ return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
+
+ // C90 6.3.2.2:
+ // If the expression that precedes the parenthesized argument list in a
+ // function call consists solely of an identifier, and if no
+ // declaration is visible for this identifier, the identifier is
+ // implicitly declared exactly as if, in the innermost block containing
+ // the function call, the declaration
+ //
+ // extern int identifier ();
+ //
+ // appeared.
+ //
+ // We also allow this in C99 as an extension.
+ if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) {
+ Result.addDecl(D);
+ Result.resolveKind();
+ return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false);
+ }
+ }
+
+ // In C, we first see whether there is a tag type by the same name, in
+ // which case it's likely that the user just forget to write "enum",
+ // "struct", or "union".
+ if (!getLangOptions().CPlusPlus && !SecondTry) {
+ Result.clear(LookupTagName);
+ LookupParsedName(Result, S, &SS);
+ if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
+ const char *TagName = 0;
+ const char *FixItTagName = 0;
+ switch (Tag->getTagKind()) {
+ case TTK_Class:
+ TagName = "class";
+ FixItTagName = "class ";
+ break;
+
+ case TTK_Enum:
+ TagName = "enum";
+ FixItTagName = "enum ";
+ break;
+
+ case TTK_Struct:
+ TagName = "struct";
+ FixItTagName = "struct ";
+ break;
+
+ case TTK_Union:
+ TagName = "union";
+ FixItTagName = "union ";
+ break;
+ }
+
+ Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
+ << Name << TagName << getLangOptions().CPlusPlus
+ << FixItHint::CreateInsertion(NameLoc, FixItTagName);
+ break;
+ }
+
+ Result.clear(LookupOrdinaryName);
+ }
+
+ // Perform typo correction to determine if there is another name that is
+ // close to this name.
+ if (!SecondTry) {
+ if (DeclarationName Corrected = CorrectTypo(Result, S, &SS)) {
+ unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
+ unsigned QualifiedDiag = diag::err_no_member_suggest;
+
+ NamedDecl *FirstDecl = Result.empty()? 0 : *Result.begin();
+ NamedDecl *UnderlyingFirstDecl
+ = FirstDecl? FirstDecl->getUnderlyingDecl() : 0;
+ if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
+ UnderlyingFirstDecl && isa<TemplateDecl>(UnderlyingFirstDecl)) {
+ UnqualifiedDiag = diag::err_no_template_suggest;
+ QualifiedDiag = diag::err_no_member_template_suggest;
+ } else if (UnderlyingFirstDecl &&
+ (isa<TypeDecl>(UnderlyingFirstDecl) ||
+ isa<ObjCInterfaceDecl>(UnderlyingFirstDecl) ||
+ isa<ObjCCompatibleAliasDecl>(UnderlyingFirstDecl))) {
+ UnqualifiedDiag = diag::err_unknown_typename_suggest;
+ QualifiedDiag = diag::err_unknown_nested_typename_suggest;
+ }
+
+ if (SS.isEmpty())
+ Diag(NameLoc, UnqualifiedDiag)
+ << Name << Corrected
+ << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+ else
+ Diag(NameLoc, QualifiedDiag)
+ << Name << computeDeclContext(SS, false) << Corrected
+ << SS.getRange()
+ << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+
+ // Update the name, so that the caller has the new name.
+ Name = Corrected.getAsIdentifierInfo();
+
+ // Typo correction corrected to a keyword.
+ if (Result.empty())
+ return Corrected.getAsIdentifierInfo();
+
+ Diag(FirstDecl->getLocation(), diag::note_previous_decl)
+ << FirstDecl->getDeclName();
+
+ // If we found an Objective-C instance variable, let
+ // LookupInObjCMethod build the appropriate expression to
+ // reference the ivar.
+ // FIXME: This is a gross hack.
+ if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
+ Result.clear();
+ ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
+ return move(E);
+ }
+
+ goto Corrected;
+ }
+ }
+
+ // We failed to correct; just fall through and let the parser deal with it.
+ Result.suppressDiagnostics();
+ return NameClassification::Unknown();
+
+ case LookupResult::NotFoundInCurrentInstantiation:
+ // We performed name lookup into the current instantiation, and there were
+ // dependent bases, so we treat this result the same way as any other
+ // dependent nested-name-specifier.
+
+ // C++ [temp.res]p2:
+ // A name used in a template declaration or definition and that is
+ // dependent on a template-parameter is assumed not to name a type
+ // unless the applicable name lookup finds a type name or the name is
+ // qualified by the keyword typename.
+ //
+ // FIXME: If the next token is '<', we might want to ask the parser to
+ // perform some heroics to see if we actually have a
+ // template-argument-list, which would indicate a missing 'template'
+ // keyword here.
+ return BuildDependentDeclRefExpr(SS, NameInfo, /*TemplateArgs=*/0);
+
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ break;
+
+ case LookupResult::Ambiguous:
+ if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
+ hasAnyAcceptableTemplateNames(Result)) {
+ // C++ [temp.local]p3:
+ // A lookup that finds an injected-class-name (10.2) can result in an
+ // ambiguity in certain cases (for example, if it is found in more than
+ // one base class). If all of the injected-class-names that are found
+ // refer to specializations of the same class template, and if the name
+ // is followed by a template-argument-list, the reference refers to the
+ // class template itself and not a specialization thereof, and is not
+ // ambiguous.
+ //
+ // This filtering can make an ambiguous result into an unambiguous one,
+ // so try again after filtering out template names.
+ FilterAcceptableTemplateNames(Result);
+ if (!Result.isAmbiguous()) {
+ IsFilteredTemplateName = true;
+ break;
+ }
+ }
+
+ // Diagnose the ambiguity and return an error.
+ return NameClassification::Error();
+ }
+
+ if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
+ (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) {
+ // C++ [temp.names]p3:
+ // After name lookup (3.4) finds that a name is a template-name or that
+ // an operator-function-id or a literal- operator-id refers to a set of
+ // overloaded functions any member of which is a function template if
+ // this is followed by a <, the < is always taken as the delimiter of a
+ // template-argument-list and never as the less-than operator.
+ if (!IsFilteredTemplateName)
+ FilterAcceptableTemplateNames(Result);
+
+ if (!Result.empty()) {
+ bool IsFunctionTemplate;
+ TemplateName Template;
+ if (Result.end() - Result.begin() > 1) {
+ IsFunctionTemplate = true;
+ Template = Context.getOverloadedTemplateName(Result.begin(),
+ Result.end());
+ } else {
+ TemplateDecl *TD
+ = cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl());
+ IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
+
+ if (SS.isSet() && !SS.isInvalid())
+ Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
+ /*TemplateKeyword=*/false,
+ TD);
+ else
+ Template = TemplateName(TD);
+ }
+
+ if (IsFunctionTemplate) {
+ // Function templates always go through overload resolution, at which
+ // point we'll perform the various checks (e.g., accessibility) we need
+ // to based on which function we selected.
+ Result.suppressDiagnostics();
+
+ return NameClassification::FunctionTemplate(Template);
+ }
+
+ return NameClassification::TypeTemplate(Template);
+ }
+ }
+
+ NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();
+ if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) {
+ DiagnoseUseOfDecl(Type, NameLoc);
+ QualType T = Context.getTypeDeclType(Type);
+ 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.
+ if (ObjCCompatibleAliasDecl *Alias
+ = dyn_cast<ObjCCompatibleAliasDecl>(FirstDecl))
+ Class = Alias->getClassInterface();
+ }
+
+ if (Class) {
+ DiagnoseUseOfDecl(Class, NameLoc);
+
+ if (NextToken.is(tok::period)) {
+ // Interface. <something> is parsed as a property reference expression.
+ // Just return "unknown" as a fall-through for now.
+ Result.suppressDiagnostics();
+ return NameClassification::Unknown();
+ }
+
+ QualType T = Context.getObjCInterfaceType(Class);
+ return ParsedType::make(T);
+ }
+
+ if (!Result.empty() && (*Result.begin())->isCXXClassMember())
+ return BuildPossibleImplicitMemberExpr(SS, Result, 0);
+
+ bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
+ return BuildDeclarationNameExpr(SS, Result, ADL);
+}
+
// Determines the context to return to after temporarily entering a
// context. This depends in an unnecessarily complicated way on the
// exact ordering of callbacks from the parser.
@@ -472,11 +848,30 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
}
S->AddDecl(D);
- IdResolver.AddDecl(D);
+
+ if (isa<LabelDecl>(D) && !cast<LabelDecl>(D)->isGnuLocal()) {
+ // Implicitly-generated labels may end up getting generated in an order that
+ // isn't strictly lexical, which breaks name lookup. Be careful to insert
+ // the label at the appropriate place in the identifier chain.
+ for (I = IdResolver.begin(D->getDeclName()); I != IEnd; ++I) {
+ DeclContext *IDC = (*I)->getLexicalDeclContext()->getRedeclContext();
+ if (IDC == CurContext) {
+ if (!S->isDeclScope(*I))
+ continue;
+ } else if (IDC->Encloses(CurContext))
+ break;
+ }
+
+ IdResolver.InsertDeclAfter(I, D);
+ } else {
+ IdResolver.AddDecl(D);
+ }
}
-bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) {
- return IdResolver.isDeclInScope(D, Ctx, Context, S);
+bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
+ bool ExplicitInstantiationOrSpecialization) {
+ return IdResolver.isDeclInScope(D, Ctx, Context, S,
+ ExplicitInstantiationOrSpecialization);
}
Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) {
@@ -498,12 +893,13 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *,
/// as determined by isDeclInScope.
static void FilterLookupForScope(Sema &SemaRef, LookupResult &R,
DeclContext *Ctx, Scope *S,
- bool ConsiderLinkage) {
+ bool ConsiderLinkage,
+ bool ExplicitInstantiationOrSpecialization) {
LookupResult::Filter F = R.makeFilter();
while (F.hasNext()) {
NamedDecl *D = F.next();
- if (SemaRef.isDeclInScope(D, Ctx, S))
+ if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
continue;
if (ConsiderLinkage &&
@@ -841,7 +1237,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
FunctionDecl *New = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
- Loc, II, R, /*TInfo=*/0,
+ Loc, Loc, II, R, /*TInfo=*/0,
SC_Extern,
SC_None, false,
/*hasPrototype=*/true);
@@ -851,10 +1247,15 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
// FunctionDecl.
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
llvm::SmallVector<ParmVarDecl*, 16> Params;
- for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
- Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
- FT->getArgType(i), /*TInfo=*/0,
- SC_None, SC_None, 0));
+ for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ ParmVarDecl *parm =
+ ParmVarDecl::Create(Context, New, SourceLocation(),
+ SourceLocation(), 0,
+ FT->getArgType(i), /*TInfo=*/0,
+ SC_None, SC_None, 0);
+ parm->setScopeInfo(0, i);
+ Params.push_back(parm);
+ }
New->setParams(Params.data(), Params.size());
}
@@ -871,12 +1272,12 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
return New;
}
-/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the
+/// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the
/// same name and scope as a previous declaration 'Old'. Figure out
/// how to resolve this situation, merging decls or emitting
/// diagnostics as appropriate. If there was an error, set New to be invalid.
///
-void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
+void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
// If the new decl is known invalid already, don't bother doing any
// merging checks.
if (New->isInvalidDecl()) return;
@@ -936,7 +1337,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
// Determine the "old" type we'll use for checking and diagnostics.
QualType OldType;
- if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old))
+ if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
OldType = OldTypedef->getUnderlyingType();
else
OldType = Context.getTypeDeclType(Old);
@@ -947,8 +1348,11 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
if (OldType != New->getUnderlyingType() &&
Context.getCanonicalType(OldType) !=
Context.getCanonicalType(New->getUnderlyingType())) {
+ int Kind = 0;
+ if (isa<TypeAliasDecl>(Old))
+ Kind = 1;
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
- << New->getUnderlyingType() << OldType;
+ << Kind << New->getUnderlyingType() << OldType;
if (Old->getLocation().isValid())
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -958,8 +1362,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
// declaration was a typedef.
// FIXME: this is a potential source of wierdness if the type
// spellings don't match exactly.
- if (isa<TypedefDecl>(Old))
- New->setPreviousDeclaration(cast<TypedefDecl>(Old));
+ if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old))
+ New->setPreviousDeclaration(Typedef);
if (getLangOptions().Microsoft)
return;
@@ -993,7 +1397,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
// };
//
// since that was the intent of DR56.
- if (!isa<TypedefDecl >(Old))
+ if (!isa<TypedefNameDecl>(Old))
return;
Diag(New->getLocation(), diag::err_redefinition)
@@ -1033,23 +1437,58 @@ DeclHasAttr(const Decl *D, const Attr *A) {
return false;
}
-/// MergeDeclAttributes - append attributes from the Old decl to the New one.
-static void MergeDeclAttributes(Decl *New, Decl *Old, ASTContext &C) {
- if (!Old->hasAttrs())
+/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
+static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl,
+ ASTContext &C) {
+ if (!oldDecl->hasAttrs())
return;
+
+ bool foundAny = newDecl->hasAttrs();
+
// Ensure that any moving of objects within the allocated map is done before
// we process them.
- if (!New->hasAttrs())
- New->setAttrs(AttrVec());
+ if (!foundAny) newDecl->setAttrs(AttrVec());
+
for (specific_attr_iterator<InheritableAttr>
- i = Old->specific_attr_begin<InheritableAttr>(),
- e = Old->specific_attr_end<InheritableAttr>(); i != e; ++i) {
- if (!DeclHasAttr(New, *i)) {
- InheritableAttr *NewAttr = cast<InheritableAttr>((*i)->clone(C));
- NewAttr->setInherited(true);
- New->addAttr(NewAttr);
+ i = oldDecl->specific_attr_begin<InheritableAttr>(),
+ e = oldDecl->specific_attr_end<InheritableAttr>(); i != e; ++i) {
+ if (!DeclHasAttr(newDecl, *i)) {
+ InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(C));
+ newAttr->setInherited(true);
+ newDecl->addAttr(newAttr);
+ foundAny = true;
}
}
+
+ if (!foundAny) newDecl->dropAttrs();
+}
+
+/// mergeParamDeclAttributes - Copy attributes from the old parameter
+/// to the new one.
+static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
+ const ParmVarDecl *oldDecl,
+ ASTContext &C) {
+ if (!oldDecl->hasAttrs())
+ return;
+
+ bool foundAny = newDecl->hasAttrs();
+
+ // Ensure that any moving of objects within the allocated map is
+ // done before we process them.
+ if (!foundAny) newDecl->setAttrs(AttrVec());
+
+ for (specific_attr_iterator<InheritableParamAttr>
+ i = oldDecl->specific_attr_begin<InheritableParamAttr>(),
+ e = oldDecl->specific_attr_end<InheritableParamAttr>(); i != e; ++i) {
+ if (!DeclHasAttr(newDecl, *i)) {
+ InheritableAttr *newAttr = cast<InheritableParamAttr>((*i)->clone(C));
+ newAttr->setInherited(true);
+ newDecl->addAttr(newAttr);
+ foundAny = true;
+ }
+ }
+
+ if (!foundAny) newDecl->dropAttrs();
}
namespace {
@@ -1145,10 +1584,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
New->getStorageClass() == SC_Static &&
Old->getStorageClass() != SC_Static &&
!canRedefineFunction(Old, getLangOptions())) {
- Diag(New->getLocation(), diag::err_static_non_static)
- << New;
- Diag(Old->getLocation(), PrevDiag);
- return true;
+ if (getLangOptions().Microsoft) {
+ Diag(New->getLocation(), diag::warn_static_non_static) << New;
+ Diag(Old->getLocation(), PrevDiag);
+ } else {
+ Diag(New->getLocation(), diag::err_static_non_static) << New;
+ Diag(Old->getLocation(), PrevDiag);
+ return true;
+ }
}
// If a function is first declared with a calling convention, but is
@@ -1191,8 +1634,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
}
// Merge regparm attribute.
- if (OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) {
- if (NewTypeInfo.getRegParm()) {
+ if (OldTypeInfo.getHasRegParm() != NewTypeInfo.getHasRegParm() ||
+ OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) {
+ if (NewTypeInfo.getHasRegParm()) {
Diag(New->getLocation(), diag::err_regparm_mismatch)
<< NewType->getRegParmType()
<< OldType->getRegParmType();
@@ -1335,10 +1779,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
ParamEnd = OldProto->arg_type_end();
ParamType != ParamEnd; ++ParamType) {
ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
+ SourceLocation(),
SourceLocation(), 0,
*ParamType, /*TInfo=*/0,
SC_None, SC_None,
0);
+ Param->setScopeInfo(0, Params.size());
Param->setImplicit();
Params.push_back(Param);
}
@@ -1450,7 +1896,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
/// \returns false
bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
// Merge the attributes
- MergeDeclAttributes(New, Old, Context);
+ mergeDeclAttributes(New, Old, Context);
// Merge the storage class.
if (Old->getStorageClass() != SC_Extern &&
@@ -1465,14 +1911,33 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
if (Old->isDeleted())
New->setDeleted();
+ // Merge attributes from the parameters. These can mismatch with K&R
+ // declarations.
+ if (New->getNumParams() == Old->getNumParams())
+ for (unsigned i = 0, e = New->getNumParams(); i != e; ++i)
+ mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i),
+ Context);
+
if (getLangOptions().CPlusPlus)
return MergeCXXFunctionDecl(New, Old);
return false;
}
-/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope
-/// as a previous declaration 'Old'. Figure out how to merge their types,
+void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
+ const ObjCMethodDecl *oldMethod) {
+ // Merge the attributes.
+ mergeDeclAttributes(newMethod, oldMethod, Context);
+
+ // Merge attributes from the parameters.
+ for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(),
+ ni = newMethod->param_begin(), ne = newMethod->param_end();
+ ni != ne; ++ni, ++oi)
+ mergeParamDeclAttributes(*ni, *oi, Context);
+}
+
+/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and
+/// scope as a previous declaration 'Old'. Figure out how to merge their types,
/// emitting diagnostics as appropriate.
///
/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
@@ -1489,8 +1954,10 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
if (AT && !AT->isDeduced()) {
// We don't know what the new type is until the initializer is attached.
return;
- } else if (Context.hasSameType(New->getType(), Old->getType()))
- return;
+ } else if (Context.hasSameType(New->getType(), Old->getType())) {
+ // These could still be something that needs exception specs checked.
+ return MergeVarDeclExceptionSpecs(New, Old);
+ }
// C++ [basic.link]p10:
// [...] the types specified by all declarations referring to a given
// object or function shall be identical, except that declarations for an
@@ -1564,7 +2031,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setInvalidDecl();
}
- MergeDeclAttributes(New, Old, Context);
+ mergeDeclAttributes(New, Old, Context);
// Merge the types.
MergeVarDeclTypes(New, Old);
@@ -1664,12 +2131,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
- DeclSpec &DS) {
- // FIXME: Error on inline/virtual/explicit
- // FIXME: Warn on useless __thread
- // FIXME: Warn on useless const/volatile
- // FIXME: Warn on useless static/extern/typedef/private_extern/mutable
- // FIXME: Warn on useless attributes
+ DeclSpec &DS) {
Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -1703,6 +2165,10 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return 0;
return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
}
+
+ // Track whether we warned about the fact that there aren't any
+ // declarators.
+ bool emittedWarning = false;
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
ProcessDeclAttributeList(S, Record, DS.getAttributes().getList());
@@ -1715,6 +2181,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
+ emittedWarning = true;
}
}
@@ -1740,12 +2207,16 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DS.getStorageClassSpec() != DeclSpec::SCS_typedef)
if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag))
if (Enum->enumerator_begin() == Enum->enumerator_end() &&
- !Enum->getIdentifier() && !Enum->isInvalidDecl())
+ !Enum->getIdentifier() && !Enum->isInvalidDecl()) {
Diag(Enum->getLocation(), diag::ext_no_declarators)
<< DS.getSourceRange();
+ emittedWarning = true;
+ }
+
+ // Skip all the checks below if we have a type error.
+ if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD;
- if (!DS.isMissingDeclaratorOk() &&
- DS.getTypeSpecType() != DeclSpec::TST_error) {
+ if (!DS.isMissingDeclaratorOk()) {
// Warn about typedefs of enums without names, since this is an
// extension in both Microsoft and GNU.
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
@@ -1757,7 +2228,40 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
- }
+ emittedWarning = true;
+ }
+
+ // We're going to complain about a bunch of spurious specifiers;
+ // only do this if we're declaring a tag, because otherwise we
+ // should be getting diag::ext_no_declarators.
+ if (emittedWarning || (TagD && TagD->isInvalidDecl()))
+ return TagD;
+
+ // Note that a linkage-specification sets a storage class, but
+ // 'extern "C" struct foo;' is actually valid and not theoretically
+ // useless.
+ if (DeclSpec::SCS scs = DS.getStorageClassSpec())
+ if (!DS.isExternInLinkageSpec())
+ Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier)
+ << DeclSpec::getSpecifierName(scs);
+
+ if (DS.isThreadSpecified())
+ Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread";
+ if (DS.getTypeQualifiers()) {
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const";
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+ Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile";
+ // Restrict is covered above.
+ }
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline";
+ if (DS.isVirtualSpecified())
+ Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual";
+ if (DS.isExplicitSpecified())
+ Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit";
+
+ // FIXME: Warn on useless attributes
return TagD;
}
@@ -2062,7 +2566,9 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// Create a declaration for this anonymous struct/union.
NamedDecl *Anon = 0;
if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) {
- Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(),
+ Anon = FieldDecl::Create(Context, OwningClass,
+ DS.getSourceRange().getBegin(),
+ Record->getLocation(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
@@ -2086,8 +2592,9 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
VarDecl::StorageClass SCAsWritten
= StorageClassSpecToVarDeclStorageClass(SCSpec);
- Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
- /*IdentifierInfo=*/0,
+ Anon = VarDecl::Create(Context, Owner,
+ DS.getSourceRange().getBegin(),
+ Record->getLocation(), /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo, SC, SCAsWritten);
}
@@ -2151,6 +2658,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
NamedDecl* Anon = FieldDecl::Create(Context,
cast<RecordDecl>(CurContext),
DS.getSourceRange().getBegin(),
+ DS.getSourceRange().getBegin(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
@@ -2379,6 +2887,26 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
}
+/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
+/// If T is the name of a class, then each of the following shall have a
+/// name different from T:
+/// - every static data member of class T;
+/// - every member function of class T
+/// - every member of class T that is itself a type;
+/// \returns true if the declaration name violates these rules.
+bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
+ DeclarationNameInfo NameInfo) {
+ DeclarationName Name = NameInfo.getName();
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
+ if (Record->getIdentifier() && Record->getDeclName() == Name) {
+ Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name;
+ return true;
+ }
+
+ return false;
+}
+
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition) {
@@ -2466,23 +2994,12 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
D.setInvalidType();
}
}
-
- // C++ [class.mem]p13:
- // If T is the name of a class, then each of the following shall have a
- // name different from T:
- // - every static data member of class T;
- // - every member function of class T
- // - every member of class T that is itself a type;
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getIdentifier() && Record->getDeclName() == Name) {
- Diag(D.getIdentifierLoc(), diag::err_member_name_of_class)
- << Name;
-
- // If this is a typedef, we'll end up spewing multiple diagnostics.
- // Just return early; it's safer.
- if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- return 0;
- }
+
+ if (DiagnoseClassNameShadow(DC, NameInfo))
+ // If this is a typedef, we'll end up spewing multiple diagnostics.
+ // Just return early; it's safer.
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
+ return 0;
NamedDecl *New;
@@ -2777,6 +3294,15 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewTD, D);
+ return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration);
+}
+
+/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
+/// declares a typedef-name, either using the 'typedef' type specifier or via
+/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
+NamedDecl*
+Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
+ LookupResult &Previous, bool &Redeclaration) {
// C99 6.7.7p2: If a typedef name specifies a variably modified type
// then it shall have block scope.
// Note that variably modified types must be fixed before merging the decl so
@@ -2792,18 +3318,17 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative,
Oversized);
if (!FixedTy.isNull()) {
- Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size);
+ Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size);
NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy));
} else {
if (SizeIsNegative)
- Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size);
+ Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size);
else if (T->isVariableArrayType())
- Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope);
+ Diag(NewTD->getLocation(), diag::err_vla_decl_in_file_scope);
else if (Oversized.getBoolValue())
- Diag(D.getIdentifierLoc(), diag::err_array_too_large)
- << Oversized.toString(10);
+ Diag(NewTD->getLocation(), diag::err_array_too_large) << Oversized.toString(10);
else
- Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope);
+ Diag(NewTD->getLocation(), diag::err_vm_decl_in_file_scope);
NewTD->setInvalidDecl();
}
}
@@ -2811,10 +3336,11 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
- FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false);
+ FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false,
+ /*ExplicitInstantiationOrSpecialization=*/false);
if (!Previous.empty()) {
Redeclaration = true;
- MergeTypeDefDecl(NewTD, Previous);
+ MergeTypedefNameDecl(NewTD, Previous);
}
// If this is the C FILE type, notify the AST context.
@@ -2952,8 +3478,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isExplicitSpecialization = false;
VarDecl *NewVD;
if (!getLangOptions().CPlusPlus) {
- NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
- II, R, TInfo, SC, SCAsWritten);
+ NewVD = VarDecl::Create(Context, DC, D.getSourceRange().getBegin(),
+ D.getIdentifierLoc(), II,
+ R, TInfo, SC, SCAsWritten);
if (D.isInvalidType())
NewVD->setInvalidDecl();
@@ -2988,7 +3515,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
isExplicitSpecialization = false;
- unsigned NumMatchedTemplateParamLists = TemplateParamLists.size();
bool Invalid = false;
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
@@ -2999,9 +3525,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
/*never a friend*/ false,
isExplicitSpecialization,
Invalid)) {
- // All but one template parameter lists have been matching.
- --NumMatchedTemplateParamLists;
-
if (TemplateParams->size() > 0) {
// There is no such thing as a variable template.
Diag(D.getIdentifierLoc(), diag::err_template_variable)
@@ -3017,13 +3540,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
-
isExplicitSpecialization = true;
}
}
- NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
- II, R, TInfo, SC, SCAsWritten);
+ NewVD = VarDecl::Create(Context, DC, D.getSourceRange().getBegin(),
+ D.getIdentifierLoc(), II,
+ R, TInfo, SC, SCAsWritten);
// If this decl has an auto type in need of deduction, make a note of the
// Decl so we can diagnose uses of it in its own initializer.
@@ -3036,9 +3559,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
SetNestedNameSpecifier(NewVD, D);
- if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
+ if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) {
NewVD->setTemplateParameterListsInfo(Context,
- NumMatchedTemplateParamLists,
+ TemplateParamLists.size(),
TemplateParamLists.release());
}
}
@@ -3092,7 +3615,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage());
+ FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(),
+ isExplicitSpecialization);
if (!getLangOptions().CPlusPlus)
CheckVariableDeclaration(NewVD, Previous, Redeclaration);
@@ -3169,10 +3693,11 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
return;
// Don't diagnose declarations at file scope.
- DeclContext *NewDC = D->getDeclContext();
- if (NewDC->isFileContext())
+ if (D->hasGlobalStorage())
return;
-
+
+ DeclContext *NewDC = D->getDeclContext();
+
// Only diagnose if we're shadowing an unambiguous field or variable.
if (R.getResultKind() != LookupResult::Found)
return;
@@ -3189,17 +3714,6 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl))
if (shadowedVar->isExternC()) {
- // Don't warn for this case:
- //
- // @code
- // extern int bob;
- // void f() {
- // extern int bob;
- // }
- // @endcode
- if (D->isExternC())
- return;
-
// For shadowing external vars, make sure that we point to the global
// declaration, not a locally scoped extern declaration.
for (VarDecl::redecl_iterator
@@ -3528,8 +4042,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
FunctionTemplateDecl *FunctionTemplate = 0;
bool isExplicitSpecialization = false;
bool isFunctionTemplateSpecialization = false;
- unsigned NumMatchedTemplateParamLists = 0;
-
+
if (!getLangOptions().CPlusPlus) {
// Determine whether the function was written with a
// prototype. This true when:
@@ -3540,7 +4053,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
(D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
(!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
- NewFD = FunctionDecl::Create(Context, DC,
+ NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(),
NameInfo, R, TInfo, SC, SCAsWritten, isInline,
HasPrototype);
if (D.isInvalidType())
@@ -3549,7 +4062,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Set the lexical context.
NewFD->setLexicalDeclContext(CurContext);
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
+ FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ /*ExplicitInstantiationOrSpecialization=*/false);
} else {
isFriend = D.getDeclSpec().isFriendSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
@@ -3566,14 +4080,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
AbstractReturnType))
D.setInvalidType();
-
- if (isFriend) {
- // C++ [class.friend]p5
- // A function can be defined in a friend declaration of a
- // class . . . . Such a function is implicitly inline.
- isInline |= IsFunctionDefinition;
- }
-
if (Name.getNameKind() == DeclarationName::CXXConstructorName) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
@@ -3584,6 +4090,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Create the new declaration
NewFD = CXXConstructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
@@ -3594,6 +4101,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewFD = CXXDestructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isInline,
/*isImplicitlyDeclared=*/false);
@@ -3603,8 +4111,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Create a FunctionDecl to satisfy the function definition parsing
// code path.
- NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
- Name, R, TInfo, SC, SCAsWritten, isInline,
+ NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(),
+ D.getIdentifierLoc(), Name, R, TInfo,
+ SC, SCAsWritten, isInline,
/*hasPrototype=*/true);
D.setInvalidType();
}
@@ -3617,8 +4126,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
- isInline, isExplicit);
+ isInline, isExplicit,
+ SourceLocation());
isVirtualOkay = true;
} else if (DC->isRecord()) {
@@ -3636,7 +4147,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
bool isStatic = SC == SC_Static;
-
+
// [class.free]p1:
// Any allocation function for a class T is a static member
// (even if not explicitly declared static).
@@ -3649,25 +4160,34 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Name.getCXXOverloadedOperator() == OO_Delete ||
Name.getCXXOverloadedOperator() == OO_Array_Delete)
isStatic = true;
-
+
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
- isStatic, SCAsWritten, isInline);
+ isStatic, SCAsWritten, isInline,
+ SourceLocation());
isVirtualOkay = !isStatic;
} else {
// Determine whether the function was written with a
// prototype. This true when:
// - we're in C++ (where every function has a prototype),
- NewFD = FunctionDecl::Create(Context, DC,
+ NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(),
NameInfo, R, TInfo, SC, SCAsWritten, isInline,
true/*HasPrototype*/);
}
+
+ if (isFriend && !isInline && IsFunctionDefinition) {
+ // C++ [class.friend]p5
+ // A function can be defined in a friend declaration of a
+ // class . . . . Such a function is implicitly inline.
+ NewFD->setImplicitlyInline();
+ }
+
SetNestedNameSpecifier(NewFD, D);
isExplicitSpecialization = false;
isFunctionTemplateSpecialization = false;
- NumMatchedTemplateParamLists = TemplateParamLists.size();
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -3680,7 +4200,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// determine whether we have a template or a template specialization.
bool Invalid = false;
if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(
+ = MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getSourceRange().getBegin(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
@@ -3688,54 +4208,71 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isFriend,
isExplicitSpecialization,
Invalid)) {
- // All but one template parameter lists have been matching.
- --NumMatchedTemplateParamLists;
-
- if (TemplateParams->size() > 0) {
- // This is a function template
-
- // Check that we can declare a template here.
- if (CheckTemplateDeclScope(S, TemplateParams))
- return 0;
-
- FunctionTemplate = FunctionTemplateDecl::Create(Context, DC,
- NewFD->getLocation(),
- Name, TemplateParams,
- NewFD);
- FunctionTemplate->setLexicalDeclContext(CurContext);
- NewFD->setDescribedFunctionTemplate(FunctionTemplate);
- } else {
- // This is a function template specialization.
- isFunctionTemplateSpecialization = true;
-
- // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
- if (isFriend && isFunctionTemplateSpecialization) {
- // We want to remove the "template<>", found here.
- SourceRange RemoveRange = TemplateParams->getSourceRange();
-
- // If we remove the template<> and the name is not a
- // template-id, we're actually silently creating a problem:
- // the friend declaration will refer to an untemplated decl,
- // and clearly the user wants a template specialization. So
- // we need to insert '<>' after the name.
- SourceLocation InsertLoc;
- if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
- InsertLoc = D.getName().getSourceRange().getEnd();
- InsertLoc = PP.getLocForEndOfToken(InsertLoc);
- }
+ if (TemplateParams->size() > 0) {
+ // This is a function template
- Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend)
- << Name << RemoveRange
- << FixItHint::CreateRemoval(RemoveRange)
- << FixItHint::CreateInsertion(InsertLoc, "<>");
- }
- }
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return 0;
+
+ // A destructor cannot be a template.
+ if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
+ Diag(NewFD->getLocation(), diag::err_destructor_template);
+ return 0;
}
- if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) {
- NewFD->setTemplateParameterListsInfo(Context,
- NumMatchedTemplateParamLists,
- TemplateParamLists.release());
+ FunctionTemplate = FunctionTemplateDecl::Create(Context, DC,
+ NewFD->getLocation(),
+ Name, TemplateParams,
+ NewFD);
+ FunctionTemplate->setLexicalDeclContext(CurContext);
+ NewFD->setDescribedFunctionTemplate(FunctionTemplate);
+
+ // For source fidelity, store the other template param lists.
+ if (TemplateParamLists.size() > 1) {
+ NewFD->setTemplateParameterListsInfo(Context,
+ TemplateParamLists.size() - 1,
+ TemplateParamLists.release());
+ }
+ } else {
+ // This is a function template specialization.
+ isFunctionTemplateSpecialization = true;
+ // For source fidelity, store all the template param lists.
+ NewFD->setTemplateParameterListsInfo(Context,
+ TemplateParamLists.size(),
+ TemplateParamLists.release());
+
+ // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
+ if (isFriend) {
+ // We want to remove the "template<>", found here.
+ SourceRange RemoveRange = TemplateParams->getSourceRange();
+
+ // If we remove the template<> and the name is not a
+ // template-id, we're actually silently creating a problem:
+ // the friend declaration will refer to an untemplated decl,
+ // and clearly the user wants a template specialization. So
+ // we need to insert '<>' after the name.
+ SourceLocation InsertLoc;
+ if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+ InsertLoc = D.getName().getSourceRange().getEnd();
+ InsertLoc = PP.getLocForEndOfToken(InsertLoc);
+ }
+
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend)
+ << Name << RemoveRange
+ << FixItHint::CreateRemoval(RemoveRange)
+ << FixItHint::CreateInsertion(InsertLoc, "<>");
+ }
+ }
+ }
+ else {
+ // All template param lists were matched against the scope specifier:
+ // this is NOT (an explicit specialization of) a template.
+ if (TemplateParamLists.size() > 0)
+ // For source fidelity, store all the template param lists.
+ NewFD->setTemplateParameterListsInfo(Context,
+ TemplateParamLists.size(),
+ TemplateParamLists.release());
}
if (Invalid) {
@@ -3802,7 +4339,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
+ FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ isExplicitSpecialization ||
+ isFunctionTemplateSpecialization);
if (isFriend) {
// For now, claim that the objects have no previous declaration.
@@ -3863,8 +4402,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// In C++, the empty parameter-type-list must be spelled "void"; a
// typedef of void is not permitted.
if (getLangOptions().CPlusPlus &&
- Param->getType().getUnqualifiedType() != Context.VoidTy)
- Diag(Param->getLocation(), diag::err_param_typedef_of_void);
+ Param->getType().getUnqualifiedType() != Context.VoidTy) {
+ bool IsTypeAlias = false;
+ if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
+ IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
+ Diag(Param->getLocation(), diag::err_param_typedef_of_void)
+ << IsTypeAlias;
+ }
} 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);
@@ -3892,6 +4436,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
AE = FT->arg_type_end(); AI != AE; ++AI) {
ParmVarDecl *Param =
BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), *AI);
+ Param->setScopeInfo(0, Params.size());
Params.push_back(Param);
}
} else {
@@ -3977,9 +4522,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous))
NewFD->setInvalidDecl();
} else if (isFunctionTemplateSpecialization) {
- if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs : 0),
- Previous))
+ if (CurContext->isDependentContext() && CurContext->isRecord()
+ && !isFriend) {
+ Diag(NewFD->getLocation(), diag::err_function_specialization_in_class)
+ << NewFD->getDeclName();
+ NewFD->setInvalidDecl();
+ return 0;
+ } else if (CheckFunctionTemplateSpecialization(NewFD,
+ (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+ Previous))
NewFD->setInvalidDecl();
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
if (CheckMemberSpecialization(NewFD, Previous))
@@ -4049,7 +4600,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// are situations where these conditions don't apply and we
// can actually do this check immediately.
if (isFriend &&
- (NumMatchedTemplateParamLists ||
+ (TemplateParamLists.size() ||
D.getCXXScopeSpec().getScopeRep()->isDependent() ||
CurContext->isDependentContext())) {
// ignore these
@@ -4146,7 +4697,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
RegisterLocallyScopedExternCDecl(NewFD, Previous, S);
// Set this FunctionDecl's range up to the right paren.
- NewFD->setLocEnd(D.getSourceRange().getEnd());
+ NewFD->setRangeEnd(D.getSourceRange().getEnd());
if (getLangOptions().CPlusPlus) {
if (FunctionTemplate) {
@@ -4420,8 +4971,7 @@ void Sema::CheckMain(FunctionDecl* FD) {
// Darwin passes an undocumented fourth argument of type char**. If
// other platforms start sprouting these, the logic below will start
// getting shifty.
- if (nparams == 4 &&
- Context.Target.getTriple().getOS() == llvm::Triple::Darwin)
+ if (nparams == 4 && Context.Target.getTriple().isOSDarwin())
HasExtraParameters = false;
if (HasExtraParameters) {
@@ -4493,6 +5043,46 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
return true;
}
+namespace {
+ // Visits an initialization expression to see if OrigDecl is evaluated in
+ // its own initialization and throws a warning if it does.
+ class SelfReferenceChecker
+ : public EvaluatedExprVisitor<SelfReferenceChecker> {
+ Sema &S;
+ Decl *OrigDecl;
+
+ public:
+ typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
+
+ SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context),
+ S(S), OrigDecl(OrigDecl) { }
+
+ void VisitExpr(Expr *E) {
+ if (isa<ObjCMessageExpr>(*E)) return;
+ Inherited::VisitExpr(E);
+ }
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ CheckForSelfReference(E);
+ Inherited::VisitImplicitCastExpr(E);
+ }
+
+ void CheckForSelfReference(ImplicitCastExpr *E) {
+ if (E->getCastKind() != CK_LValueToRValue) return;
+ Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts();
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr);
+ if (!DRE) return;
+ Decl* ReferenceDecl = DRE->getDecl();
+ if (OrigDecl != ReferenceDecl) return;
+ LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
+ Sema::NotForRedeclaration);
+ S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init)
+ << Result.getLookupName() << OrigDecl->getLocation()
+ << SubExpr->getSourceRange();
+ }
+ };
+}
+
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@@ -4503,6 +5093,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (RealDecl == 0 || RealDecl->isInvalidDecl())
return;
+ // Check for self-references within variable initializers.
+ if (VarDecl *vd = dyn_cast<VarDecl>(RealDecl)) {
+ // Variables declared within a function/method body are handled
+ // by a dataflow analysis.
+ if (!vd->hasLocalStorage() && !vd->isStaticLocal())
+ SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
+ }
+ else {
+ SelfReferenceChecker(*this, RealDecl).VisitExpr(Init);
+ }
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
// With declarators parsed the way they are, the parser cannot
// distinguish between a normal initializer and a pure-specifier.
@@ -4533,15 +5134,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
- QualType DeducedType;
- if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) {
+ TypeSourceInfo *DeducedType = 0;
+ if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
<< Init->getSourceRange();
+ if (!DeducedType) {
RealDecl->setInvalidDecl();
return;
}
- VDecl->setType(DeducedType);
+ VDecl->setTypeSourceInfo(DeducedType);
+ VDecl->setType(DeducedType->getType());
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
@@ -4952,7 +5555,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
const RecordType *Record
= Context.getBaseElementType(Type)->getAs<RecordType>();
- if (Record && getLangOptions().CPlusPlus && !getLangOptions().CPlusPlus0x &&
+ if (Record && getLangOptions().CPlusPlus &&
cast<CXXRecordDecl>(Record->getDecl())->isPOD()) {
// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
@@ -4965,7 +5568,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// any, have an indeterminate initial value); if the object
// or any of its subobjects are of const-qualified type, the
// program is ill-formed.
- // FIXME: DPG thinks it is very fishy that C++0x disables this.
} else {
// Check for jumps past the implicit initializer. C++0x
// clarifies that this applies to a "variable with automatic
@@ -4990,6 +5592,47 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
}
}
+void Sema::ActOnCXXForRangeDecl(Decl *D) {
+ VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (!VD) {
+ Diag(D->getLocation(), diag::err_for_range_decl_must_be_var);
+ D->setInvalidDecl();
+ return;
+ }
+
+ VD->setCXXForRangeDecl(true);
+
+ // for-range-declaration cannot be given a storage class specifier.
+ int Error = -1;
+ switch (VD->getStorageClassAsWritten()) {
+ case SC_None:
+ break;
+ case SC_Extern:
+ Error = 0;
+ break;
+ case SC_Static:
+ Error = 1;
+ break;
+ case SC_PrivateExtern:
+ Error = 2;
+ break;
+ case SC_Auto:
+ Error = 3;
+ break;
+ case SC_Register:
+ Error = 4;
+ break;
+ }
+ // FIXME: constexpr isn't allowed here.
+ //if (DS.isConstexprSpecified())
+ // Error = 5;
+ if (Error != -1) {
+ Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class)
+ << VD->getDeclName() << Error;
+ D->setInvalidDecl();
+ }
+}
+
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;
@@ -5058,7 +5701,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (Decl *D = Group[i])
Decls.push_back(D);
- return BuildDeclaratorGroup(Decls.data(), Decls.size(),
+ return BuildDeclaratorGroup(Decls.data(), Decls.size(),
DS.getTypeSpecType() == DeclSpec::TST_auto);
}
@@ -5195,12 +5838,18 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// the enclosing context. This prevents them from accidentally
// looking like class members in C++.
ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(),
- TInfo, parmDeclType, II,
- D.getIdentifierLoc(),
+ D.getSourceRange().getBegin(),
+ D.getIdentifierLoc(), II,
+ parmDeclType, TInfo,
StorageClass, StorageClassAsWritten);
if (D.isInvalidType())
- New->setInvalidDecl();
+ New->setInvalidDecl();
+
+ assert(S->isFunctionPrototypeScope());
+ assert(S->getFunctionPrototypeDepth() >= 1);
+ New->setScopeInfo(S->getFunctionPrototypeDepth() - 1,
+ S->getNextFunctionPrototypeIndex());
// Add the parameter declaration into this scope.
S->AddDecl(New);
@@ -5220,7 +5869,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
QualType T) {
- ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, 0,
+ /* FIXME: setting StartLoc == Loc.
+ Would it be worth to modify callers so as to provide proper source
+ location for the unnamed parameters, embedding the parameter's type? */
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, 0,
T, Context.getTrivialTypeSourceInfo(T, Loc),
SC_None, SC_None, 0);
Param->setImplicit();
@@ -5272,14 +5924,13 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
}
}
-ParmVarDecl *Sema::CheckParameter(DeclContext *DC,
- TypeSourceInfo *TSInfo, QualType T,
- IdentifierInfo *Name,
- SourceLocation NameLoc,
+ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation NameLoc, IdentifierInfo *Name,
+ QualType T, TypeSourceInfo *TSInfo,
VarDecl::StorageClass StorageClass,
VarDecl::StorageClass StorageClassAsWritten) {
- ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name,
- adjustParameterType(T), TSInfo,
+ ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
+ adjustParameterType(T), TSInfo,
StorageClass, StorageClassAsWritten,
0);
@@ -5331,7 +5982,8 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
// Implicitly declare the argument as type 'int' for lack of a better
// type.
- DeclSpec DS;
+ AttributeFactory attrs;
+ DeclSpec DS(attrs);
const char* PrevSpec; // unused
unsigned DiagID; // unused
DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
@@ -5374,7 +6026,7 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
return false;
// Don't warn about inline functions.
- if (FD->isInlineSpecified())
+ if (FD->isInlined())
return false;
// Don't warn about function templates.
@@ -5400,6 +6052,22 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
return MissingPrototype;
}
+void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
+ // Don't complain if we're in GNU89 mode and the previous definition
+ // was an extern inline function.
+ const FunctionDecl *Definition;
+ if (FD->hasBody(Definition) &&
+ !canRedefineFunction(Definition, getLangOptions())) {
+ if (getLangOptions().GNUMode && Definition->isInlineSpecified() &&
+ Definition->getStorageClass() == SC_Extern)
+ Diag(FD->getLocation(), diag::err_redefinition_extern_inline)
+ << FD->getDeclName() << getLangOptions().CPlusPlus;
+ else
+ Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
+ Diag(Definition->getLocation(), diag::note_previous_definition);
+ }
+}
+
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// Clear the last template instantiation error context.
LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation();
@@ -5417,19 +6085,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
PushFunctionScope();
// See if this is a redefinition.
- // But don't complain if we're in GNU89 mode and the previous definition
- // was an extern inline function.
- const FunctionDecl *Definition;
- if (FD->hasBody(Definition) &&
- !canRedefineFunction(Definition, getLangOptions())) {
- if (getLangOptions().GNUMode && Definition->isInlineSpecified() &&
- Definition->getStorageClass() == SC_Extern)
- Diag(FD->getLocation(), diag::err_redefinition_extern_inline)
- << FD->getDeclName() << getLangOptions().CPlusPlus;
- else
- Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
- Diag(Definition->getLocation(), diag::note_previous_definition);
- }
+ if (!FD->isLateTemplateParsed())
+ CheckForFunctionRedefinition(FD);
// Builtin functions cannot be defined.
if (unsigned BuiltinID = FD->getBuiltinID()) {
@@ -5481,7 +6138,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
DLLImportAttr *DA = FD->getAttr<DLLImportAttr>();
if (DA && (!FD->getAttr<DLLExportAttr>())) {
// dllimport attribute cannot be directly applied to definition.
- if (!DA->isInherited()) {
+ // Microsoft accepts dllimport for functions defined within class scope.
+ if (!DA->isInherited() &&
+ !(LangOpts.Microsoft && FD->getLexicalDeclContext()->isRecord())) {
Diag(FD->getLocation(),
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
<< "dllimport";
@@ -5615,7 +6274,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (PP.getDiagnostics().hasErrorOccurred())
+ if (PP.getDiagnostics().hasErrorOccurred() ||
+ PP.getDiagnostics().getSuppressAllDiagnostics())
ExprTemporaries.clear();
else if (!isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
@@ -5666,17 +6326,18 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// Set a Declarator for the implicit definition: int foo();
const char *Dummy;
- DeclSpec DS;
+ AttributeFactory attrFactory;
+ DeclSpec DS(attrFactory);
unsigned DiagID;
bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID);
(void)Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
Declarator D(DS, Declarator::BlockContext);
- D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(),
- false, false, SourceLocation(), 0,
+ D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
0, 0, true, SourceLocation(),
- false, SourceLocation(),
- false, 0,0,0, Loc, Loc, D),
+ EST_None, SourceLocation(),
+ 0, 0, 0, 0, Loc, Loc, D),
+ DS.getAttributes(),
SourceLocation());
D.SetIdentifier(&II, Loc);
@@ -5784,6 +6445,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
// Scope manipulation handled by caller.
TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext,
+ D.getSourceRange().getBegin(),
D.getIdentifierLoc(),
D.getIdentifier(),
TInfo);
@@ -5810,7 +6472,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
// Do nothing if the tag is not anonymous or already has an
// associated typedef (from an earlier typedef in this decl group).
if (tagFromDeclSpec->getIdentifier()) break;
- if (tagFromDeclSpec->getTypedefForAnonDecl()) break;
+ if (tagFromDeclSpec->getTypedefNameForAnonDecl()) break;
// A well-formed anonymous tag must always be a TUK_Definition.
assert(tagFromDeclSpec->isThisDeclarationADefinition());
@@ -5820,7 +6482,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
break;
// Otherwise, set this is the anon-decl typedef for the tag.
- tagFromDeclSpec->setTypedefForAnonDecl(NewTD);
+ tagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);
break;
}
@@ -5897,36 +6559,33 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// FIXME: Check explicit specializations more carefully.
bool isExplicitSpecialization = false;
- unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size();
bool Invalid = false;
// We only need to do this matching if we have template parameters
// or a scope specifier, which also conveniently avoids this work
// for non-C++ cases.
- if (NumMatchedTemplateParamLists ||
+ if (TemplateParameterLists.size() > 0 ||
(SS.isNotEmpty() && TUK != TUK_Reference)) {
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
TemplateParameterLists.get(),
- TemplateParameterLists.size(),
+ TemplateParameterLists.size(),
TUK == TUK_Friend,
isExplicitSpecialization,
Invalid)) {
- // All but one template parameter lists have been matching.
- --NumMatchedTemplateParamLists;
-
if (TemplateParams->size() > 0) {
// This is a declaration or definition of a class template (which may
// be a member of another template).
+
if (Invalid)
return 0;
-
+
OwnedDecl = false;
DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
SS, Name, NameLoc, Attr,
- TemplateParams,
- AS);
- TemplateParameterLists.release();
+ TemplateParams, AS,
+ TemplateParameterLists.size() - 1,
+ (TemplateParameterList**) TemplateParameterLists.release());
return Result.get();
} else {
// The "template<>" header is extraneous.
@@ -6164,7 +6823,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// okay according to the likely resolution of an open issue;
// see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407
if (getLangOptions().CPlusPlus) {
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(PrevDecl)) {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(PrevDecl)) {
if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
TagDecl *Tag = TT->getDecl();
if (Tag->getDeclName() == Name &&
@@ -6184,7 +6843,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// in the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl.
if (TUK == TUK_Reference || TUK == TUK_Friend ||
- isDeclInScope(PrevDecl, SearchDC, S)) {
+ isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
@@ -6322,30 +6981,34 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
!Previous.isForRedeclaration()) {
unsigned Kind = 0;
if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
- else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3;
Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind;
Diag(PrevDecl->getLocation(), diag::note_declared_at);
Invalid = true;
// Otherwise, only diagnose if the declaration is in scope.
- } else if (!isDeclInScope(PrevDecl, SearchDC, S)) {
+ } else if (!isDeclInScope(PrevDecl, SearchDC, S,
+ isExplicitSpecialization)) {
// do nothing
// Diagnose implicit declarations introduced by elaborated types.
} else if (TUK == TUK_Reference || TUK == TUK_Friend) {
unsigned Kind = 0;
if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
- else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3;
Diag(NameLoc, diag::err_tag_reference_conflict) << Kind;
Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
Invalid = true;
// Otherwise it's a declaration. Call out a particularly common
// case here.
- } else if (isa<TypedefDecl>(PrevDecl)) {
+ } else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(PrevDecl)) {
+ unsigned Kind = 0;
+ if (isa<TypeAliasDecl>(PrevDecl)) Kind = 1;
Diag(NameLoc, diag::err_tag_definition_of_typedef)
- << Name
- << cast<TypedefDecl>(PrevDecl)->getUnderlyingType();
+ << Name << Kind << TND->getUnderlyingType();
Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
Invalid = true;
@@ -6385,7 +7048,7 @@ CreateNewDecl:
if (Kind == TTK_Enum) {
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// enum X { A, B, C } D; D should chain to X.
- New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc,
+ New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name,
cast_or_null<EnumDecl>(PrevDecl), ScopedEnum,
ScopedEnumUsesClassTag, !EnumUnderlying.isNull());
// If this is an undefined enum, warn.
@@ -6431,13 +7094,13 @@ CreateNewDecl:
// struct X { int A; } D; D should chain to X.
if (getLangOptions().CPlusPlus) {
// FIXME: Look for a way to use RecordDecl for simple structs.
- New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
+ New = CXXRecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name,
cast_or_null<CXXRecordDecl>(PrevDecl));
-
+
if (isStdBadAlloc && (!StdBadAlloc || getStdBadAlloc()->isImplicit()))
StdBadAlloc = cast<CXXRecordDecl>(New);
} else
- New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc,
+ New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name,
cast_or_null<RecordDecl>(PrevDecl));
}
@@ -6445,9 +7108,9 @@ CreateNewDecl:
if (SS.isNotEmpty()) {
if (SS.isSet()) {
New->setQualifierInfo(SS.getWithLocInContext(Context));
- if (NumMatchedTemplateParamLists > 0) {
+ if (TemplateParameterLists.size() > 0) {
New->setTemplateParameterListsInfo(Context,
- NumMatchedTemplateParamLists,
+ TemplateParameterLists.size(),
(TemplateParameterList**) TemplateParameterLists.release());
}
}
@@ -6466,6 +7129,8 @@ CreateNewDecl:
// the #pragma tokens are effectively skipped over during the
// parsing of the struct).
AddAlignmentAttributesForRecord(RD);
+
+ AddMsStructLayoutForRecord(RD);
}
// If this is a specialization of a member class (of a class template),
@@ -6541,7 +7206,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
}
void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
- ClassVirtSpecifiers &CVS,
+ SourceLocation FinalLoc,
SourceLocation LBraceLoc) {
AdjustDeclIfTemplate(TagD);
CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD);
@@ -6551,10 +7216,8 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
if (!Record->getIdentifier())
return;
- if (CVS.isFinalSpecified())
- Record->addAttr(new (Context) FinalAttr(CVS.getFinalLoc(), Context));
- if (CVS.isExplicitSpecified())
- Record->addAttr(new (Context) ExplicitAttr(CVS.getExplicitLoc(), Context));
+ if (FinalLoc.isValid())
+ Record->addAttr(new (Context) FinalAttr(FinalLoc, Context));
// C++ [class]p2:
// [...] The class-name is also inserted into the scope of the
@@ -6562,10 +7225,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
// purposes of access checking, the injected-class-name is treated
// as if it were a public member name.
CXXRecordDecl *InjectedClassName
- = CXXRecordDecl::Create(Context, Record->getTagKind(),
- CurContext, Record->getLocation(),
+ = CXXRecordDecl::Create(Context, Record->getTagKind(), CurContext,
+ Record->getLocStart(), Record->getLocation(),
Record->getIdentifier(),
- Record->getTagKeywordLoc(),
/*PrevDecl=*/0,
/*DelayTypeCreation=*/true);
Context.getTypeDeclType(InjectedClassName, Record);
@@ -6852,7 +7514,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
}
- FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, TInfo,
+ FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
BitWidth, Mutable);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -7152,8 +7814,8 @@ Decl *Sema::ActOnIvar(Scope *S,
}
// Construct the decl.
- ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
- EnclosingContext, Loc, II, T,
+ ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, EnclosingContext,
+ DeclStart, Loc, II, T,
TInfo, ac, (Expr *)BitfieldWidth);
if (II) {
@@ -7216,7 +7878,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl,
Expr * BW = IntegerLiteral::Create(Context, Zero, Context.CharTy, DeclLoc);
Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(EnclosingDecl),
- DeclLoc, 0,
+ DeclLoc, DeclLoc, 0,
Context.CharTy,
Context.CreateTypeSourceInfo(Context.CharTy),
ObjCIvarDecl::Private, BW,
@@ -7281,20 +7943,27 @@ void Sema::ActOnFields(Scope* S,
continue;
} else if (FDTy->isIncompleteArrayType() && Record &&
((i == NumFields - 1 && !Record->isUnion()) ||
- (getLangOptions().Microsoft &&
+ ((getLangOptions().Microsoft || getLangOptions().CPlusPlus) &&
(i == NumFields - 1 || Record->isUnion())))) {
// Flexible array member.
- // Microsoft is more permissive regarding flexible array.
+ // Microsoft and g++ is more permissive regarding flexible array.
// It will accept flexible array in union and also
// as the sole element of a struct/class.
if (getLangOptions().Microsoft) {
if (Record->isUnion())
- Diag(FD->getLocation(), diag::ext_flexible_array_union)
+ Diag(FD->getLocation(), diag::ext_flexible_array_union_ms)
+ << FD->getDeclName();
+ else if (NumFields == 1)
+ Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms)
+ << FD->getDeclName() << Record->getTagKind();
+ } else if (getLangOptions().CPlusPlus) {
+ if (Record->isUnion())
+ Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu)
<< FD->getDeclName();
else if (NumFields == 1)
- Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate)
+ Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu)
<< FD->getDeclName() << Record->getTagKind();
- } else if (NumNamedMembers < 1) {
+ } else if (NumNamedMembers < 1) {
Diag(FD->getLocation(), diag::err_flexible_array_empty_struct)
<< FD->getDeclName();
FD->setInvalidDecl();
@@ -7547,7 +8216,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
<< (EnumVal.isUnsigned() || EnumVal.isNonNegative());
else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
// Force the type of the expression to 'int'.
- ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast);
+ Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).take();
}
}
@@ -7560,12 +8229,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
if (getLangOptions().Microsoft) {
Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
- ImpCastExprToType(Val, EltTy, CK_IntegralCast);
+ Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
} else
Diag(IdLoc, diag::err_enumerator_too_large)
<< EltTy;
} else
- ImpCastExprToType(Val, EltTy, CK_IntegralCast);
+ Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
}
else {
// C++0x [dcl.enum]p5:
@@ -7949,11 +8618,14 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
NumPositiveBits, NumNegativeBits);
}
-Decl *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, Expr *expr) {
+Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
StringLiteral *AsmString = cast<StringLiteral>(expr);
FileScopeAsmDecl *New = FileScopeAsmDecl::Create(Context, CurContext,
- Loc, AsmString);
+ AsmString, StartLoc,
+ EndLoc);
CurContext->addDecl(New);
return New;
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 893cf6ac26e4..7f93ab72d6d1 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -24,6 +24,26 @@
using namespace clang;
using namespace sema;
+/// These constants match the enumerated choices of
+/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type.
+enum {
+ ExpectedFunction,
+ ExpectedUnion,
+ ExpectedVariableOrFunction,
+ ExpectedFunctionOrMethod,
+ ExpectedParameter,
+ ExpectedParameterOrMethod,
+ ExpectedFunctionMethodOrBlock,
+ ExpectedClassOrVirtualMethod,
+ ExpectedFunctionMethodOrParameter,
+ ExpectedClass,
+ ExpectedVirtualMethod,
+ ExpectedClassMember,
+ ExpectedVariable,
+ ExpectedMethod,
+ ExpectedVariableFunctionOrLabel
+};
+
//===----------------------------------------------------------------------===//
// Helper functions
//===----------------------------------------------------------------------===//
@@ -35,7 +55,7 @@ static const FunctionType *getFunctionType(const Decl *d,
Ty = decl->getType();
else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d))
Ty = decl->getType();
- else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d))
+ else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(d))
Ty = decl->getUnderlyingType();
else
return 0;
@@ -81,8 +101,8 @@ static bool isFunctionOrMethodOrBlock(const Decl *d) {
/// Return true if the given decl has a declarator that should have
/// been processed by Sema::GetTypeForDeclarator.
static bool hasDeclarator(const Decl *d) {
- // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
- return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefDecl>(d);
+ // In some sense, TypedefNameDecl really *ought* to be a DeclaratorDecl.
+ return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefNameDecl>(d);
}
/// hasFunctionProto - Return true if the given decl has a argument
@@ -182,7 +202,7 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
const AttributeList &Attr, Sema &S) {
- TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d);
+ TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(d);
if (tDecl == 0) {
S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
return;
@@ -241,6 +261,13 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
+static void HandleMsStructAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(d))
+ TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context));
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() > 0) {
@@ -332,7 +359,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// ignore it as well
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -474,8 +501,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
}
if (!isFunction(d) || !hasFunctionProto(d)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL.getName()
- << 0 /*function*/;
+ S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << AL.getName() << ExpectedFunction;
return;
}
@@ -615,7 +642,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variables and functions*/;
+ << Attr.getName() << ExpectedVariableOrFunction;
return;
}
@@ -701,7 +728,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (S.Context.Target.getTriple().getOS() == llvm::Triple::Darwin) {
+ if (S.Context.Target.getTriple().isOSDarwin()) {
S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin);
return;
}
@@ -722,7 +749,7 @@ static void HandleNakedAttr(Decl *d, const AttributeList &Attr,
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -732,14 +759,14 @@ static void HandleNakedAttr(Decl *d, const AttributeList &Attr,
static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
// Check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
+ if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -748,7 +775,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
+ if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
@@ -780,7 +807,7 @@ static void HandleNoCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 12 /* variable */;
+ << Attr.getName() << ExpectedVariable;
}
static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -789,7 +816,7 @@ static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 12 /* variable */;
+ << Attr.getName() << ExpectedVariable;
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
@@ -799,7 +826,7 @@ static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
if (!isa<ObjCMethodDecl>(d)) {
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << 0 /*function*/;
+ << attr.getName() << ExpectedFunctionOrMethod;
return;
}
@@ -807,7 +834,7 @@ static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
- if (attr.getNumArgs() != 0) {
+ if (attr.hasParameterOrArguments()) {
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
attr.setInvalid();
return true;
@@ -834,7 +861,7 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
S.Diag(Attr.getLoc(),
Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
: diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
}
@@ -870,7 +897,7 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
*/
if (!isa<RecordDecl>(d)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << 9 /*class*/;
+ << Attr.getName() << ExpectedClass;
return;
}
@@ -907,7 +934,7 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << 8 /*function, method, or parameter*/;
+ << Attr.getName() << ExpectedFunctionMethodOrParameter;
return;
}
// FIXME: Actually store the attribute on the declaration
@@ -915,7 +942,7 @@ static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
+ if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
@@ -923,7 +950,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) &&
!isa<TypeDecl>(d) && !isa<LabelDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 14 /*variable, function, labels*/;
+ << Attr.getName() << ExpectedVariableFunctionOrLabel;
return;
}
@@ -932,7 +959,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
+ if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
@@ -944,7 +971,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
} else if (!isFunctionOrMethod(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
+ << Attr.getName() << ExpectedVariableOrFunction;
return;
}
@@ -953,9 +980,8 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << "0 or 1";
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
@@ -974,7 +1000,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -984,9 +1010,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << "0 or 1";
+ if (Attr.getNumArgs() > 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
@@ -1005,7 +1030,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -1016,8 +1041,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
- S.Diag(Attr.getLoc(),
- diag::err_attribute_wrong_number_arguments) << "0 or 1";
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
@@ -1039,8 +1063,7 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned NumArgs = Attr.getNumArgs();
if (NumArgs > 1) {
- S.Diag(Attr.getLoc(),
- diag::err_attribute_wrong_number_arguments) << "0 or 1";
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
@@ -1058,6 +1081,59 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str));
}
+static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+ IdentifierInfo *Platform = Attr.getParameterName();
+ SourceLocation PlatformLoc = Attr.getParameterLoc();
+
+ llvm::StringRef PlatformName
+ = AvailabilityAttr::getPrettyPlatformName(Platform->getName());
+ if (PlatformName.empty()) {
+ S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
+ << Platform;
+
+ PlatformName = Platform->getName();
+ }
+
+ AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
+ AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
+ AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
+ bool IsUnavailable = Attr.getUnavailableLoc().isValid();
+
+ // Ensure that Introduced < Deprecated < Obsoleted (although not all
+ // of these steps are needed).
+ if (Introduced.isValid() && Deprecated.isValid() &&
+ !(Introduced.Version < Deprecated.Version)) {
+ S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
+ << 1 << PlatformName << Deprecated.Version.getAsString()
+ << 0 << Introduced.Version.getAsString();
+ return;
+ }
+
+ if (Introduced.isValid() && Obsoleted.isValid() &&
+ !(Introduced.Version < Obsoleted.Version)) {
+ S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering)
+ << 2 << PlatformName << Obsoleted.Version.getAsString()
+ << 0 << Introduced.Version.getAsString();
+ return;
+ }
+
+ if (Deprecated.isValid() && Obsoleted.isValid() &&
+ !(Deprecated.Version < Obsoleted.Version)) {
+ S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering)
+ << 2 << PlatformName << Obsoleted.Version.getAsString()
+ << 1 << Deprecated.Version.getAsString();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context,
+ Platform,
+ Introduced.Version,
+ Deprecated.Version,
+ Obsoleted.Version,
+ IsUnavailable));
+}
+
static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1) {
@@ -1094,6 +1170,51 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type));
}
+static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr,
+ Sema &S) {
+ ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl);
+ if (!method) {
+ S.Diag(attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << ExpectedMethod;
+ return;
+ }
+
+ if (attr.getNumArgs() != 0 || !attr.getParameterName()) {
+ if (!attr.getParameterName() && attr.getNumArgs() == 1) {
+ S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "objc_method_family" << 1;
+ } else {
+ S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ }
+ attr.setInvalid();
+ return;
+ }
+
+ llvm::StringRef param = attr.getParameterName()->getName();
+ ObjCMethodFamilyAttr::FamilyKind family;
+ if (param == "none")
+ family = ObjCMethodFamilyAttr::OMF_None;
+ else if (param == "alloc")
+ family = ObjCMethodFamilyAttr::OMF_alloc;
+ else if (param == "copy")
+ family = ObjCMethodFamilyAttr::OMF_copy;
+ else if (param == "init")
+ family = ObjCMethodFamilyAttr::OMF_init;
+ else if (param == "mutableCopy")
+ family = ObjCMethodFamilyAttr::OMF_mutableCopy;
+ else if (param == "new")
+ family = ObjCMethodFamilyAttr::OMF_new;
+ else {
+ // Just warn and ignore it. This is future-proof against new
+ // families being used in system headers.
+ S.Diag(attr.getParameterLoc(), diag::warn_unknown_method_family);
+ return;
+ }
+
+ decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(),
+ S.Context, family));
+}
+
static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
Sema &S) {
if (Attr.getNumArgs() != 0) {
@@ -1115,7 +1236,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
QualType T = TD->getUnderlyingType();
if (!T->isPointerType() ||
!T->getAs<PointerType>()->getPointeeType()->isRecordType()) {
@@ -1168,8 +1289,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() > 2) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << "0, 1 or 2";
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2;
return;
}
@@ -1247,12 +1367,12 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 6 /*function, method or block */;
+ << Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 6 /*function, method or block */;
+ << Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel,
@@ -1268,7 +1388,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunctionOrMethod;
return;
}
@@ -1289,14 +1409,14 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
static void HandleWeakAttr(Decl *d, const AttributeList &attr, Sema &S) {
// check the attribute arguments.
- if (attr.getNumArgs() != 0) {
+ if (attr.hasParameterOrArguments()) {
S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << 2 /*variables and functions*/;
+ << attr.getName() << ExpectedVariableOrFunction;
return;
}
@@ -1320,27 +1440,19 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// weak_import only applies to variable & function declarations.
bool isDef = false;
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- isDef = (!VD->hasExternalStorage() || VD->getInit());
- } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- isDef = FD->hasBody();
- } else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) {
- // We ignore weak import on properties and methods
- return;
- } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) {
- // Don't issue the warning for darwin as target; yet, ignore the attribute.
- if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin ||
- !isa<ObjCInterfaceDecl>(D))
+ if (!D->canBeWeakImported(isDef)) {
+ if (isDef)
+ S.Diag(Attr.getLoc(),
+ diag::warn_attribute_weak_import_invalid_on_definition)
+ << "weak_import" << 2 /*variable and function*/;
+ else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) ||
+ (S.Context.Target.getTriple().isOSDarwin() &&
+ isa<ObjCInterfaceDecl>(D))) {
+ // Nothing to warn about here.
+ } else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
- return;
- }
+ << Attr.getName() << ExpectedVariableOrFunction;
- // Merge should handle any subsequent violations.
- if (isDef) {
- S.Diag(Attr.getLoc(),
- diag::warn_attribute_weak_import_invalid_on_definition)
- << "weak_import" << 2 /*variable and function*/;
return;
}
@@ -1409,7 +1521,7 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
+ if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
@@ -1419,7 +1531,7 @@ static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
+ if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
@@ -1506,7 +1618,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -1674,7 +1786,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -1807,7 +1919,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
// Try to find the underlying union declaration.
RecordDecl *RD = 0;
- TypedefDecl *TD = dyn_cast<TypedefDecl>(d);
+ TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(d);
if (TD && TD->getUnderlyingType()->isUnionType())
RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
else
@@ -1815,7 +1927,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
if (!RD || !RD->isUnion()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 1 /*union*/;
+ << Attr.getName() << ExpectedUnion;
return;
}
@@ -1998,7 +2110,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
QualType OldTy;
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D))
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
OldTy = TD->getUnderlyingType();
else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
OldTy = VD->getType();
@@ -2097,7 +2209,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
}
// Install the new type.
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
// FIXME: preserve existing source info.
TD->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(NewTy));
} else
@@ -2113,7 +2225,7 @@ static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isFunctionOrMethod(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -2129,7 +2241,7 @@ static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -2146,7 +2258,7 @@ static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr,
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -2157,14 +2269,14 @@ static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr,
static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (S.LangOpts.CUDA) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
+ if (Attr.hasParameterOrArguments()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
if (!isa<VarDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 12 /*variable*/;
+ << Attr.getName() << ExpectedVariable;
return;
}
@@ -2184,7 +2296,7 @@ static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<FunctionDecl>(d) && !isa<VarDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
+ << Attr.getName() << ExpectedVariableOrFunction;
return;
}
@@ -2204,7 +2316,7 @@ static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -2239,7 +2351,7 @@ static void HandleHostAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -2259,7 +2371,7 @@ static void HandleSharedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isa<VarDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 12 /*variable*/;
+ << Attr.getName() << ExpectedVariable;
return;
}
@@ -2279,7 +2391,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
if (Fn == 0) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunction;
return;
}
@@ -2302,7 +2414,7 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
if (!isa<ObjCMethodDecl>(d)) {
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << 0 /*function*/;
+ << attr.getName() << ExpectedFunctionOrMethod;
return;
}
@@ -2322,6 +2434,30 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
case AttributeList::AT_pascal:
d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context));
return;
+ case AttributeList::AT_pcs: {
+ Expr *Arg = attr.getArg(0);
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+ if (Str == 0 || Str->isWide()) {
+ S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "pcs" << 1;
+ attr.setInvalid();
+ return;
+ }
+
+ llvm::StringRef StrRef = Str->getString();
+ PcsAttr::PCSType PCS;
+ if (StrRef == "aapcs")
+ PCS = PcsAttr::AAPCS;
+ else if (StrRef == "aapcs-vfp")
+ PCS = PcsAttr::AAPCS_VFP;
+ else {
+ S.Diag(attr.getLoc(), diag::err_invalid_pcs);
+ attr.setInvalid();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) PcsAttr(attr.getLoc(), S.Context, PCS));
+ }
default:
llvm_unreachable("unexpected attribute kind");
return;
@@ -2337,19 +2473,42 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
if (attr.isInvalid())
return true;
- if (attr.getNumArgs() != 0) {
+ if ((attr.getNumArgs() != 0 &&
+ !(attr.getKind() == AttributeList::AT_pcs && attr.getNumArgs() == 1)) ||
+ attr.getParameterName()) {
Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
attr.setInvalid();
return true;
}
- // TODO: diagnose uses of these conventions on the wrong target.
+ // TODO: diagnose uses of these conventions on the wrong target. Or, better
+ // move to TargetAttributesSema one day.
switch (attr.getKind()) {
case AttributeList::AT_cdecl: CC = CC_C; break;
case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
case AttributeList::AT_pascal: CC = CC_X86Pascal; break;
+ case AttributeList::AT_pcs: {
+ Expr *Arg = attr.getArg(0);
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+ if (Str == 0 || Str->isWide()) {
+ Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "pcs" << 1;
+ attr.setInvalid();
+ return true;
+ }
+
+ llvm::StringRef StrRef = Str->getString();
+ if (StrRef == "aapcs") {
+ CC = CC_AAPCS;
+ break;
+ } else if (StrRef == "aapcs-vfp") {
+ CC = CC_AAPCS_VFP;
+ break;
+ }
+ // FALLS THROUGH
+ }
default: llvm_unreachable("unexpected attribute kind"); return true;
}
@@ -2365,7 +2524,7 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) {
if (!isa<ObjCMethodDecl>(d)) {
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << 0 /*function*/;
+ << attr.getName() << ExpectedFunctionOrMethod;
return;
}
@@ -2416,14 +2575,14 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
if (S.LangOpts.CUDA) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << "1 or 2";
+ // FIXME: 0 is not okay.
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2;
return;
}
if (!isFunctionOrMethod(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << ExpectedFunctionOrMethod;
return;
}
@@ -2472,7 +2631,7 @@ static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) {
ParmVarDecl *param = dyn_cast<ParmVarDecl>(d);
if (!param) {
S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName() << 4 /*parameter*/;
+ << SourceRange(attr.getLoc()) << attr.getName() << ExpectedParameter;
return;
}
@@ -2501,7 +2660,7 @@ static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr,
Sema &S) {
if (!isa<ObjCMethodDecl>(d)) {
S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(attr.getLoc()) << attr.getName() << 13 /*method*/;
+ << SourceRange(attr.getLoc()) << attr.getName() << ExpectedMethod;
return;
}
@@ -2520,7 +2679,7 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr,
else {
S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
<< SourceRange(attr.getLoc()) << attr.getName()
- << 3 /* function or method */;
+ << ExpectedFunctionOrMethod;
return;
}
@@ -2664,6 +2823,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
case AttributeList::AT_IBOutletCollection:
HandleIBOutletCollection(D, Attr, S); break;
case AttributeList::AT_address_space:
+ case AttributeList::AT_opencl_image_access:
case AttributeList::AT_objc_gc:
case AttributeList::AT_vector_size:
case AttributeList::AT_neon_vector_type:
@@ -2684,6 +2844,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
case AttributeList::AT_analyzer_noreturn:
HandleAnalyzerNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
+ case AttributeList::AT_availability:HandleAvailabilityAttr(D, Attr, S); break;
case AttributeList::AT_carries_dependency:
HandleDependencyAttr (D, Attr, S); break;
case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break;
@@ -2736,6 +2897,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
HandleInitPriorityAttr(D, Attr, S); break;
case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
+ case AttributeList::AT_MsStruct: HandleMsStructAttr (D, Attr, S); break;
case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
@@ -2752,6 +2914,9 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
case AttributeList::AT_objc_exception:
HandleObjCExceptionAttr(D, Attr, S);
break;
+ case AttributeList::AT_objc_method_family:
+ HandleObjCMethodFamilyAttr(D, Attr, S);
+ break;
case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
@@ -2772,6 +2937,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
case AttributeList::AT_fastcall:
case AttributeList::AT_thiscall:
case AttributeList::AT_pascal:
+ case AttributeList::AT_pcs:
HandleCallConvAttr(D, Attr, S);
break;
case AttributeList::AT_opencl_kernel_function:
@@ -2837,6 +3003,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
NamedDecl *NewD = 0;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
+ FD->getInnerLocStart(),
FD->getLocation(), DeclarationName(II),
FD->getType(), FD->getTypeSourceInfo());
if (FD->getQualifier()) {
@@ -2845,7 +3012,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
}
} else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) {
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
- VD->getLocation(), II,
+ VD->getInnerLocStart(), VD->getLocation(), II,
VD->getType(), VD->getTypeSourceInfo(),
VD->getStorageClass(),
VD->getStorageClassAsWritten());
@@ -2986,14 +3153,14 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
// Destroy all the delayed diagnostics we're about to pop off.
for (unsigned i = state.SavedStackSize, e = DD.StackSize; i != e; ++i)
- DD.Stack[i].destroy();
+ DD.Stack[i].Destroy();
DD.StackSize = state.SavedStackSize;
}
static bool isDeclDeprecated(Decl *D) {
do {
- if (D->hasAttr<DeprecatedAttr>())
+ if (D->isDeprecated())
return true;
} while ((D = cast_or_null<Decl>(D->getDeclContext())));
return false;
@@ -3016,7 +3183,7 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message,
SourceLocation Loc,
- bool UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass) {
// Delay if we're currently parsing a declaration.
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, Message));
@@ -3032,7 +3199,9 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message,
else {
if (!UnknownObjCClass)
Diag(Loc, diag::warn_deprecated) << D->getDeclName();
- else
+ else {
Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName();
+ Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
+ }
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f483262a8cf5..27632a1a57c4 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -18,9 +18,11 @@
#include "clang/Sema/Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
@@ -287,17 +289,37 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
ParmVarDecl *NewParam = New->getParamDecl(p);
if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) {
+
+ unsigned DiagDefaultParamID =
+ diag::err_param_default_argument_redefinition;
+
+ // MSVC accepts that default parameters be redefined for member functions
+ // of template class. The new default parameter's value is ignored.
+ Invalid = true;
+ if (getLangOptions().Microsoft) {
+ CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(New);
+ if (MD && MD->getParent()->getDescribedClassTemplate()) {
+ // Merge the old default argument into the new parameter.
+ NewParam->setHasInheritedDefaultArg();
+ if (OldParam->hasUninstantiatedDefaultArg())
+ NewParam->setUninstantiatedDefaultArg(
+ OldParam->getUninstantiatedDefaultArg());
+ else
+ NewParam->setDefaultArg(OldParam->getInit());
+ DiagDefaultParamID = diag::warn_param_default_argument_redefinition;
+ Invalid = false;
+ }
+ }
+
// FIXME: If we knew where the '=' was, we could easily provide a fix-it
// hint here. Alternatively, we could walk the type-source information
// for NewParam to find the last source location in the type... but it
// isn't worth the effort right now. This is the kind of test case that
// is hard to get right:
-
// int f(int);
// void g(int (*fp)(int) = f);
// void g(int (*fp)(int) = &f);
- Diag(NewParam->getLocation(),
- diag::err_param_default_argument_redefinition)
+ Diag(NewParam->getLocation(), DiagDefaultParamID)
<< NewParam->getDefaultArgRange();
// Look for the function declaration where the default argument was
@@ -312,7 +334,6 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
Diag(OldParam->getLocation(), diag::note_previous_definition)
<< OldParam->getDefaultArgRange();
- Invalid = true;
} else if (OldParam->hasDefaultArg()) {
// Merge the old default argument into the new parameter.
// It's important to use getInit() here; getDefaultArg()
@@ -382,6 +403,48 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
return Invalid;
}
+/// \brief Merge the exception specifications of two variable declarations.
+///
+/// This is called when there's a redeclaration of a VarDecl. The function
+/// checks if the redeclaration might have an exception specification and
+/// validates compatibility and merges the specs if necessary.
+void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
+ // Shortcut if exceptions are disabled.
+ if (!getLangOptions().CXXExceptions)
+ return;
+
+ assert(Context.hasSameType(New->getType(), Old->getType()) &&
+ "Should only be called if types are otherwise the same.");
+
+ QualType NewType = New->getType();
+ QualType OldType = Old->getType();
+
+ // We're only interested in pointers and references to functions, as well
+ // as pointers to member functions.
+ if (const ReferenceType *R = NewType->getAs<ReferenceType>()) {
+ NewType = R->getPointeeType();
+ OldType = OldType->getAs<ReferenceType>()->getPointeeType();
+ } else if (const PointerType *P = NewType->getAs<PointerType>()) {
+ NewType = P->getPointeeType();
+ OldType = OldType->getAs<PointerType>()->getPointeeType();
+ } else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) {
+ NewType = M->getPointeeType();
+ OldType = OldType->getAs<MemberPointerType>()->getPointeeType();
+ }
+
+ if (!NewType->isFunctionProtoType())
+ return;
+
+ // There's lots of special cases for functions. For function pointers, system
+ // libraries are hopefully not as broken so that we don't need these
+ // workarounds.
+ if (CheckEquivalentExceptionSpec(
+ OldType->getAs<FunctionProtoType>(), Old->getLocation(),
+ NewType->getAs<FunctionProtoType>(), New->getLocation())) {
+ New->setInvalidDecl();
+ }
+}
+
/// CheckCXXDefaultArguments - Verify that the default arguments for a
/// function declaration are well-formed according to C++
/// [dcl.fct.default].
@@ -520,10 +583,9 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
assert(CXXBaseDecl && "Base type is not a C++ type");
- // C++ [class.derived]p2:
- // If a class is marked with the class-virt-specifier final and it appears
- // as a base-type-specifier in a base-clause (10 class.derived), the program
- // is ill-formed.
+ // C++ [class]p3:
+ // If a class is marked final and it appears as a base-type-specifier in
+ // base-clause, the program is ill-formed.
if (CXXBaseDecl->hasAttr<FinalAttr>()) {
Diag(BaseLoc, diag::err_class_marked_final_used_as_base)
<< CXXBaseDecl->getDeclName();
@@ -876,26 +938,6 @@ void Sema::CheckOverrideControl(const Decl *D) {
<< MD->getDeclName();
return;
}
-
- // C++0x [class.derived]p8:
- // In a class definition marked with the class-virt-specifier explicit,
- // if a virtual member function that is neither implicitly-declared nor a
- // destructor overrides a member function of a base class and it is not
- // marked with the virt-specifier override, the program is ill-formed.
- if (MD->getParent()->hasAttr<ExplicitAttr>() && !isa<CXXDestructorDecl>(MD) &&
- HasOverriddenMethods && !MD->hasAttr<OverrideAttr>()) {
- llvm::SmallVector<const CXXMethodDecl*, 4>
- OverriddenMethods(MD->begin_overridden_methods(),
- MD->end_overridden_methods());
-
- Diag(MD->getLocation(), diag::err_function_overriding_without_override)
- << MD->getDeclName()
- << (unsigned)OverriddenMethods.size();
-
- for (unsigned I = 0; I != OverriddenMethods.size(); ++I)
- Diag(OverriddenMethods[I]->getLocation(),
- diag::note_overridden_virtual_function);
- }
}
/// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member
@@ -1068,6 +1110,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context));
}
+ if (VS.getLastLocation().isValid()) {
+ // Update the end location of a method that has a virt-specifiers.
+ if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Member))
+ MD->setRangeEnd(VS.getLastLocation());
+ }
+
CheckOverrideControl(Member);
assert((Name || isInstField) && "No identifier for non-field ?");
@@ -1225,10 +1273,9 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
if (!NotUnknownSpecialization) {
// When the scope specifier can refer to a member of an unknown
// specialization, we take it as a type name.
- BaseType = CheckTypenameType(ETK_None,
- (NestedNameSpecifier *)SS.getScopeRep(),
- *MemberOrBase, SourceLocation(),
- SS.getRange(), IdLoc);
+ BaseType = CheckTypenameType(ETK_None, SourceLocation(),
+ SS.getWithLocInContext(Context),
+ *MemberOrBase, IdLoc);
if (BaseType.isNull())
return true;
@@ -1356,7 +1403,7 @@ static bool InitExprContainsUninitializedFields(const Stmt *S,
*L = ME->getMemberLoc();
return true;
}
- } else if (isa<SizeOfAlignOfExpr>(S)) {
+ } else if (isa<UnaryExprOrTypeTraitExpr>(S)) {
// sizeof/alignof doesn't reference contents, do not warn.
return false;
} else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(S)) {
@@ -1476,17 +1523,61 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
MemInitResult
Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
Expr **Args, unsigned NumArgs,
+ SourceLocation NameLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc,
- CXXRecordDecl *ClassDecl,
- SourceLocation EllipsisLoc) {
+ CXXRecordDecl *ClassDecl) {
SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!LangOpts.CPlusPlus0x)
return Diag(Loc, diag::err_delegation_0x_only)
<< TInfo->getTypeLoc().getLocalSourceRange();
- return Diag(Loc, diag::err_delegation_unimplemented)
- << TInfo->getTypeLoc().getLocalSourceRange();
+ // Initialize the object.
+ InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation(
+ QualType(ClassDecl->getTypeForDecl(), 0));
+ InitializationKind Kind =
+ InitializationKind::CreateDirect(NameLoc, LParenLoc, RParenLoc);
+
+ InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs);
+
+ ExprResult DelegationInit =
+ InitSeq.Perform(*this, DelegationEntity, Kind,
+ MultiExprArg(*this, Args, NumArgs), 0);
+ if (DelegationInit.isInvalid())
+ return true;
+
+ CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get());
+ CXXConstructorDecl *Constructor = ConExpr->getConstructor();
+ assert(Constructor && "Delegating constructor with no target?");
+
+ CheckImplicitConversions(DelegationInit.get(), LParenLoc);
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ DelegationInit = MaybeCreateExprWithCleanups(DelegationInit);
+ if (DelegationInit.isInvalid())
+ return true;
+
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the base
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext()) {
+ ExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args,
+ NumArgs, RParenLoc));
+ return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc,
+ Constructor, Init.takeAs<Expr>(),
+ RParenLoc);
+ }
+
+ return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor,
+ DelegationInit.takeAs<Expr>(),
+ RParenLoc);
}
MemInitResult
@@ -1538,9 +1629,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (!Dependent) {
if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
BaseType))
- return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs,
- LParenLoc, RParenLoc, ClassDecl,
- EllipsisLoc);
+ return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, BaseLoc,
+ LParenLoc, RParenLoc, ClassDecl);
FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
VirtualBaseSpec);
@@ -1684,7 +1774,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
QualType ParamType = Param->getType().getNonReferenceType();
Expr *CopyCtorArg =
- DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
Constructor->getLocation(), ParamType,
VK_LValue, 0);
@@ -1695,9 +1785,9 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
CXXCastPath BasePath;
BasePath.push_back(BaseSpec);
- SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
- CK_UncheckedDerivedToBase,
- VK_LValue, &BasePath);
+ CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
+ CK_UncheckedDerivedToBase,
+ VK_LValue, &BasePath).take();
InitializationKind InitKind
= InitializationKind::CreateDirect(Constructor->getLocation(),
@@ -1745,7 +1835,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
QualType ParamType = Param->getType().getNonReferenceType();
Expr *MemberExprBase =
- DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
Loc, ParamType, VK_LValue, 0);
// Build a reference to this field within the parameter.
@@ -1783,7 +1873,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
IterationVarName = &SemaRef.Context.Idents.get(OS.str());
}
VarDecl *IterationVar
- = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc,
+ = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc,
IterationVarName, SizeType,
SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc),
SC_None, SC_None);
@@ -1978,6 +2068,30 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
return false;
}
+
+bool
+Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
+ CXXCtorInitializer *Initializer) {
+ Constructor->setNumCtorInitializers(1);
+ CXXCtorInitializer **initializer =
+ new (Context) CXXCtorInitializer*[1];
+ memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
+ Constructor->setCtorInitializers(initializer);
+
+ // FIXME: This doesn't catch indirect loops yet
+ CXXConstructorDecl *Target = Initializer->getTargetConstructor();
+ while (Target) {
+ if (Target == Constructor) {
+ Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop)
+ << Constructor;
+ return true;
+ }
+ Target = Target->getTargetConstructor();
+ }
+
+ return false;
+}
+
bool
Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
@@ -2340,10 +2454,23 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
if (CheckRedundantInit(*this, Init, Members[Field]) ||
CheckRedundantUnionInit(*this, Init, MemberUnions))
HadError = true;
- } else {
+ } else if (Init->isBaseInitializer()) {
void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
if (CheckRedundantInit(*this, Init, Members[Key]))
HadError = true;
+ } else {
+ assert(Init->isDelegatingInitializer());
+ // This must be the only initializer
+ if (i != 0 || NumMemInits > 1) {
+ Diag(MemInits[0]->getSourceLocation(),
+ diag::err_delegating_initializer_alone)
+ << MemInits[0]->getSourceRange();
+ HadError = true;
+ // We will treat this as being the only initializer.
+ }
+ SetDelegatingInitializer(Constructor, *MemInits);
+ // Return immediately as the initializer is set.
+ return;
}
}
@@ -2380,10 +2507,13 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
continue;
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->isInvalidDecl())
+ continue;
if (FieldClassDecl->hasTrivialDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
+ assert(Dtor && "No dtor found for FieldClassDecl!");
CheckDestructorAccess(Field->getLocation(), Dtor,
PDiag(diag::err_access_dtor_field)
<< Field->getDeclName()
@@ -2404,12 +2534,16 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
if (Base->isVirtual())
DirectVirtualBases.insert(RT);
- // Ignore trivial destructors.
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ // If our base class is invalid, we probably can't get its dtor anyway.
+ if (BaseClassDecl->isInvalidDecl())
+ continue;
+ // Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
+ assert(Dtor && "No dtor found for BaseClassDecl!");
// FIXME: caret should be on the start of the class name
CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
@@ -2431,12 +2565,16 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
if (DirectVirtualBases.count(RT))
continue;
- // Ignore trivial destructors.
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ // If our base class is invalid, we probably can't get its dtor anyway.
+ if (BaseClassDecl->isInvalidDecl())
+ continue;
+ // Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
+ assert(Dtor && "No dtor found for BaseClassDecl!");
CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
PDiag(diag::err_access_dtor_vbase)
<< VBase->getType());
@@ -2786,7 +2924,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
- DiagnoseHiddenVirtualMethods(Record, *M);
+ if (!(*M)->isStatic())
+ DiagnoseHiddenVirtualMethods(Record, *M);
}
}
@@ -2801,12 +2940,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
/// \brief Data used with FindHiddenVirtualMethod
-struct FindHiddenVirtualMethodData {
- Sema *S;
- CXXMethodDecl *Method;
- llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods;
- llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
-};
+namespace {
+ struct FindHiddenVirtualMethodData {
+ Sema *S;
+ CXXMethodDecl *Method;
+ llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods;
+ llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
+ };
+}
/// \brief Member lookup function that determines whether a given C++
/// method overloads virtual methods in a base class without overriding any,
@@ -2917,53 +3058,101 @@ namespace {
/// implicitly-declared special member functions.
class ImplicitExceptionSpecification {
ASTContext &Context;
- bool AllowsAllExceptions;
+ // We order exception specifications thus:
+ // noexcept is the most restrictive, but is only used in C++0x.
+ // throw() comes next.
+ // Then a throw(collected exceptions)
+ // Finally no specification.
+ // throw(...) is used instead if any called function uses it.
+ ExceptionSpecificationType ComputedEST;
llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
llvm::SmallVector<QualType, 4> Exceptions;
-
+
+ void ClearExceptions() {
+ ExceptionsSeen.clear();
+ Exceptions.clear();
+ }
+
public:
explicit ImplicitExceptionSpecification(ASTContext &Context)
- : Context(Context), AllowsAllExceptions(false) { }
-
- /// \brief Whether the special member function should have any
- /// exception specification at all.
- bool hasExceptionSpecification() const {
- return !AllowsAllExceptions;
+ : Context(Context), ComputedEST(EST_BasicNoexcept) {
+ if (!Context.getLangOptions().CPlusPlus0x)
+ ComputedEST = EST_DynamicNone;
}
-
- /// \brief Whether the special member function should have a
- /// throw(...) exception specification (a Microsoft extension).
- bool hasAnyExceptionSpecification() const {
- return false;
+
+ /// \brief Get the computed exception specification type.
+ ExceptionSpecificationType getExceptionSpecType() const {
+ assert(ComputedEST != EST_ComputedNoexcept &&
+ "noexcept(expr) should not be a possible result");
+ return ComputedEST;
}
-
+
/// \brief The number of exceptions in the exception specification.
unsigned size() const { return Exceptions.size(); }
-
+
/// \brief The set of exceptions in the exception specification.
const QualType *data() const { return Exceptions.data(); }
-
- /// \brief Note that
+
+ /// \brief Integrate another called method into the collected data.
void CalledDecl(CXXMethodDecl *Method) {
- // If we already know that we allow all exceptions, do nothing.
- if (AllowsAllExceptions || !Method)
+ // If we have an MSAny spec already, don't bother.
+ if (!Method || ComputedEST == EST_MSAny)
return;
-
+
const FunctionProtoType *Proto
= Method->getType()->getAs<FunctionProtoType>();
-
+
+ ExceptionSpecificationType EST = Proto->getExceptionSpecType();
+
// If this function can throw any exceptions, make a note of that.
- if (!Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec()) {
- AllowsAllExceptions = true;
- ExceptionsSeen.clear();
- Exceptions.clear();
+ if (EST == EST_MSAny || EST == EST_None) {
+ ClearExceptions();
+ ComputedEST = EST;
return;
}
-
+
+ // If this function has a basic noexcept, it doesn't affect the outcome.
+ if (EST == EST_BasicNoexcept)
+ return;
+
+ // If we have a throw-all spec at this point, ignore the function.
+ if (ComputedEST == EST_None)
+ return;
+
+ // If we're still at noexcept(true) and there's a nothrow() callee,
+ // change to that specification.
+ if (EST == EST_DynamicNone) {
+ if (ComputedEST == EST_BasicNoexcept)
+ ComputedEST = EST_DynamicNone;
+ return;
+ }
+
+ // Check out noexcept specs.
+ if (EST == EST_ComputedNoexcept) {
+ FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(Context);
+ assert(NR != FunctionProtoType::NR_NoNoexcept &&
+ "Must have noexcept result for EST_ComputedNoexcept.");
+ assert(NR != FunctionProtoType::NR_Dependent &&
+ "Should not generate implicit declarations for dependent cases, "
+ "and don't know how to handle them anyway.");
+
+ // noexcept(false) -> no spec on the new function
+ if (NR == FunctionProtoType::NR_Throw) {
+ ClearExceptions();
+ ComputedEST = EST_None;
+ }
+ // noexcept(true) won't change anything either.
+ return;
+ }
+
+ assert(EST == EST_Dynamic && "EST case not considered earlier.");
+ assert(ComputedEST != EST_None &&
+ "Shouldn't collect exceptions when throw-all is guaranteed.");
+ ComputedEST = EST_Dynamic;
// Record the exceptions in this function's exception specification.
for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
EEnd = Proto->exception_end();
- E != EEnd; ++E)
+ E != EEnd; ++E)
if (ExceptionsSeen.insert(Context.getCanonicalType(*E)))
Exceptions.push_back(*E);
}
@@ -3006,6 +3195,25 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
}
+void Sema::ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D) {
+ if (!D)
+ return;
+
+ int NumParamList = D->getNumTemplateParameterLists();
+ for (int i = 0; i < NumParamList; i++) {
+ TemplateParameterList* Params = D->getTemplateParameterList(i);
+ for (TemplateParameterList::iterator Param = Params->begin(),
+ ParamEnd = Params->end();
+ Param != ParamEnd; ++Param) {
+ NamedDecl *Named = cast<NamedDecl>(*Param);
+ if (Named->getDeclName()) {
+ S->AddDecl(Named);
+ IdResolver.AddDecl(Named);
+ }
+ }
+ }
+}
+
void Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
if (!D)
return;
@@ -3256,9 +3464,9 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
// be used as the identifier in the declarator for a destructor
// declaration.
QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName);
- if (isa<TypedefType>(DeclaratorType))
+ if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>())
Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
- << DeclaratorType;
+ << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl());
// C++ [class.dtor]p2:
// A destructor is used to destroy objects of its class type. A
@@ -3488,14 +3696,16 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
/// definition.
Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
SourceLocation InlineLoc,
+ SourceLocation NamespaceLoc,
SourceLocation IdentLoc,
IdentifierInfo *II,
SourceLocation LBrace,
AttributeList *AttrList) {
- // anonymous namespace starts at its left brace
+ SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
+ // For anonymous namespace, take the location of the left brace.
+ SourceLocation Loc = II ? IdentLoc : LBrace;
NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext,
- (II ? IdentLoc : LBrace) , II);
- Namespc->setLBracLoc(LBrace);
+ StartLoc, Loc, II);
Namespc->setInline(InlineLoc.isValid());
Scope *DeclRegionScope = NamespcScope->getParent();
@@ -3654,7 +3864,7 @@ static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) {
void Sema::ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace) {
NamespaceDecl *Namespc = dyn_cast_or_null<NamespaceDecl>(Dcl);
assert(Namespc && "Invalid parameter, expected NamespaceDecl");
- Namespc->setRBracLoc(RBrace);
+ Namespc->setRBraceLoc(RBrace);
PopDeclContext();
if (Namespc->hasAttr<VisibilityAttr>())
PopPragmaVisibility();
@@ -3677,7 +3887,7 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() {
// The "std" namespace has not yet been defined, so build one implicitly.
StdNamespace = NamespaceDecl::Create(Context,
Context.getTranslationUnitDecl(),
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("std"));
getStdNamespace()->setImplicit(true);
}
@@ -3685,6 +3895,19 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() {
return getStdNamespace();
}
+/// \brief Determine whether a using statement is in a context where it will be
+/// apply in all contexts.
+static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
+ switch (CurContext->getDeclKind()) {
+ case Decl::TranslationUnit:
+ return true;
+ case Decl::LinkageSpec:
+ return IsUsingDirectiveInToplevelContext(CurContext->getParent());
+ default:
+ return false;
+ }
+}
+
Decl *Sema::ActOnUsingDirective(Scope *S,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
@@ -3769,6 +3992,12 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, NamespcLoc,
SS.getWithLocInContext(Context),
IdentLoc, Named, CommonAncestor);
+
+ if (IsUsingDirectiveInToplevelContext(CurContext) &&
+ !SourceMgr.isFromMainFile(SourceMgr.getInstantiationLoc(IdentLoc))) {
+ Diag(IdentLoc, diag::warn_using_directive_in_header);
+ }
+
PushUsingDirective(S, UDir);
} else {
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
@@ -3870,8 +4099,8 @@ IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2,
return true;
}
- if (TypedefDecl *TD1 = dyn_cast<TypedefDecl>(D1))
- if (TypedefDecl *TD2 = dyn_cast<TypedefDecl>(D2)) {
+ if (TypedefNameDecl *TD1 = dyn_cast<TypedefNameDecl>(D1))
+ if (TypedefNameDecl *TD2 = dyn_cast<TypedefNameDecl>(D2)) {
SuppressRedeclaration = true;
return Context.hasSameType(TD1->getUnderlyingType(),
TD2->getUnderlyingType());
@@ -4470,6 +4699,61 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
return true;
}
+Decl *Sema::ActOnAliasDeclaration(Scope *S,
+ AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ UnqualifiedId &Name,
+ TypeResult Type) {
+ assert((S->getFlags() & Scope::DeclScope) &&
+ "got alias-declaration outside of declaration scope");
+
+ if (Type.isInvalid())
+ return 0;
+
+ bool Invalid = false;
+ DeclarationNameInfo NameInfo = GetNameFromUnqualifiedId(Name);
+ TypeSourceInfo *TInfo = 0;
+ GetTypeFromParser(Type.get(), &TInfo);
+
+ if (DiagnoseClassNameShadow(CurContext, NameInfo))
+ return 0;
+
+ if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
+ UPPC_DeclarationType))
+ Invalid = true;
+
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
+ LookupName(Previous, S);
+
+ // Warn about shadowing the name of a template parameter.
+ if (Previous.isSingleResult() &&
+ Previous.getFoundDecl()->isTemplateParameter()) {
+ if (DiagnoseTemplateParameterShadow(Name.StartLocation,
+ Previous.getFoundDecl()))
+ Invalid = true;
+ Previous.clear();
+ }
+
+ assert(Name.Kind == UnqualifiedId::IK_Identifier &&
+ "name in alias declaration must be an identifier");
+ TypeAliasDecl *NewTD = TypeAliasDecl::Create(Context, CurContext, UsingLoc,
+ Name.StartLocation,
+ Name.Identifier, TInfo);
+
+ NewTD->setAccess(AS);
+
+ if (Invalid)
+ NewTD->setInvalidDecl();
+
+ bool Redeclaration = false;
+ ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
+
+ if (!Redeclaration)
+ PushOnScopeChains(NewTD, S);
+
+ return NewTD;
+}
+
Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
@@ -4609,7 +4893,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// exception-specification. [...]
ImplicitExceptionSpecification ExceptSpec(Context);
- // Direct base-class destructors.
+ // Direct base-class constructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
BEnd = ClassDecl->bases_end();
B != BEnd; ++B) {
@@ -4625,8 +4909,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
ExceptSpec.CalledDecl(Constructor);
}
}
-
- // Virtual base-class destructors.
+
+ // Virtual base-class constructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
BEnd = ClassDecl->vbases_end();
B != BEnd; ++B) {
@@ -4639,8 +4923,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
ExceptSpec.CalledDecl(Constructor);
}
}
-
- // Field destructors.
+
+ // Field constructors.
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
@@ -4657,19 +4941,19 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
}
FunctionProtoType::ExtProtoInfo EPI;
- EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification();
- EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification();
+ EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
EPI.NumExceptions = ExceptSpec.size();
EPI.Exceptions = ExceptSpec.data();
-
+
// Create the actual constructor declaration.
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
+ SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(ClassType);
- DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation());
+ DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXConstructorDecl *DefaultCon
- = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo,
+ = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
Context.getFunctionType(Context.VoidTy,
0, 0, EPI),
/*TInfo=*/0,
@@ -4714,6 +4998,10 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
Constructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(Constructor);
+ }
}
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
@@ -4865,15 +5153,16 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// user-writtern inline constructor [...]
DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
- Context, ClassDecl, DNI, QualType(NewCtorType, 0), /*TInfo=*/0,
- BaseCtor->isExplicit(), /*Inline=*/true,
+ Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0),
+ /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true,
/*ImplicitlyDeclared=*/true);
NewCtor->setAccess(BaseCtor->getAccess());
// Build up the parameter decls and add them.
llvm::SmallVector<ParmVarDecl *, 16> ParamDecls;
for (unsigned i = 0; i < params; ++i) {
- ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc,
+ ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor,
+ UsingLoc, UsingLoc,
/*IdentifierInfo=*/0,
BaseCtorType->getArgType(i),
/*TInfo=*/0, SC_None,
@@ -4931,24 +5220,24 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
ExceptSpec.CalledDecl(
LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
}
-
+
// Create the actual destructor declaration.
FunctionProtoType::ExtProtoInfo EPI;
- EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification();
- EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification();
+ EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
EPI.NumExceptions = ExceptSpec.size();
EPI.Exceptions = ExceptSpec.data();
QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
-
+
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
+ SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
- DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation());
+ DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXDestructorDecl *Destructor
- = CXXDestructorDecl::Create(Context, ClassDecl, NameInfo, Ty, 0,
- /*isInline=*/true,
- /*isImplicitlyDeclared=*/true);
+ = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0,
+ /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
@@ -4998,6 +5287,10 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
Destructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(Destructor);
+ }
}
/// \brief Builds a statement that copies the given entity from \p From to
@@ -5133,7 +5426,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
OS << "__i" << Depth;
IterationVarName = &S.Context.Idents.get(OS.str());
}
- VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc,
+ VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
IterationVarName, SizeType,
S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
SC_None, SC_None);
@@ -5328,30 +5621,30 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
ExceptSpec.CalledDecl(CopyAssign);
}
}
-
+
// An implicitly-declared copy assignment operator is an inline public
// member of its class.
FunctionProtoType::ExtProtoInfo EPI;
- EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification();
- EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification();
+ EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
EPI.NumExceptions = ExceptSpec.size();
EPI.Exceptions = ExceptSpec.data();
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation());
+ SourceLocation ClassLoc = ClassDecl->getLocation();
+ DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *CopyAssignment
- = CXXMethodDecl::Create(Context, ClassDecl, NameInfo,
+ = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
Context.getFunctionType(RetType, &ArgType, 1, EPI),
/*TInfo=*/0, /*isStatic=*/false,
/*StorageClassAsWritten=*/SC_None,
- /*isInline=*/true);
+ /*isInline=*/true,
+ SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
- ClassDecl->getLocation(),
- /*Id=*/0,
+ ClassLoc, ClassLoc, /*Id=*/0,
ArgType, /*TInfo=*/0,
SC_None,
SC_None, 0);
@@ -5440,21 +5733,19 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Construct the "from" expression, which is an implicit cast to the
// appropriately-qualified base type.
Expr *From = OtherRef;
- ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals),
- CK_UncheckedDerivedToBase,
- VK_LValue, &BasePath);
+ From = ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals),
+ CK_UncheckedDerivedToBase,
+ VK_LValue, &BasePath).take();
// Dereference "this".
ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
// Implicitly cast "this" to the appropriately-qualified base type.
- Expr *ToE = To.takeAs<Expr>();
- ImpCastExprToType(ToE,
- Context.getCVRQualifiedType(BaseType,
- CopyAssignOperator->getTypeQualifiers()),
- CK_UncheckedDerivedToBase,
- VK_LValue, &BasePath);
- To = Owned(ToE);
+ To = ImpCastExprToType(To.take(),
+ Context.getCVRQualifiedType(BaseType,
+ CopyAssignOperator->getTypeQualifiers()),
+ CK_UncheckedDerivedToBase,
+ VK_LValue, &BasePath);
// Build the copy.
StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType,
@@ -5659,6 +5950,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
CopyAssignOperator->setBody(Body.takeAs<Stmt>());
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(CopyAssignOperator);
+ }
}
CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
@@ -5790,20 +6085,20 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
ExceptSpec.CalledDecl(CopyConstructor);
}
}
-
+
// An implicitly-declared copy constructor is an inline public
// member of its class.
FunctionProtoType::ExtProtoInfo EPI;
- EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification();
- EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification();
+ EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
EPI.NumExceptions = ExceptSpec.size();
EPI.Exceptions = ExceptSpec.data();
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType));
- DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation());
+ SourceLocation ClassLoc = ClassDecl->getLocation();
+ DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXConstructorDecl *CopyConstructor
- = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo,
+ = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
Context.getFunctionType(Context.VoidTy,
&ArgType, 1, EPI),
/*TInfo=*/0,
@@ -5818,7 +6113,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
- ClassDecl->getLocation(),
+ ClassLoc, ClassLoc,
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
SC_None,
@@ -5859,6 +6154,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
CopyConstructor->setUsed();
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(CopyConstructor);
+ }
}
ExprResult
@@ -5903,6 +6202,13 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
+ for (specific_attr_iterator<NonNullAttr>
+ i = Constructor->specific_attr_begin<NonNullAttr>(),
+ e = Constructor->specific_attr_end<NonNullAttr>(); i != e; ++i) {
+ const NonNullAttr *NonNull = *i;
+ CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc);
+ }
+
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
@@ -5932,20 +6238,29 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
}
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
+ if (VD->isInvalidDecl()) return;
+
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
- if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() &&
- !ClassDecl->hasTrivialDestructor() && !ClassDecl->isDependentContext()) {
- CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
- MarkDeclarationReferenced(VD->getLocation(), Destructor);
- CheckDestructorAccess(VD->getLocation(), Destructor,
- PDiag(diag::err_access_dtor_var)
- << VD->getDeclName()
- << VD->getType());
+ if (ClassDecl->isInvalidDecl()) return;
+ if (ClassDecl->hasTrivialDestructor()) return;
+ if (ClassDecl->isDependentContext()) return;
- // TODO: this should be re-enabled for static locals by !CXAAtExit
- if (!VD->isInvalidDecl() && VD->hasGlobalStorage() && !VD->isStaticLocal())
- Diag(VD->getLocation(), diag::warn_global_destructor);
- }
+ CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
+ MarkDeclarationReferenced(VD->getLocation(), Destructor);
+ CheckDestructorAccess(VD->getLocation(), Destructor,
+ PDiag(diag::err_access_dtor_var)
+ << VD->getDeclName()
+ << VD->getType());
+
+ if (!VD->hasGlobalStorage()) return;
+
+ // Emit warning for non-trivial dtor in global scope (a real global,
+ // class-static, function-static).
+ Diag(VD->getLocation(), diag::warn_exit_time_destructor);
+
+ // TODO: this should be re-enabled for static locals by !CXAAtExit
+ if (!VD->isStaticLocal())
+ Diag(VD->getLocation(), diag::warn_global_destructor);
}
/// AddCXXDirectInitializerToDecl - This action is called immediately after
@@ -5983,15 +6298,17 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
}
Expr *Init = Exprs.get()[0];
- QualType DeducedType;
- if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) {
+ TypeSourceInfo *DeducedType = 0;
+ if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
<< Init->getSourceRange();
+ if (!DeducedType) {
RealDecl->setInvalidDecl();
return;
}
- VDecl->setType(DeducedType);
+ VDecl->setTypeSourceInfo(DeducedType);
+ VDecl->setType(DeducedType->getType());
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
@@ -6523,8 +6840,7 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
// FIXME: Add all the various semantics of linkage specifications
LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext,
- LangLoc, Language,
- LBraceLoc.isValid());
+ ExternLoc, LangLoc, Language);
CurContext->addDecl(D);
PushDeclContext(S, D);
return D;
@@ -6535,20 +6851,26 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
/// valid, it's the position of the closing '}' brace in a linkage
/// specification that uses braces.
Decl *Sema::ActOnFinishLinkageSpecification(Scope *S,
- Decl *LinkageSpec,
- SourceLocation RBraceLoc) {
- if (LinkageSpec)
+ Decl *LinkageSpec,
+ SourceLocation RBraceLoc) {
+ if (LinkageSpec) {
+ if (RBraceLoc.isValid()) {
+ LinkageSpecDecl* LSDecl = cast<LinkageSpecDecl>(LinkageSpec);
+ LSDecl->setRBraceLoc(RBraceLoc);
+ }
PopDeclContext();
+ }
return LinkageSpec;
}
/// \brief Perform semantic analysis for the variable declaration that
/// occurs within a C++ catch clause, returning the newly-created
/// variable.
-VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
+VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
TypeSourceInfo *TInfo,
- IdentifierInfo *Name,
- SourceLocation Loc) {
+ SourceLocation StartLoc,
+ SourceLocation Loc,
+ IdentifierInfo *Name) {
bool Invalid = false;
QualType ExDeclType = TInfo->getType();
@@ -6608,19 +6930,15 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Diag(Loc, diag::err_objc_object_catch);
Invalid = true;
} else if (T->isObjCObjectPointerType()) {
- if (!getLangOptions().NeXTRuntime) {
- Diag(Loc, diag::err_objc_pointer_cxx_catch_gnu);
- Invalid = true;
- } else if (!getLangOptions().ObjCNonFragileABI) {
+ if (!getLangOptions().ObjCNonFragileABI) {
Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile);
Invalid = true;
}
}
}
- VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, TInfo, SC_None,
- SC_None);
+ VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name,
+ ExDeclType, TInfo, SC_None, SC_None);
ExDecl->setExceptionVariable(true);
if (!Invalid) {
@@ -6703,9 +7021,9 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
}
VarDecl *ExDecl = BuildExceptionDeclaration(S, TInfo,
- D.getIdentifier(),
- D.getIdentifierLoc());
-
+ D.getSourceRange().getBegin(),
+ D.getIdentifierLoc(),
+ D.getIdentifier());
if (Invalid)
ExDecl->setInvalidDecl();
@@ -6719,21 +7037,23 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
return ExDecl;
}
-Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
- Expr *AssertMessageExpr_) {
+ Expr *AssertMessageExpr_,
+ SourceLocation RParenLoc) {
StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_);
if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
llvm::APSInt Value(32);
if (!AssertExpr->isIntegerConstantExpr(Value, Context)) {
- Diag(AssertLoc, diag::err_static_assert_expression_is_not_constant) <<
+ Diag(StaticAssertLoc,
+ diag::err_static_assert_expression_is_not_constant) <<
AssertExpr->getSourceRange();
return 0;
}
if (Value == 0) {
- Diag(AssertLoc, diag::err_static_assert_failed)
+ Diag(StaticAssertLoc, diag::err_static_assert_failed)
<< AssertMessage->getString() << AssertExpr->getSourceRange();
}
}
@@ -6741,8 +7061,8 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
return 0;
- Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc,
- AssertExpr, AssertMessage);
+ Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
+ AssertExpr, AssertMessage, RParenLoc);
CurContext->addDecl(Decl);
return Decl;
@@ -6815,7 +7135,6 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
bool isExplicitSpecialization = false;
- unsigned NumMatchedTemplateParamLists = TempParamLists.size();
bool Invalid = false;
if (TemplateParameterList *TemplateParams
@@ -6825,16 +7144,16 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/*friend*/ true,
isExplicitSpecialization,
Invalid)) {
- --NumMatchedTemplateParamLists;
-
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
if (Invalid)
return 0;
-
+
return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc,
SS, Name, NameLoc, Attr,
- TemplateParams, AS_public).take();
+ TemplateParams, AS_public,
+ TempParamLists.size() - 1,
+ (TemplateParameterList**) TempParamLists.release()).take();
} else {
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
@@ -6848,7 +7167,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?");
bool isAllExplicitSpecializations = true;
- for (unsigned I = 0; I != NumMatchedTemplateParamLists; ++I) {
+ for (unsigned I = TempParamLists.size(); I-- > 0; ) {
if (TempParamLists.get()[I]->size()) {
isAllExplicitSpecializations = false;
break;
@@ -6861,10 +7180,11 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
// about the template header and build an appropriate non-templated
// friend. TODO: for source fidelity, remember the headers.
if (isAllExplicitSpecializations) {
+ NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
ElaboratedTypeKeyword Keyword
= TypeWithKeyword::getKeywordForTagTypeKind(Kind);
- QualType T = CheckTypenameType(Keyword, SS.getScopeRep(), *Name,
- TagLoc, SS.getRange(), NameLoc);
+ QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc,
+ *Name, NameLoc);
if (T.isNull())
return 0;
@@ -6872,12 +7192,12 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (isa<DependentNameType>(T)) {
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
TL.setKeywordLoc(TagLoc);
- TL.setQualifierRange(SS.getRange());
+ TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(NameLoc);
} else {
ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
TL.setKeywordLoc(TagLoc);
- TL.setQualifierRange(SS.getRange());
+ TL.setQualifierLoc(QualifierLoc);
cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(NameLoc);
}
@@ -6896,7 +7216,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
TL.setKeywordLoc(TagLoc);
- TL.setQualifierRange(SS.getRange());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
TL.setNameLoc(NameLoc);
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc,
@@ -7359,10 +7679,14 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
///
/// \param InitRange the source range that covers the "0" initializer.
bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
+ SourceLocation EndLoc = InitRange.getEnd();
+ if (EndLoc.isValid())
+ Method->setRangeEnd(EndLoc);
+
if (Method->isVirtual() || Method->getParent()->isDependentContext()) {
Method->setPure();
return false;
- }
+ }
if (!Method->isInvalidDecl())
Diag(Method->getLocation(), diag::err_non_virtual_pure)
@@ -7379,7 +7703,7 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
/// class X.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
- if (D == 0) return;
+ if (D == 0 || D->isInvalidDecl()) return;
// We should only get called for declarations with scope specifiers, like:
// int foo::bar;
@@ -7391,7 +7715,7 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
/// initializer for the out-of-line declaration 'D'.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
- if (D == 0) return;
+ if (D == 0 || D->isInvalidDecl()) return;
assert(D->isOutOfLine());
ExitDeclaratorContext(S);
@@ -7472,6 +7796,7 @@ bool Sema::DefineUsedVTables() {
// the members of a class as "used", so we check the size each
// time through the loop and prefer indices (with are stable) to
// iterators (which are not).
+ bool DefinedAnything = false;
for (unsigned I = 0; I != VTableUses.size(); ++I) {
CXXRecordDecl *Class = VTableUses[I].first->getDefinition();
if (!Class)
@@ -7524,6 +7849,7 @@ bool Sema::DefineUsedVTables() {
// Mark all of the virtual members of this class as referenced, so
// that we can build a vtable. Then, tell the AST consumer that a
// vtable for this class is required.
+ DefinedAnything = true;
MarkVirtualMembersReferenced(Loc, Class);
CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl());
Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
@@ -7537,7 +7863,7 @@ bool Sema::DefineUsedVTables() {
}
VTableUses.clear();
- return true;
+ return DefinedAnything;
}
void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 652318f7204e..7b235bab5d9a 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -28,7 +28,7 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S,
NamedDecl *ND,
SourceLocation ImplLoc,
int select) {
- if (ND && ND->getAttr<DeprecatedAttr>()) {
+ if (ND && ND->isDeprecated()) {
S.Diag(ImplLoc, diag::warn_deprecated_def) << select;
if (select == 0)
S.Diag(ND->getLocation(), diag::note_method_declared_at);
@@ -174,7 +174,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (PrevDecl && SuperClassDecl == 0) {
// The previous declaration was not a class decl. Check if we have a
// typedef. If we do, get the underlying class type.
- if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
+ if (const TypedefNameDecl *TDecl =
+ dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface())
@@ -193,7 +194,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
}
}
- if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
+ if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
if (!SuperClassDecl)
Diag(SuperLoc, diag::err_undef_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
@@ -242,7 +243,8 @@ Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
// Check for class declaration
NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
LookupOrdinaryName, ForRedeclaration);
- if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) {
+ if (const TypedefNameDecl *TDecl =
+ dyn_cast_or_null<TypedefNameDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
@@ -1242,7 +1244,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// @class XCElementToggler;
//
// FIXME: Make an extension?
- TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl);
+ TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(PrevDecl);
if (!TDD || !TDD->getUnderlyingType()->isObjCObjectType()) {
Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i];
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
@@ -1369,15 +1371,14 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
PrevObjCMethod->setDefined(impl);
// If a method is deprecated, push it in the global pool.
// This is used for better diagnostics.
- if (Method->getAttr<DeprecatedAttr>()) {
- if (!PrevObjCMethod->getAttr<DeprecatedAttr>())
+ if (Method->isDeprecated()) {
+ if (!PrevObjCMethod->isDeprecated())
List->Method = Method;
}
// If new method is unavailable, push it into global pool
// unless previous one is deprecated.
- if (Method->getAttr<UnavailableAttr>()) {
- if (!PrevObjCMethod->getAttr<UnavailableAttr>() &&
- !PrevObjCMethod->getAttr<DeprecatedAttr>())
+ if (Method->isUnavailable()) {
+ if (PrevObjCMethod->getAvailability() < AR_Deprecated)
List->Method = Method;
}
return;
@@ -1475,7 +1476,7 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl,
assert(PrevI != SuperMethodDecl->param_end() && "Param mismatch");
QualType T1 = Context.getCanonicalType((*ParamI)->getType());
QualType T2 = Context.getCanonicalType((*PrevI)->getType());
- // If type of arguement of method in this class does not match its
+ // If type of argument of method in this class does not match its
// respective argument type in the super class method, issue warning;
if (!Context.typesAreCompatible(T1, T2)) {
Diag((*ParamI)->getLocation(), diag::ext_typecheck_base_super)
@@ -1535,7 +1536,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
SourceLocation L = ClassDecl->getLocation();
AtEnd.setBegin(L);
AtEnd.setEnd(L);
- Diag(L, diag::warn_missing_atend);
+ Diag(L, diag::err_missing_atend);
}
// FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
@@ -1697,21 +1698,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
/// objective-c's type qualifier from the parser version of the same info.
static Decl::ObjCDeclQualifier
CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
- Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None;
- if (PQTVal & ObjCDeclSpec::DQ_In)
- ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_In);
- if (PQTVal & ObjCDeclSpec::DQ_Inout)
- ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Inout);
- if (PQTVal & ObjCDeclSpec::DQ_Out)
- ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Out);
- if (PQTVal & ObjCDeclSpec::DQ_Bycopy)
- ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy);
- if (PQTVal & ObjCDeclSpec::DQ_Byref)
- ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Byref);
- if (PQTVal & ObjCDeclSpec::DQ_Oneway)
- ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Oneway);
-
- return ret;
+ return (Decl::ObjCDeclQualifier) (unsigned) PQTVal;
}
static inline
@@ -1736,7 +1723,7 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCArgInfo *ArgInfo,
DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args
AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind,
- bool isVariadic) {
+ bool isVariadic, bool MethodDefinition) {
// Make sure we can establish a context for the method.
if (!ClassDecl) {
Diag(MethodLoc, diag::error_missing_method_context);
@@ -1789,25 +1776,24 @@ Decl *Sema::ActOnMethodDeclaration(
if (R.isSingleResult()) {
NamedDecl *PrevDecl = R.getFoundDecl();
if (S->isDeclScope(PrevDecl)) {
- // FIXME. This should be an error; but will break projects.
- Diag(ArgInfo[i].NameLoc, diag::warn_method_param_redefinition)
+ Diag(ArgInfo[i].NameLoc,
+ (MethodDefinition ? diag::warn_method_param_redefinition
+ : diag::warn_method_param_declaration))
<< ArgInfo[i].Name;
Diag(PrevDecl->getLocation(),
diag::note_previous_declaration);
}
}
- ParmVarDecl* Param
- = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc,
- ArgInfo[i].Name, ArgType, DI,
- SC_None, SC_None, 0);
+ SourceLocation StartLoc = DI
+ ? DI->getTypeLoc().getBeginLoc()
+ : ArgInfo[i].NameLoc;
- if (ArgType->isObjCObjectType()) {
- Diag(ArgInfo[i].NameLoc,
- diag::err_object_cannot_be_passed_returned_by_value)
- << 1 << ArgType;
- Param->setInvalidDecl();
- }
+ ParmVarDecl* Param = CheckParameter(ObjCMethod, StartLoc,
+ ArgInfo[i].NameLoc, ArgInfo[i].Name,
+ ArgType, DI, SC_None, SC_None);
+
+ Param->setObjCMethodScopeInfo(i);
Param->setObjCDeclQualifier(
CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier()));
@@ -1888,16 +1874,9 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
}
- // If the interface declared this method, and it was deprecated there,
- // mark it deprecated here.
+ // Merge information down from the interface declaration if we have one.
if (InterfaceMD)
- if (Attr *DA = InterfaceMD->getAttr<DeprecatedAttr>()) {
- StringLiteral *SE = StringLiteral::CreateEmpty(Context, 1);
- ObjCMethod->addAttr(::new (Context)
- DeprecatedAttr(DA->getLocation(),
- Context,
- SE->getString()));
- }
+ mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
return ObjCMethod;
}
@@ -1935,7 +1914,9 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
for (unsigned i = 0; i < Ivars.size(); i++) {
FieldDecl* ID = cast<FieldDecl>(Ivars[i]);
RecordDecl *Record = dyn_cast<RecordDecl>(TagD);
- Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, ID->getLocation(),
+ Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record,
+ /*FIXME: StartL=*/ID->getLocation(),
+ ID->getLocation(),
ID->getIdentifier(), ID->getType(),
ID->getBitWidth());
Decls.push_back(FD);
@@ -1953,17 +1934,17 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
}
/// \brief Build a type-check a new Objective-C exception variable declaration.
-VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo,
- QualType T,
- IdentifierInfo *Name,
- SourceLocation NameLoc,
+VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id,
bool Invalid) {
// ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
if (T.getAddressSpace() != 0) {
- Diag(NameLoc, diag::err_arg_with_address_space);
+ Diag(IdLoc, diag::err_arg_with_address_space);
Invalid = true;
}
@@ -1975,14 +1956,14 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo,
// Okay: we don't know what this type will instantiate to.
} else if (!T->isObjCObjectPointerType()) {
Invalid = true;
- Diag(NameLoc ,diag::err_catch_param_not_objc_type);
+ Diag(IdLoc ,diag::err_catch_param_not_objc_type);
} else if (T->isObjCQualifiedIdType()) {
Invalid = true;
- Diag(NameLoc, diag::err_illegal_qualifiers_on_catch_parm);
+ Diag(IdLoc, diag::err_illegal_qualifiers_on_catch_parm);
}
- VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo,
- SC_None, SC_None);
+ VarDecl *New = VarDecl::Create(Context, CurContext, StartLoc, IdLoc, Id,
+ T, TInfo, SC_None, SC_None);
New->setExceptionVariable(true);
if (Invalid)
@@ -2023,8 +2004,10 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
<< Context.getTypeDeclType(OwnedDecl);
}
- VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, D.getIdentifier(),
- D.getIdentifierLoc(),
+ VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType,
+ D.getSourceRange().getBegin(),
+ D.getIdentifierLoc(),
+ D.getIdentifier(),
D.isInvalidType());
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 5d7993b1afba..f1033dc8c2ff 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -96,16 +96,24 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
}
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+ OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
+ bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
bool MissingExceptionSpecification = false;
bool MissingEmptyExceptionSpecification = false;
- if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec),
+ unsigned DiagID = diag::err_mismatched_exception_spec;
+ if (getLangOptions().Microsoft)
+ 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))
+ &MissingEmptyExceptionSpecification,
+ /*AllowNoexceptAllMatchWithNoSpec=*/true,
+ IsOperatorNew))
return false;
// The failure was something other than an empty exception
@@ -129,9 +137,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
Old->isExternC()) {
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
- EPI.HasExceptionSpec = true;
- EPI.HasAnyExceptionSpec = false;
- EPI.NumExceptions = 0;
+ EPI.ExceptionSpecType = EST_DynamicNone;
QualType NewType = Context.getFunctionType(NewProto->getResultType(),
NewProto->arg_type_begin(),
NewProto->getNumArgs(),
@@ -145,10 +151,14 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
= Old->getType()->getAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
- EPI.HasExceptionSpec = OldProto->hasExceptionSpec();
- EPI.HasAnyExceptionSpec = OldProto->hasAnyExceptionSpec();
- EPI.NumExceptions = OldProto->getNumExceptions();
- EPI.Exceptions = OldProto->exception_begin();
+ EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
+ if (EPI.ExceptionSpecType == EST_Dynamic) {
+ EPI.NumExceptions = OldProto->getNumExceptions();
+ EPI.Exceptions = OldProto->exception_begin();
+ } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+ // FIXME: We can't just take the expression from the old prototype. It
+ // likely contains references to the old prototype's parameters.
+ }
// Update the type of the function with the appropriate exception
// specification.
@@ -160,7 +170,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// If exceptions are disabled, suppress the warning about missing
// exception specifications for new and delete operators.
- if (!getLangOptions().Exceptions) {
+ if (!getLangOptions().CXXExceptions) {
switch (New->getDeclName().getCXXOverloadedOperator()) {
case OO_New:
case OO_Array_New:
@@ -178,30 +188,53 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// Warn about the lack of exception specification.
llvm::SmallString<128> ExceptionSpecString;
llvm::raw_svector_ostream OS(ExceptionSpecString);
- OS << "throw(";
- bool OnFirstException = true;
- for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
- EEnd = OldProto->exception_end();
- E != EEnd;
- ++E) {
- if (OnFirstException)
- OnFirstException = false;
- else
- OS << ", ";
-
- OS << E->getAsString(Context.PrintingPolicy);
+ switch (OldProto->getExceptionSpecType()) {
+ case EST_DynamicNone:
+ OS << "throw()";
+ break;
+
+ case EST_Dynamic: {
+ OS << "throw(";
+ bool OnFirstException = true;
+ for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
+ EEnd = OldProto->exception_end();
+ E != EEnd;
+ ++E) {
+ if (OnFirstException)
+ OnFirstException = false;
+ else
+ OS << ", ";
+
+ OS << E->getAsString(Context.PrintingPolicy);
+ }
+ OS << ")";
+ break;
+ }
+
+ case EST_BasicNoexcept:
+ OS << "noexcept";
+ break;
+
+ case EST_ComputedNoexcept:
+ OS << "noexcept(";
+ OldProto->getNoexceptExpr()->printPretty(OS, Context, 0,
+ Context.PrintingPolicy);
+ OS << ")";
+ break;
+
+ default:
+ assert(false && "This spec type is compatible with none.");
}
- OS << ")";
OS.flush();
- SourceLocation AfterParenLoc;
+ SourceLocation FixItLoc;
if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL))
- AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc());
+ FixItLoc = PP.getLocForEndOfToken(FTLoc->getLocalRangeEnd());
}
- if (AfterParenLoc.isInvalid())
+ if (FixItLoc.isInvalid())
Diag(New->getLocation(), diag::warn_missing_exception_specification)
<< New << OS.str();
else {
@@ -209,7 +242,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// late-specified return types.
Diag(New->getLocation(), diag::warn_missing_exception_specification)
<< New << OS.str()
- << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str());
+ << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());
}
if (!Old->getLocation().isInvalid())
@@ -218,7 +251,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
return false;
}
- Diag(New->getLocation(), diag::err_mismatched_exception_spec);
+ Diag(New->getLocation(), DiagID);
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
}
@@ -230,26 +263,29 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
bool Sema::CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc) {
+ unsigned DiagID = diag::err_mismatched_exception_spec;
+ if (getLangOptions().Microsoft)
+ DiagID = diag::warn_mismatched_exception_spec;
return CheckEquivalentExceptionSpec(
- PDiag(diag::err_mismatched_exception_spec),
+ PDiag(DiagID),
PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
}
-/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
-/// exception specifications. Exception specifications are equivalent if
-/// they allow exactly the same set of exception types. It does not matter how
-/// that is achieved. See C++ [except.spec]p2.
-bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
+/// CheckEquivalentExceptionSpec - Check if the two types have compatible
+/// exception specifications. See C++ [except.spec]p3.
+bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
const PartialDiagnostic & NoteID,
- const FunctionProtoType *Old,
+ const FunctionProtoType *Old,
SourceLocation OldLoc,
- const FunctionProtoType *New,
+ const FunctionProtoType *New,
SourceLocation NewLoc,
bool *MissingExceptionSpecification,
- bool *MissingEmptyExceptionSpecification) {
+ bool*MissingEmptyExceptionSpecification,
+ bool AllowNoexceptAllMatchWithNoSpec,
+ bool IsOperatorNew) {
// Just completely ignore this under -fno-exceptions.
- if (!getLangOptions().Exceptions)
+ if (!getLangOptions().CXXExceptions)
return false;
if (MissingExceptionSpecification)
@@ -258,29 +294,133 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
if (MissingEmptyExceptionSpecification)
*MissingEmptyExceptionSpecification = false;
- bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
- bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
- if (getLangOptions().Microsoft) {
- // Treat throw(whatever) as throw(...) to be compatible with MS headers.
- if (New->hasExceptionSpec() && New->getNumExceptions() > 0)
- NewAny = true;
- if (Old->hasExceptionSpec() && Old->getNumExceptions() > 0)
- OldAny = true;
+ // C++0x [except.spec]p3: Two exception-specifications are compatible if:
+ // - both are non-throwing, regardless of their form,
+ // - both have the form noexcept(constant-expression) and the constant-
+ // expressions are equivalent,
+ // - one exception-specification is a noexcept-specification allowing all
+ // exceptions and the other is of the form throw(type-id-list), or
+ // - both are dynamic-exception-specifications that have the same set of
+ // adjusted types.
+ //
+ // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is
+ // of the form throw(), noexcept, or noexcept(constant-expression) where the
+ // constant-expression yields true.
+ //
+ // CWG 1073 Proposed resolution: Strike the third bullet above.
+ //
+ // C++0x [except.spec]p4: If any declaration of a function has an exception-
+ // specifier that is not a noexcept-specification allowing all exceptions,
+ // all declarations [...] of that function shall have a compatible
+ // exception-specification.
+ //
+ // That last point basically means that noexcept(false) matches no spec.
+ // It's considered when AllowNoexceptAllMatchWithNoSpec is true.
+
+ ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
+ ExceptionSpecificationType NewEST = New->getExceptionSpecType();
+
+ // Shortcut the case where both have no spec.
+ if (OldEST == EST_None && NewEST == EST_None)
+ return false;
+
+ FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context);
+ FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context);
+ if (OldNR == FunctionProtoType::NR_BadNoexcept ||
+ NewNR == FunctionProtoType::NR_BadNoexcept)
+ return false;
+
+ // Dependent noexcept specifiers are compatible with each other, but nothing
+ // else.
+ // One noexcept is compatible with another if the argument is the same
+ if (OldNR == NewNR &&
+ OldNR != FunctionProtoType::NR_NoNoexcept &&
+ NewNR != FunctionProtoType::NR_NoNoexcept)
+ return false;
+ if (OldNR != NewNR &&
+ OldNR != FunctionProtoType::NR_NoNoexcept &&
+ NewNR != FunctionProtoType::NR_NoNoexcept) {
+ Diag(NewLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(OldLoc, NoteID);
+ return true;
+ }
+
+ // The MS extension throw(...) is compatible with itself.
+ if (OldEST == EST_MSAny && NewEST == EST_MSAny)
+ return false;
+
+ // It's also compatible with no spec.
+ if ((OldEST == EST_None && NewEST == EST_MSAny) ||
+ (OldEST == EST_MSAny && NewEST == EST_None))
+ return false;
+
+ // It's also compatible with noexcept(false).
+ if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw)
+ return false;
+ if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw)
+ return false;
+
+ // As described above, noexcept(false) matches no spec only for functions.
+ if (AllowNoexceptAllMatchWithNoSpec) {
+ if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw)
+ return false;
+ if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw)
+ return false;
}
- if (OldAny && NewAny)
+ // Any non-throwing specifications are compatible.
+ bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow ||
+ OldEST == EST_DynamicNone;
+ bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow ||
+ NewEST == EST_DynamicNone;
+ if (OldNonThrowing && NewNonThrowing)
return false;
- if (OldAny || NewAny) {
+
+ // As a special compatibility feature, under C++0x we accept no spec and
+ // throw(std::bad_alloc) as equivalent for operator new and operator new[].
+ // This is because the implicit declaration changed, but old code would break.
+ if (getLangOptions().CPlusPlus0x && IsOperatorNew) {
+ const FunctionProtoType *WithExceptions = 0;
+ if (OldEST == EST_None && NewEST == EST_Dynamic)
+ WithExceptions = New;
+ else if (OldEST == EST_Dynamic && NewEST == EST_None)
+ WithExceptions = Old;
+ if (WithExceptions && WithExceptions->getNumExceptions() == 1) {
+ // One has no spec, the other throw(something). If that something is
+ // std::bad_alloc, all conditions are met.
+ QualType Exception = *WithExceptions->exception_begin();
+ if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {
+ IdentifierInfo* Name = ExRecord->getIdentifier();
+ if (Name && Name->getName() == "bad_alloc") {
+ // It's called bad_alloc, but is it in std?
+ DeclContext* DC = ExRecord->getDeclContext();
+ DC = DC->getEnclosingNamespaceContext();
+ if (NamespaceDecl* NS = dyn_cast<NamespaceDecl>(DC)) {
+ IdentifierInfo* NSName = NS->getIdentifier();
+ DC = DC->getParent();
+ if (NSName && NSName->getName() == "std" &&
+ DC->getEnclosingNamespaceContext()->isTranslationUnit()) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // At this point, the only remaining valid case is two matching dynamic
+ // specifications. We return here unless both specifications are dynamic.
+ if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) {
if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
!New->hasExceptionSpec()) {
// The old type has an exception specification of some sort, but
// the new type does not.
*MissingExceptionSpecification = true;
- if (MissingEmptyExceptionSpecification &&
- !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) {
- // The old type has a throw() exception specification and the
- // new type has no exception specification, and the caller asked
+ if (MissingEmptyExceptionSpecification && OldNonThrowing) {
+ // The old type has a throw() or noexcept(true) exception specification
+ // and the new type has no exception specification, and the caller asked
// to handle this itself.
*MissingEmptyExceptionSpecification = true;
}
@@ -294,8 +434,11 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
return true;
}
+ assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic &&
+ "Exception compatibility logic error: non-dynamic spec slipped through.");
+
bool Success = true;
- // Both have a definite exception spec. Collect the first set, then compare
+ // Both have a dynamic exception spec. Collect the first set, then compare
// to the second.
llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
@@ -331,7 +474,7 @@ bool Sema::CheckExceptionSpecSubset(
const FunctionProtoType *Subset, SourceLocation SubLoc) {
// Just auto-succeed under -fno-exceptions.
- if (!getLangOptions().Exceptions)
+ if (!getLangOptions().CXXExceptions)
return false;
// FIXME: As usual, we could be more specific in our error messages, but
@@ -340,19 +483,66 @@ bool Sema::CheckExceptionSpecSubset(
if (!SubLoc.isValid())
SubLoc = SuperLoc;
+ ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
+
// If superset contains everything, we're done.
- if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
+ if (SuperEST == EST_None || SuperEST == EST_MSAny)
+ return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+
+ // If there are dependent noexcept specs, assume everything is fine. Unlike
+ // with the equivalency check, this is safe in this case, because we don't
+ // want to merge declarations. Checks after instantiation will catch any
+ // omissions we make here.
+ // We also shortcut checking if a noexcept expression was bad.
+
+ FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context);
+ if (SuperNR == FunctionProtoType::NR_BadNoexcept ||
+ SuperNR == FunctionProtoType::NR_Dependent)
+ return false;
+
+ // Another case of the superset containing everything.
+ if (SuperNR == FunctionProtoType::NR_Throw)
return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+ ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
+
// It does not. If the subset contains everything, we've failed.
- if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
+ if (SubEST == EST_None || SubEST == EST_MSAny) {
+ Diag(SubLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+
+ FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context);
+ if (SubNR == FunctionProtoType::NR_BadNoexcept ||
+ SubNR == FunctionProtoType::NR_Dependent)
+ return false;
+
+ // Another case of the subset containing everything.
+ if (SubNR == FunctionProtoType::NR_Throw) {
+ Diag(SubLoc, DiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+
+ // If the subset contains nothing, we're done.
+ if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow)
+ return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+
+ // Otherwise, if the superset contains nothing, we've failed.
+ if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) {
Diag(SubLoc, DiagID);
if (NoteID.getDiagID() != 0)
Diag(SuperLoc, NoteID);
return true;
}
- // Neither contains everything. Do a proper comparison.
+ assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&
+ "Exception spec subset: non-dynamic case slipped through.");
+
+ // Neither contains everything or nothing. Do a proper comparison.
for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
// Take one type from the subset.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 415ab3f38d58..20b92b84203f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -16,6 +16,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/AnalysisBasedWarnings.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -56,7 +57,7 @@ using namespace sema;
/// referenced), false otherwise.
///
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
- bool UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass) {
if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
@@ -68,7 +69,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
Diag(Suppressed[I].first, Suppressed[I].second);
// Clear out the list of suppressed diagnostics, so that we don't emit
- // them again for this specialization. However, we don't remove this
+ // them again for this specialization. However, we don't obsolete this
// entry from the table, because we want to avoid ever emitting these
// diagnostics again.
Suppressed.clear();
@@ -82,13 +83,28 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return true;
}
- // See if the decl is deprecated.
- if (const DeprecatedAttr *DA = D->getAttr<DeprecatedAttr>())
- EmitDeprecationWarning(D, DA->getMessage(), Loc, UnknownObjCClass);
+ // See if this is a deleted function.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isDeleted()) {
+ Diag(Loc, diag::err_deleted_function_use);
+ Diag(D->getLocation(), diag::note_unavailable_here) << true;
+ return true;
+ }
+ }
- // See if the decl is unavailable
- if (const UnavailableAttr *UA = D->getAttr<UnavailableAttr>()) {
- if (UA->getMessage().empty()) {
+ // See if this declaration is unavailable or deprecated.
+ std::string Message;
+ switch (D->getAvailability(&Message)) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ break;
+
+ case AR_Deprecated:
+ EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass);
+ break;
+
+ case AR_Unavailable:
+ if (Message.empty()) {
if (!UnknownObjCClass)
Diag(Loc, diag::err_unavailable) << D->getDeclName();
else
@@ -97,17 +113,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
}
else
Diag(Loc, diag::err_unavailable_message)
- << D->getDeclName() << UA->getMessage();
- Diag(D->getLocation(), diag::note_unavailable_here) << 0;
- }
-
- // See if this is a deleted function.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->isDeleted()) {
- Diag(Loc, diag::err_deleted_function_use);
- Diag(D->getLocation(), diag::note_unavailable_here) << true;
- return true;
- }
+ << D->getDeclName() << Message;
+ Diag(D->getLocation(), diag::note_unavailable_here) << 0;
+ break;
}
// Warn if this is used but marked unused.
@@ -117,6 +125,23 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return false;
}
+/// \brief Retrieve the message suffix that should be added to a
+/// diagnostic complaining about the given function being deleted or
+/// unavailable.
+std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) {
+ // FIXME: C++0x implicitly-deleted special member functions could be
+ // detected here so that we could improve diagnostics to say, e.g.,
+ // "base class 'A' had a deleted copy constructor".
+ if (FD->isDeleted())
+ return std::string();
+
+ std::string Message;
+ if (FD->getAvailability(&Message))
+ return ": " + Message;
+
+ return std::string();
+}
+
/// DiagnoseSentinelCalls - This routine checks on method dispatch calls
/// (and other functions in future), which have been declared with sentinel
/// attribute. It warns if call does not have the sentinel argument.
@@ -232,13 +257,13 @@ SourceRange Sema::getExprRange(ExprTy *E) const {
//===----------------------------------------------------------------------===//
/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
-void Sema::DefaultFunctionArrayConversion(Expr *&E) {
+ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
if (Ty->isFunctionType())
- ImpCastExprToType(E, Context.getPointerType(Ty),
- CK_FunctionToPointerDecay);
+ E = ImpCastExprToType(E, Context.getPointerType(Ty),
+ CK_FunctionToPointerDecay).take();
else if (Ty->isArrayType()) {
// In C90 mode, arrays only promote to pointers if the array expression is
// an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has
@@ -252,25 +277,48 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
// T" can be converted to an rvalue of type "pointer to T".
//
if (getLangOptions().C99 || getLangOptions().CPlusPlus || E->isLValue())
- ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
- CK_ArrayToPointerDecay);
+ E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
+ CK_ArrayToPointerDecay).take();
+ }
+ return Owned(E);
+}
+
+static void CheckForNullPointerDereference(Sema &S, Expr *E) {
+ // Check to see if we are dereferencing a null pointer. If so,
+ // and if not volatile-qualified, this is undefined behavior that the
+ // optimizer will delete, so warn about it. People sometimes try to use this
+ // to get a deterministic trap and are surprised by clang's behavior. This
+ // only handles the pattern "*null", which is a very syntactic check.
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()))
+ if (UO->getOpcode() == UO_Deref &&
+ UO->getSubExpr()->IgnoreParenCasts()->
+ isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) &&
+ !UO->getType().isVolatileQualified()) {
+ S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ S.PDiag(diag::warn_indirection_through_null)
+ << UO->getSubExpr()->getSourceRange());
+ S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ S.PDiag(diag::note_indirection_through_null));
}
}
-void Sema::DefaultLvalueConversion(Expr *&E) {
+ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// C++ [conv.lval]p1:
// A glvalue of a non-function, non-array type T can be
// converted to a prvalue.
- if (!E->isGLValue()) return;
+ if (!E->isGLValue()) return Owned(E);
QualType T = E->getType();
assert(!T.isNull() && "r-value conversion on typeless expression?");
// Create a load out of an ObjCProperty l-value, if necessary.
if (E->getObjectKind() == OK_ObjCProperty) {
- ConvertPropertyForRValue(E);
+ ExprResult Res = ConvertPropertyForRValue(E);
+ if (Res.isInvalid())
+ return Owned(E);
+ E = Res.take();
if (!E->isGLValue())
- return;
+ return Owned(E);
}
// We don't want to throw lvalue-to-rvalue casts on top of
@@ -279,7 +327,7 @@ void Sema::DefaultLvalueConversion(Expr *&E) {
(E->getType() == Context.OverloadTy ||
T->isDependentType() ||
T->isRecordType()))
- return;
+ return Owned(E);
// The C standard is actually really unclear on this point, and
// DR106 tells us what the result should be but not why. It's
@@ -287,7 +335,9 @@ void Sema::DefaultLvalueConversion(Expr *&E) {
// lvalue-to-rvalue at all. Note that expressions of unqualified
// 'void' type are never l-values, but qualified void can be.
if (T->isVoidType())
- return;
+ return Owned(E);
+
+ CheckForNullPointerDereference(*this, E);
// C++ [conv.lval]p1:
// [...] If T is a non-class type, the type of the prvalue is the
@@ -301,27 +351,34 @@ void Sema::DefaultLvalueConversion(Expr *&E) {
if (T.hasQualifiers())
T = T.getUnqualifiedType();
- if (const ArraySubscriptExpr *ae = dyn_cast<ArraySubscriptExpr>(E))
- CheckArrayAccess(ae);
+ CheckArrayAccess(E);
- E = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
- E, 0, VK_RValue);
+ return Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
+ E, 0, VK_RValue));
}
-void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) {
- DefaultFunctionArrayConversion(E);
- DefaultLvalueConversion(E);
+ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) {
+ ExprResult Res = DefaultFunctionArrayConversion(E);
+ if (Res.isInvalid())
+ return ExprError();
+ Res = DefaultLvalueConversion(Res.take());
+ if (Res.isInvalid())
+ return ExprError();
+ return move(Res);
}
/// UsualUnaryConversions - Performs various conversions that are common to most
/// operators (C99 6.3). The conversions of array and function types are
-/// sometimes surpressed. For example, the array->pointer conversion doesn't
+/// sometimes suppressed. For example, the array->pointer conversion doesn't
/// apply if the array is an argument to the sizeof or address (&) operators.
/// In these instances, this routine should *not* be called.
-Expr *Sema::UsualUnaryConversions(Expr *&E) {
+ExprResult Sema::UsualUnaryConversions(Expr *E) {
// First, convert to an r-value.
- DefaultFunctionArrayLvalueConversion(E);
+ ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
+ if (Res.isInvalid())
+ return Owned(E);
+ E = Res.take();
QualType Ty = E->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
@@ -345,60 +402,66 @@ Expr *Sema::UsualUnaryConversions(Expr *&E) {
QualType PTy = Context.isPromotableBitField(E);
if (!PTy.isNull()) {
- ImpCastExprToType(E, PTy, CK_IntegralCast);
- return E;
+ E = ImpCastExprToType(E, PTy, CK_IntegralCast).take();
+ return Owned(E);
}
if (Ty->isPromotableIntegerType()) {
QualType PT = Context.getPromotedIntegerType(Ty);
- ImpCastExprToType(E, PT, CK_IntegralCast);
- return E;
+ E = ImpCastExprToType(E, PT, CK_IntegralCast).take();
+ return Owned(E);
}
}
-
- return E;
+ return Owned(E);
}
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
/// do not have a prototype. Arguments that have type float are promoted to
/// double. All other argument types are converted by UsualUnaryConversions().
-void Sema::DefaultArgumentPromotion(Expr *&Expr) {
- QualType Ty = Expr->getType();
+ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
+ QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
- UsualUnaryConversions(Expr);
+ ExprResult Res = UsualUnaryConversions(E);
+ if (Res.isInvalid())
+ return Owned(E);
+ E = Res.take();
// If this is a 'float' (CVR qualified or typedef) promote to double.
if (Ty->isSpecificBuiltinType(BuiltinType::Float))
- return ImpCastExprToType(Expr, Context.DoubleTy, CK_FloatingCast);
+ E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take();
+
+ return Owned(E);
}
/// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
/// will warn if the resulting type is not a POD type, and rejects ObjC
-/// interfaces passed by value. This returns true if the argument type is
-/// completely illegal.
-bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
+/// interfaces passed by value.
+ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
FunctionDecl *FDecl) {
- DefaultArgumentPromotion(Expr);
+ ExprResult ExprRes = DefaultArgumentPromotion(E);
+ if (ExprRes.isInvalid())
+ return ExprError();
+ E = ExprRes.take();
// __builtin_va_start takes the second argument as a "varargs" argument, but
// it doesn't actually do anything with it. It doesn't need to be non-pod
// etc.
if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start)
- return false;
+ return Owned(E);
- if (Expr->getType()->isObjCObjectType() &&
- DiagRuntimeBehavior(Expr->getLocStart(), 0,
+ if (E->getType()->isObjCObjectType() &&
+ DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
- << Expr->getType() << CT))
- return true;
+ << E->getType() << CT))
+ return ExprError();
- if (!Expr->getType()->isPODType() &&
- DiagRuntimeBehavior(Expr->getLocStart(), 0,
+ if (!E->getType()->isPODType() &&
+ DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << Expr->getType() << CT))
- return true;
+ << E->getType() << CT))
+ return ExprError();
- return false;
+ return Owned(E);
}
/// UsualArithmeticConversions - Performs various conversions that are common to
@@ -407,19 +470,24 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT,
/// responsible for emitting appropriate error diagnostics.
/// FIXME: verify the conversion rules for "complex int" are consistent with
/// GCC.
-QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
+QualType Sema::UsualArithmeticConversions(ExprResult &lhsExpr, ExprResult &rhsExpr,
bool isCompAssign) {
- if (!isCompAssign)
- UsualUnaryConversions(lhsExpr);
+ if (!isCompAssign) {
+ lhsExpr = UsualUnaryConversions(lhsExpr.take());
+ if (lhsExpr.isInvalid())
+ return QualType();
+ }
- UsualUnaryConversions(rhsExpr);
+ rhsExpr = UsualUnaryConversions(rhsExpr.take());
+ if (rhsExpr.isInvalid())
+ return QualType();
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhs =
- Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
+ Context.getCanonicalType(lhsExpr.get()->getType()).getUnqualifiedType();
QualType rhs =
- Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType();
+ Context.getCanonicalType(rhsExpr.get()->getType()).getUnqualifiedType();
// If both types are identical, no conversion is needed.
if (lhs == rhs)
@@ -434,11 +502,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
QualType lhs_unpromoted = lhs;
if (lhs->isPromotableIntegerType())
lhs = Context.getPromotedIntegerType(lhs);
- QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr);
+ QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr.get());
if (!LHSBitfieldPromoteTy.isNull())
lhs = LHSBitfieldPromoteTy;
if (lhs != lhs_unpromoted && !isCompAssign)
- ImpCastExprToType(lhsExpr, lhs, CK_IntegralCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), lhs, CK_IntegralCast);
// If both types are identical, no conversion is needed.
if (lhs == rhs)
@@ -455,11 +523,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (!RHSComplexFloat && !rhs->isRealFloatingType()) {
if (rhs->isIntegerType()) {
QualType fp = cast<ComplexType>(lhs)->getElementType();
- ImpCastExprToType(rhsExpr, fp, CK_IntegralToFloating);
- ImpCastExprToType(rhsExpr, lhs, CK_FloatingRealToComplex);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_IntegralToFloating);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex);
} else {
assert(rhs->isComplexIntegerType());
- ImpCastExprToType(rhsExpr, lhs, CK_IntegralComplexToFloatingComplex);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexToFloatingComplex);
}
return lhs;
}
@@ -469,11 +537,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// int -> float -> _Complex float
if (lhs->isIntegerType()) {
QualType fp = cast<ComplexType>(rhs)->getElementType();
- ImpCastExprToType(lhsExpr, fp, CK_IntegralToFloating);
- ImpCastExprToType(lhsExpr, rhs, CK_FloatingRealToComplex);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_IntegralToFloating);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex);
} else {
assert(lhs->isComplexIntegerType());
- ImpCastExprToType(lhsExpr, rhs, CK_IntegralComplexToFloatingComplex);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexToFloatingComplex);
}
}
return rhs;
@@ -495,13 +563,13 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (LHSComplexFloat && RHSComplexFloat) {
if (order > 0) {
// _Complex float -> _Complex double
- ImpCastExprToType(rhsExpr, lhs, CK_FloatingComplexCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingComplexCast);
return lhs;
} else if (order < 0) {
// _Complex float -> _Complex double
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_FloatingComplexCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingComplexCast);
return rhs;
}
return lhs;
@@ -513,8 +581,8 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (order > 0) { // LHS is wider
// float -> _Complex double
QualType fp = cast<ComplexType>(lhs)->getElementType();
- ImpCastExprToType(rhsExpr, fp, CK_FloatingCast);
- ImpCastExprToType(rhsExpr, lhs, CK_FloatingRealToComplex);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_FloatingCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex);
return lhs;
}
@@ -522,11 +590,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
QualType result = (order == 0 ? lhs : Context.getComplexType(rhs));
// double -> _Complex double
- ImpCastExprToType(rhsExpr, result, CK_FloatingRealToComplex);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex);
// _Complex float -> _Complex double
if (!isCompAssign && order < 0)
- ImpCastExprToType(lhsExpr, result, CK_FloatingComplexCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingComplexCast);
return result;
}
@@ -539,8 +607,8 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// float -> _Complex double
if (!isCompAssign) {
QualType fp = cast<ComplexType>(rhs)->getElementType();
- ImpCastExprToType(lhsExpr, fp, CK_FloatingCast);
- ImpCastExprToType(lhsExpr, rhs, CK_FloatingRealToComplex);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_FloatingCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex);
}
return rhs;
}
@@ -550,11 +618,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// double -> _Complex double
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, result, CK_FloatingRealToComplex);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex);
// _Complex float -> _Complex double
if (order > 0)
- ImpCastExprToType(rhsExpr, result, CK_FloatingComplexCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingComplexCast);
return result;
}
@@ -568,13 +636,13 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (LHSFloat && RHSFloat) {
int order = Context.getFloatingTypeOrder(lhs, rhs);
if (order > 0) {
- ImpCastExprToType(rhsExpr, lhs, CK_FloatingCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingCast);
return lhs;
}
assert(order < 0 && "illegal float comparison");
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_FloatingCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingCast);
return rhs;
}
@@ -582,7 +650,7 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (LHSFloat) {
if (rhs->isIntegerType()) {
// Convert rhs to the lhs floating point type.
- ImpCastExprToType(rhsExpr, lhs, CK_IntegralToFloating);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralToFloating);
return lhs;
}
@@ -591,11 +659,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
QualType result = Context.getComplexType(lhs);
// _Complex int -> _Complex float
- ImpCastExprToType(rhsExpr, result, CK_IntegralComplexToFloatingComplex);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralComplexToFloatingComplex);
// float -> _Complex float
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, result, CK_FloatingRealToComplex);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex);
return result;
}
@@ -604,7 +672,7 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (lhs->isIntegerType()) {
// Convert lhs to the rhs floating point type.
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_IntegralToFloating);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralToFloating);
return rhs;
}
@@ -614,10 +682,10 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// _Complex int -> _Complex float
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, result, CK_IntegralComplexToFloatingComplex);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralComplexToFloatingComplex);
// float -> _Complex float
- ImpCastExprToType(rhsExpr, result, CK_FloatingRealToComplex);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex);
return result;
}
@@ -633,21 +701,21 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
assert(order && "inequal types with equal element ordering");
if (order > 0) {
// _Complex int -> _Complex long
- ImpCastExprToType(rhsExpr, lhs, CK_IntegralComplexCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexCast);
return lhs;
}
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_IntegralComplexCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexCast);
return rhs;
} else if (lhsComplexInt) {
// int -> _Complex int
- ImpCastExprToType(rhsExpr, lhs, CK_IntegralRealToComplex);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralRealToComplex);
return lhs;
} else if (rhsComplexInt) {
// int -> _Complex int
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_IntegralRealToComplex);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralRealToComplex);
return rhs;
}
@@ -659,29 +727,29 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (lhsSigned == rhsSigned) {
// Same signedness; use the higher-ranked type
if (compare >= 0) {
- ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast);
return lhs;
} else if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast);
return rhs;
} else if (compare != (lhsSigned ? 1 : -1)) {
// The unsigned type has greater than or equal rank to the
// signed type, so use the unsigned type
if (rhsSigned) {
- ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast);
return lhs;
} else if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast);
return rhs;
} else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) {
// The two types are different widths; if we are here, that
// means the signed type is larger than the unsigned type, so
// use the signed type.
if (lhsSigned) {
- ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast);
return lhs;
} else if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast);
return rhs;
} else {
// The signed type is higher-ranked than the unsigned type,
@@ -690,9 +758,9 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// to the signed type.
QualType result =
Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
- ImpCastExprToType(rhsExpr, result, CK_IntegralCast);
+ rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralCast);
if (!isCompAssign)
- ImpCastExprToType(lhsExpr, result, CK_IntegralCast);
+ lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralCast);
return result;
}
}
@@ -702,6 +770,163 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
//===----------------------------------------------------------------------===//
+ExprResult
+Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ MultiTypeArg types,
+ MultiExprArg exprs) {
+ unsigned NumAssocs = types.size();
+ assert(NumAssocs == exprs.size());
+
+ ParsedType *ParsedTypes = types.release();
+ Expr **Exprs = exprs.release();
+
+ TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
+ for (unsigned i = 0; i < NumAssocs; ++i) {
+ if (ParsedTypes[i])
+ (void) GetTypeFromParser(ParsedTypes[i], &Types[i]);
+ else
+ Types[i] = 0;
+ }
+
+ ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
+ ControllingExpr, Types, Exprs,
+ NumAssocs);
+ delete [] Types;
+ return ER;
+}
+
+ExprResult
+Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ TypeSourceInfo **Types,
+ Expr **Exprs,
+ unsigned NumAssocs) {
+ bool TypeErrorFound = false,
+ IsResultDependent = ControllingExpr->isTypeDependent(),
+ ContainsUnexpandedParameterPack
+ = ControllingExpr->containsUnexpandedParameterPack();
+
+ for (unsigned i = 0; i < NumAssocs; ++i) {
+ if (Exprs[i]->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ if (Types[i]) {
+ if (Types[i]->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ if (Types[i]->getType()->isDependentType()) {
+ IsResultDependent = true;
+ } else {
+ // C1X 6.5.1.1p2 "The type name in a generic association shall specify a
+ // complete object type other than a variably modified type."
+ unsigned D = 0;
+ if (Types[i]->getType()->isIncompleteType())
+ D = diag::err_assoc_type_incomplete;
+ else if (!Types[i]->getType()->isObjectType())
+ D = diag::err_assoc_type_nonobject;
+ else if (Types[i]->getType()->isVariablyModifiedType())
+ D = diag::err_assoc_type_variably_modified;
+
+ if (D != 0) {
+ Diag(Types[i]->getTypeLoc().getBeginLoc(), D)
+ << Types[i]->getTypeLoc().getSourceRange()
+ << Types[i]->getType();
+ TypeErrorFound = true;
+ }
+
+ // C1X 6.5.1.1p2 "No two generic associations in the same generic
+ // selection shall specify compatible types."
+ for (unsigned j = i+1; j < NumAssocs; ++j)
+ if (Types[j] && !Types[j]->getType()->isDependentType() &&
+ Context.typesAreCompatible(Types[i]->getType(),
+ Types[j]->getType())) {
+ Diag(Types[j]->getTypeLoc().getBeginLoc(),
+ diag::err_assoc_compatible_types)
+ << Types[j]->getTypeLoc().getSourceRange()
+ << Types[j]->getType()
+ << Types[i]->getType();
+ Diag(Types[i]->getTypeLoc().getBeginLoc(),
+ diag::note_compat_assoc)
+ << Types[i]->getTypeLoc().getSourceRange()
+ << Types[i]->getType();
+ TypeErrorFound = true;
+ }
+ }
+ }
+ }
+ if (TypeErrorFound)
+ return ExprError();
+
+ // If we determined that the generic selection is result-dependent, don't
+ // try to compute the result expression.
+ if (IsResultDependent)
+ return Owned(new (Context) GenericSelectionExpr(
+ Context, KeyLoc, ControllingExpr,
+ Types, Exprs, NumAssocs, DefaultLoc,
+ RParenLoc, ContainsUnexpandedParameterPack));
+
+ llvm::SmallVector<unsigned, 1> CompatIndices;
+ unsigned DefaultIndex = -1U;
+ for (unsigned i = 0; i < NumAssocs; ++i) {
+ if (!Types[i])
+ DefaultIndex = i;
+ else if (Context.typesAreCompatible(ControllingExpr->getType(),
+ Types[i]->getType()))
+ CompatIndices.push_back(i);
+ }
+
+ // C1X 6.5.1.1p2 "The controlling expression of a generic selection shall have
+ // type compatible with at most one of the types named in its generic
+ // association list."
+ if (CompatIndices.size() > 1) {
+ // We strip parens here because the controlling expression is typically
+ // parenthesized in macro definitions.
+ ControllingExpr = ControllingExpr->IgnoreParens();
+ Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match)
+ << ControllingExpr->getSourceRange() << ControllingExpr->getType()
+ << (unsigned) CompatIndices.size();
+ for (llvm::SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(),
+ E = CompatIndices.end(); I != E; ++I) {
+ Diag(Types[*I]->getTypeLoc().getBeginLoc(),
+ diag::note_compat_assoc)
+ << Types[*I]->getTypeLoc().getSourceRange()
+ << Types[*I]->getType();
+ }
+ return ExprError();
+ }
+
+ // C1X 6.5.1.1p2 "If a generic selection has no default generic association,
+ // its controlling expression shall have type compatible with exactly one of
+ // the types named in its generic association list."
+ if (DefaultIndex == -1U && CompatIndices.size() == 0) {
+ // We strip parens here because the controlling expression is typically
+ // parenthesized in macro definitions.
+ ControllingExpr = ControllingExpr->IgnoreParens();
+ Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_no_match)
+ << ControllingExpr->getSourceRange() << ControllingExpr->getType();
+ return ExprError();
+ }
+
+ // C1X 6.5.1.1p3 "If a generic selection has a generic association with a
+ // type name that is compatible with the type of the controlling expression,
+ // then the result expression of the generic selection is the expression
+ // in that generic association. Otherwise, the result expression of the
+ // generic selection is the expression in the default generic association."
+ unsigned ResultIndex =
+ CompatIndices.size() ? CompatIndices[0] : DefaultIndex;
+
+ return Owned(new (Context) GenericSelectionExpr(
+ Context, KeyLoc, ControllingExpr,
+ Types, Exprs, NumAssocs, DefaultLoc,
+ RParenLoc, ContainsUnexpandedParameterPack,
+ ResultIndex));
+}
+
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
@@ -721,8 +946,10 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
StringTokLocs.push_back(StringToks[i].getLocation());
QualType StrTy = Context.CharTy;
- if (Literal.AnyWide) StrTy = Context.getWCharType();
- if (Literal.Pascal) StrTy = Context.UnsignedCharTy;
+ if (Literal.AnyWide)
+ StrTy = Context.getWCharType();
+ else if (Literal.Pascal)
+ StrTy = Context.UnsignedCharTy;
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings)
@@ -738,7 +965,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
return Owned(StringLiteral::Create(Context, Literal.GetString(),
Literal.GetStringLength(),
- Literal.AnyWide, StrTy,
+ Literal.AnyWide, Literal.Pascal, StrTy,
&StringTokLocs[0],
StringTokLocs.size()));
}
@@ -783,11 +1010,20 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
// diagnose this.
if (!S.CurContext->isFunctionOrMethod()) return CR_NoCapture;
- // This particular madness can happen in ill-formed default
- // arguments; claim it's okay and let downstream code handle it.
- if (isa<ParmVarDecl>(var) &&
- S.CurContext == var->getDeclContext()->getParent())
- return CR_NoCapture;
+ // Certain madnesses can happen with parameter declarations, which
+ // we want to ignore.
+ if (isa<ParmVarDecl>(var)) {
+ // - If the parameter still belongs to the translation unit, then
+ // we're actually just using one parameter in the declaration of
+ // the next. This is useful in e.g. VLAs.
+ if (isa<TranslationUnitDecl>(var->getDeclContext()))
+ return CR_NoCapture;
+
+ // - This particular madness can happen in ill-formed default
+ // arguments; claim it's okay and let downstream code handle it.
+ if (S.CurContext == var->getDeclContext()->getParent())
+ return CR_NoCapture;
+ }
DeclarationName functionName;
if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext()))
@@ -889,8 +1125,18 @@ static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
// Build a copy expression.
Expr *copyExpr = 0;
- if (!byRef && S.getLangOptions().CPlusPlus &&
- !type->isDependentType() && type->isStructureOrClassType()) {
+ const RecordType *rtype;
+ if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() &&
+ (rtype = type->getAs<RecordType>())) {
+
+ // The capture logic needs the destructor, so make sure we mark it.
+ // Usually this is unnecessary because most local variables have
+ // their destructors marked at declaration time, but parameters are
+ // an exception because it's technically only the call site that
+ // actually requires the destructor.
+ if (isa<ParmVarDecl>(var))
+ S.FinalizeVarWithDestructor(var, rtype);
+
// According to the blocks spec, the capture of a variable from
// the stack requires a const copy constructor. This is not true
// of the copy/move done to move a __block variable to the heap.
@@ -974,8 +1220,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
MarkDeclarationReferenced(NameInfo.getLoc(), D);
Expr *E = DeclRefExpr::Create(Context,
- SS? (NestedNameSpecifier *)SS->getScopeRep() : 0,
- SS? SS->getRange() : SourceRange(),
+ SS? SS->getWithLocInContext(Context)
+ : NestedNameSpecifierLoc(),
D, NameInfo, Ty, VK);
// Just in case we're building an illegal pointer-to-member.
@@ -1261,12 +1507,24 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
return IMA_Error_StaticContext;
}
+ CXXRecordDecl *
+ contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl();
+
+ // [class.mfct.non-static]p3:
+ // ...is used in the body of a non-static member function of class X,
+ // if name lookup (3.4.1) resolves the name in the id-expression to a
+ // non-static non-type member of some class C [...]
+ // ...if C is not X or a base class of X, the class member access expression
+ // is ill-formed.
+ if (R.getNamingClass() &&
+ contextClass != R.getNamingClass()->getCanonicalDecl() &&
+ contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
// If we can prove that the current context is unrelated to all the
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef,
- cast<CXXMethodDecl>(DC)->getParent(),
- Classes))
+ if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
return (hasNonInstance ? IMA_Mixed : IMA_Instance);
@@ -1350,10 +1608,13 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
TemplateArgumentListInfo TList;
if (ULE->hasExplicitTemplateArgs())
ULE->copyTemplateArgumentsInto(TList);
+
+ CXXScopeSpec SS;
+ SS.Adopt(ULE->getQualifierLoc());
CXXDependentScopeMemberExpr *DepExpr =
CXXDependentScopeMemberExpr::Create(
Context, DepThis, DepThisType, true, SourceLocation(),
- ULE->getQualifier(), ULE->getQualifierRange(), NULL,
+ SS.getWithLocInContext(Context), NULL,
R.getLookupNameInfo(), &TList);
CallsUndergoingInstantiation.back()->setCallee(DepExpr);
} else {
@@ -1479,11 +1740,10 @@ bool Sema::canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property) {
return true;
}
-static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef,
- LookupResult &Lookup,
- IdentifierInfo *II,
- SourceLocation NameLoc) {
- ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl();
+ObjCIvarDecl *Sema::SynthesizeProvisionalIvar(LookupResult &Lookup,
+ IdentifierInfo *II,
+ SourceLocation NameLoc) {
+ ObjCMethodDecl *CurMeth = getCurMethodDecl();
bool LookForIvars;
if (Lookup.empty())
LookForIvars = true;
@@ -1503,7 +1763,7 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef,
if (!ClassImpDecl)
return 0;
bool DynamicImplSeen = false;
- ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II);
+ ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II);
if (!property)
return 0;
if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) {
@@ -1515,9 +1775,9 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef,
return 0;
}
if (!DynamicImplSeen) {
- QualType PropType = SemaRef.Context.getCanonicalType(property->getType());
- ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(SemaRef.Context, ClassImpDecl,
- NameLoc,
+ QualType PropType = Context.getCanonicalType(property->getType());
+ ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
+ NameLoc, NameLoc,
II, PropType, /*Dinfo=*/0,
ObjCIvarDecl::Private,
(Expr *)0, true);
@@ -1619,7 +1879,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// Synthesize ivars lazily.
if (getLangOptions().ObjCDefaultSynthProperties &&
getLangOptions().ObjCNonFragileABI2) {
- if (SynthesizeProvisionalIvar(*this, R, II, NameLoc)) {
+ if (SynthesizeProvisionalIvar(R, II, NameLoc)) {
if (const ObjCPropertyDecl *Property =
canSynthesizeProvisionalIvar(II)) {
Diag(NameLoc, diag::warn_synthesized_ivar_access) << II;
@@ -1850,13 +2110,35 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
if (SelfExpr.isInvalid())
return ExprError();
- Expr *SelfE = SelfExpr.take();
- DefaultLvalueConversion(SelfE);
+ SelfExpr = DefaultLvalueConversion(SelfExpr.take());
+ if (SelfExpr.isInvalid())
+ return ExprError();
MarkDeclarationReferenced(Loc, IV);
+ Expr *base = SelfExpr.take();
+ base = base->IgnoreParenImpCasts();
+ if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(base)) {
+ const NamedDecl *ND = DE->getDecl();
+ if (!isa<ImplicitParamDecl>(ND)) {
+ // relax the rule such that it is allowed to have a shadow 'self'
+ // where stand-alone ivar can be found in this 'self' object.
+ // This is to match gcc's behavior.
+ ObjCInterfaceDecl *selfIFace = 0;
+ if (const ObjCObjectPointerType *OPT =
+ base->getType()->getAsObjCInterfacePointerType())
+ selfIFace = OPT->getInterfaceDecl();
+ if (!selfIFace ||
+ !selfIFace->lookupInstanceVariable(IV->getIdentifier())) {
+ Diag(Loc, diag::error_implicit_ivar_access)
+ << IV->getDeclName();
+ Diag(ND->getLocation(), diag::note_declared_at);
+ return ExprError();
+ }
+ }
+ }
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
- SelfE, true, true));
+ SelfExpr.take(), true, true));
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
@@ -1902,14 +2184,14 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
/// * Finally we cast from the declaring class to the "true"
/// declaring class of the member. This conversion does not
/// obey access control.
-bool
-Sema::PerformObjectMemberConversion(Expr *&From,
+ExprResult
+Sema::PerformObjectMemberConversion(Expr *From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
NamedDecl *Member) {
CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext());
if (!RD)
- return false;
+ return Owned(From);
QualType DestRecordType;
QualType DestType;
@@ -1929,7 +2211,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
}
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) {
if (Method->isStatic())
- return false;
+ return Owned(From);
DestType = Method->getThisType(Context);
DestRecordType = DestType->getPointeeType();
@@ -1943,15 +2225,15 @@ Sema::PerformObjectMemberConversion(Expr *&From,
}
} else {
// No conversion necessary.
- return false;
+ return Owned(From);
}
if (DestType->isDependentType() || FromType->isDependentType())
- return false;
+ return Owned(From);
// If the unqualified types are the same, no conversion is necessary.
if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
- return false;
+ return Owned(From);
SourceRange FromRange = From->getSourceRange();
SourceLocation FromLoc = FromRange.getBegin();
@@ -1990,12 +2272,12 @@ Sema::PerformObjectMemberConversion(Expr *&From,
CXXCastPath BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, QRecordType,
FromLoc, FromRange, &BasePath))
- return true;
+ return ExprError();
if (PointerConversions)
QType = Context.getPointerType(QType);
- ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase,
- VK, &BasePath);
+ From = ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase,
+ VK, &BasePath).take();
FromType = QType;
FromRecordType = QRecordType;
@@ -2003,7 +2285,7 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// If the qualifier type was the same as the destination type,
// we're done.
if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
- return false;
+ return Owned(From);
}
}
@@ -2026,13 +2308,13 @@ Sema::PerformObjectMemberConversion(Expr *&From,
CXXCastPath BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, URecordType,
FromLoc, FromRange, &BasePath))
- return true;
+ return ExprError();
QualType UType = URecordType;
if (PointerConversions)
UType = Context.getPointerType(UType);
- ImpCastExprToType(From, UType, CK_UncheckedDerivedToBase,
- VK, &BasePath);
+ From = ImpCastExprToType(From, UType, CK_UncheckedDerivedToBase,
+ VK, &BasePath).take();
FromType = UType;
FromRecordType = URecordType;
}
@@ -2046,11 +2328,10 @@ Sema::PerformObjectMemberConversion(Expr *&From,
if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType,
FromLoc, FromRange, &BasePath,
IgnoreAccess))
- return true;
+ return ExprError();
- ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase,
- VK, &BasePath);
- return false;
+ return ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase,
+ VK, &BasePath);
}
/// \brief Build a MemberExpr AST node.
@@ -2061,14 +2342,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
QualType Ty,
ExprValueKind VK, ExprObjectKind OK,
const TemplateArgumentListInfo *TemplateArgs = 0) {
- NestedNameSpecifier *Qualifier = 0;
- SourceRange QualifierRange;
- if (SS.isSet()) {
- Qualifier = (NestedNameSpecifier *) SS.getScopeRep();
- QualifierRange = SS.getRange();
- }
-
- return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange,
+ return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
Member, FoundDecl, MemberNameInfo,
TemplateArgs, Ty, VK, OK);
}
@@ -2123,10 +2397,12 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
}
S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
- if (S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
- FoundDecl, Field))
+ ExprResult Base =
+ S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
+ FoundDecl, Field);
+ if (Base.isInvalid())
return ExprError();
- return S.Owned(BuildMemberExpr(S.Context, BaseExpr, IsArrow, SS,
+ return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
Field, FoundDecl, MemberNameInfo,
MemberType, VK, OK));
}
@@ -2234,7 +2510,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
/// were not overloaded, and it doesn't promise that the declaration
/// will in fact be used.
static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) {
- if (isa<TypedefDecl>(D)) {
+ if (isa<TypedefNameDecl>(D)) {
S.Diag(Loc, diag::err_unexpected_typedef) << D->getDeclName();
return true;
}
@@ -2276,8 +2552,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
UnresolvedLookupExpr *ULE
= UnresolvedLookupExpr::Create(Context, R.getNamingClass(),
- (NestedNameSpecifier*) SS.getScopeRep(),
- SS.getRange(), R.getLookupNameInfo(),
+ SS.getWithLocInContext(Context),
+ R.getLookupNameInfo(),
NeedsADL, R.isOverloadedResult(),
R.begin(), R.end());
@@ -2433,6 +2709,16 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
break;
case Decl::Function: {
+ const FunctionType *fty = type->castAs<FunctionType>();
+
+ // If we're referring to a function with an __unknown_anytype
+ // result type, make the entire expression __unknown_anytype.
+ if (fty->getResultType() == Context.UnknownAnyTy) {
+ type = Context.UnknownAnyTy;
+ valueKind = VK_RValue;
+ break;
+ }
+
// Functions are l-values in C++.
if (getLangOptions().CPlusPlus) {
valueKind = VK_LValue;
@@ -2444,10 +2730,10 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// used for checking compatibility. Therefore, when referencing
// the function, we pretend that we don't have the full function
// type.
- if (!cast<FunctionDecl>(VD)->hasPrototype())
- if (const FunctionProtoType *proto = type->getAs<FunctionProtoType>())
- type = Context.getFunctionNoProtoType(proto->getResultType(),
- proto->getExtInfo());
+ if (!cast<FunctionDecl>(VD)->hasPrototype() &&
+ isa<FunctionProtoType>(fty))
+ type = Context.getFunctionNoProtoType(fty->getResultType(),
+ fty->getExtInfo());
// Functions are r-values in C.
valueKind = VK_RValue;
@@ -2455,6 +2741,16 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
case Decl::CXXMethod:
+ // If we're referring to a method with an __unknown_anytype
+ // result type, make the entire expression __unknown_anytype.
+ // This should only be possible with a type written directly.
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(VD->getType()))
+ if (proto->getResultType() == Context.UnknownAnyTy) {
+ type = Context.UnknownAnyTy;
+ valueKind = VK_RValue;
+ break;
+ }
+
// C++ methods are l-values if static, r-values if non-static.
if (cast<CXXMethodDecl>(VD)->isStatic()) {
valueKind = VK_LValue;
@@ -2478,8 +2774,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return ExprError();
}
-ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
- tok::TokenKind Kind) {
+ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
PredefinedExpr::IdentType IT;
switch (Kind) {
@@ -2606,9 +2901,14 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
bool isExact = (result == APFloat::opOK);
Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation());
- if (getLangOptions().SinglePrecisionConstants && Ty == Context.DoubleTy)
- ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast);
-
+ if (Ty == Context.DoubleTy) {
+ if (getLangOptions().SinglePrecisionConstants) {
+ Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take();
+ } else if (getLangOptions().OpenCL && !getOpenCLOptions().cl_khr_fp64) {
+ Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64);
+ Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take();
+ }
+ }
} else if (!Literal.isIntegerLiteral()) {
return ExprError();
} else {
@@ -2716,10 +3016,10 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L,
/// The UsualUnaryConversions() function is *not* called by this routine.
/// See C99 6.3.2.1p[2-4] for more details.
-bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
- SourceLocation OpLoc,
- SourceRange ExprRange,
- bool isSizeof) {
+bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
+ SourceLocation OpLoc,
+ SourceRange ExprRange,
+ UnaryExprOrTypeTrait ExprKind) {
if (exprType->isDependentType())
return false;
@@ -2730,30 +3030,47 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
if (const ReferenceType *Ref = exprType->getAs<ReferenceType>())
exprType = Ref->getPointeeType();
+ // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in
+ // scalar or vector data type argument..."
+ // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic
+ // type (C99 6.2.5p18) or void.
+ if (ExprKind == UETT_VecStep) {
+ if (!(exprType->isArithmeticType() || exprType->isVoidType() ||
+ exprType->isVectorType())) {
+ Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type)
+ << exprType << ExprRange;
+ return true;
+ }
+ }
+
// C99 6.5.3.4p1:
if (exprType->isFunctionType()) {
// alignof(function) is allowed as an extension.
- if (isSizeof)
- Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange;
+ if (ExprKind == UETT_SizeOf)
+ Diag(OpLoc, diag::ext_sizeof_function_type)
+ << ExprRange;
return false;
}
- // Allow sizeof(void)/alignof(void) as an extension.
+ // Allow sizeof(void)/alignof(void) as an extension. vec_step(void) is not
+ // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1).
if (exprType->isVoidType()) {
- Diag(OpLoc, diag::ext_sizeof_void_type)
- << (isSizeof ? "sizeof" : "__alignof") << ExprRange;
+ if (ExprKind != UETT_VecStep)
+ Diag(OpLoc, diag::ext_sizeof_void_type)
+ << ExprKind << ExprRange;
return false;
}
if (RequireCompleteType(OpLoc, exprType,
PDiag(diag::err_sizeof_alignof_incomplete_type)
- << int(!isSizeof) << ExprRange))
+ << ExprKind << ExprRange))
return true;
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) {
Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
- << exprType << isSizeof << ExprRange;
+ << exprType << (ExprKind == UETT_SizeOf)
+ << ExprRange;
return true;
}
@@ -2783,109 +3100,132 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc,
if (isa<FieldDecl>(ME->getMemberDecl()))
return false;
- return S.CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
+ return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
+ UETT_AlignOf);
+}
+
+bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc,
+ SourceRange ExprRange) {
+ E = E->IgnoreParens();
+
+ // Cannot know anything else if the expression is dependent.
+ if (E->isTypeDependent())
+ return false;
+
+ return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
+ UETT_VecStep);
}
/// \brief Build a sizeof or alignof expression given a type operand.
ExprResult
-Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo,
- SourceLocation OpLoc,
- bool isSizeOf, SourceRange R) {
+Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
+ SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ SourceRange R) {
if (!TInfo)
return ExprError();
QualType T = TInfo->getType();
if (!T->isDependentType() &&
- CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf))
+ CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind))
return ExprError();
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
- return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, TInfo,
- Context.getSizeType(), OpLoc,
- R.getEnd()));
+ return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, TInfo,
+ Context.getSizeType(),
+ OpLoc, R.getEnd()));
}
/// \brief Build a sizeof or alignof expression given an expression
/// operand.
ExprResult
-Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
- bool isSizeOf, SourceRange R) {
+Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ SourceRange R) {
// Verify that the operand is valid.
bool isInvalid = false;
if (E->isTypeDependent()) {
// Delay type-checking for type-dependent expressions.
- } else if (!isSizeOf) {
+ } else if (ExprKind == UETT_AlignOf) {
isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R);
+ } else if (ExprKind == UETT_VecStep) {
+ isInvalid = CheckVecStepExpr(E, OpLoc, R);
} else if (E->getBitField()) { // C99 6.5.3.4p1.
Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
isInvalid = true;
} else if (E->getType()->isPlaceholderType()) {
- ExprResult PE = CheckPlaceholderExpr(E, OpLoc);
+ ExprResult PE = CheckPlaceholderExpr(E);
if (PE.isInvalid()) return ExprError();
- return CreateSizeOfAlignOfExpr(PE.take(), OpLoc, isSizeOf, R);
+ return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R);
} else {
- isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true);
+ isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R,
+ UETT_SizeOf);
}
if (isInvalid)
return ExprError();
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
- return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E,
- Context.getSizeType(), OpLoc,
- R.getEnd()));
+ return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E,
+ Context.getSizeType(),
+ OpLoc, R.getEnd()));
}
-/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and
-/// the same for @c alignof and @c __alignof
+/// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c
+/// expr and the same for @c alignof and @c __alignof
/// Note that the ArgRange is invalid if isType is false.
ExprResult
-Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
- void *TyOrEx, const SourceRange &ArgRange) {
+Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange) {
// If error parsing type, ignore.
if (TyOrEx == 0) return ExprError();
if (isType) {
TypeSourceInfo *TInfo;
(void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo);
- return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange);
+ return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange);
}
Expr *ArgEx = (Expr *)TyOrEx;
ExprResult Result
- = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange());
+ = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind,
+ ArgEx->getSourceRange());
return move(Result);
}
-static QualType CheckRealImagOperand(Sema &S, Expr *&V, SourceLocation Loc,
+static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
bool isReal) {
- if (V->isTypeDependent())
+ if (V.get()->isTypeDependent())
return S.Context.DependentTy;
// _Real and _Imag are only l-values for normal l-values.
- if (V->getObjectKind() != OK_Ordinary)
- S.DefaultLvalueConversion(V);
+ if (V.get()->getObjectKind() != OK_Ordinary) {
+ V = S.DefaultLvalueConversion(V.take());
+ if (V.isInvalid())
+ return QualType();
+ }
// These operators return the element type of a complex type.
- if (const ComplexType *CT = V->getType()->getAs<ComplexType>())
+ if (const ComplexType *CT = V.get()->getType()->getAs<ComplexType>())
return CT->getElementType();
// Otherwise they pass through real integer and floating point types here.
- if (V->getType()->isArithmeticType())
- return V->getType();
+ if (V.get()->getType()->isArithmeticType())
+ return V.get()->getType();
// Test for placeholders.
- ExprResult PR = S.CheckPlaceholderExpr(V, Loc);
+ ExprResult PR = S.CheckPlaceholderExpr(V.get());
if (PR.isInvalid()) return QualType();
- if (PR.take() != V) {
- V = PR.take();
+ if (PR.get() != V.get()) {
+ V = move(PR);
return CheckRealImagOperand(S, V, Loc, isReal);
}
// Reject anything else.
- S.Diag(Loc, diag::err_realimag_invalid_type) << V->getType()
+ S.Diag(Loc, diag::err_realimag_invalid_type) << V.get()->getType()
<< (isReal ? "__real" : "__imag");
return QualType();
}
@@ -2955,9 +3295,16 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Expr *RHSExp = Idx;
// Perform default conversions.
- if (!LHSExp->getType()->getAs<VectorType>())
- DefaultFunctionArrayLvalueConversion(LHSExp);
- DefaultFunctionArrayLvalueConversion(RHSExp);
+ if (!LHSExp->getType()->getAs<VectorType>()) {
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp);
+ if (Result.isInvalid())
+ return ExprError();
+ LHSExp = Result.take();
+ }
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(RHSExp);
+ if (Result.isInvalid())
+ return ExprError();
+ RHSExp = Result.take();
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
ExprValueKind VK = VK_LValue;
@@ -3010,8 +3357,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
// force the promotion here.
Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
LHSExp->getSourceRange();
- ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy),
- CK_ArrayToPointerDecay);
+ LHSExp = ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy),
+ CK_ArrayToPointerDecay).take();
LHSTy = LHSExp->getType();
BaseExpr = LHSExp;
@@ -3021,8 +3368,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
// Same as previous, except for 123[f().a] case
Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
RHSExp->getSourceRange();
- ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy),
- CK_ArrayToPointerDecay);
+ RHSExp = ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy),
+ CK_ArrayToPointerDecay).take();
RHSTy = RHSExp->getType();
BaseExpr = RHSExp;
@@ -3269,8 +3616,7 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
// must have pointer type, and the accessed type is the pointee.
return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
IsArrow, OpLoc,
- SS.getScopeRep(),
- SS.getRange(),
+ SS.getWithLocInContext(Context),
FirstQualifierInScope,
NameInfo, TemplateArgs));
}
@@ -3441,10 +3787,15 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
// Explicit member accesses.
} else {
+ ExprResult BaseResult = Owned(Base);
ExprResult Result =
- LookupMemberExpr(R, Base, IsArrow, OpLoc,
+ LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
+
if (Result.isInvalid()) {
Owned(Base);
return ExprError();
@@ -3477,7 +3828,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
R.setBaseObjectType(BaseType);
- NestedNameSpecifier *Qualifier = SS.getScopeRep();
const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
DeclarationName MemberName = MemberNameInfo.getName();
SourceLocation MemberLoc = MemberNameInfo.getLoc();
@@ -3522,7 +3872,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
= UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(),
BaseExpr, BaseExprType,
IsArrow, OpLoc,
- Qualifier, SS.getRange(),
+ SS.getWithLocInContext(Context),
MemberNameInfo,
TemplateArgs, R.begin(), R.end());
@@ -3569,8 +3919,12 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// Perform a property load on the base regardless of whether we
// actually need it for the declaration.
- if (BaseExpr->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForRValue(BaseExpr);
+ if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(BaseExpr);
+ if (Result.isInvalid())
+ return ExprError();
+ BaseExpr = Result.take();
+ }
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
@@ -3591,12 +3945,20 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+ ExprValueKind valueKind;
+ QualType type;
+ if (MemberFn->isInstance()) {
+ valueKind = VK_RValue;
+ type = Context.BoundMemberTy;
+ } else {
+ valueKind = VK_LValue;
+ type = MemberFn->getType();
+ }
+
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
MemberFn, FoundDecl, MemberNameInfo,
- MemberFn->getType(),
- MemberFn->isInstance() ? VK_RValue : VK_LValue,
- OK_Ordinary));
+ type, valueKind, OK_Ordinary));
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
@@ -3629,9 +3991,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
/// types would be profitable. The redefinition type is whatever
/// this translation unit tried to typedef to id/Class; we store
/// it to the side and then re-use it in places like this.
-static bool ShouldTryAgainWithRedefinitionType(Sema &S, Expr *&base) {
+static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
const ObjCObjectPointerType *opty
- = base->getType()->getAs<ObjCObjectPointerType>();
+ = base.get()->getType()->getAs<ObjCObjectPointerType>();
if (!opty) return false;
const ObjCObjectType *ty = opty->getObjectType();
@@ -3651,7 +4013,7 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, Expr *&base) {
if (opty && !opty->getObjectType()->getInterface() != 0)
return false;
- S.ImpCastExprToType(base, redef, CK_BitCast);
+ base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
return true;
}
@@ -3666,17 +4028,22 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, Expr *&base) {
/// The ObjCImpDecl bit is a gross hack that will need to be properly
/// fixed for ObjC++.
ExprResult
-Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
+Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
bool &IsArrow, SourceLocation OpLoc,
CXXScopeSpec &SS,
Decl *ObjCImpDecl, bool HasTemplateArgs) {
- assert(BaseExpr && "no base expression");
+ assert(BaseExpr.get() && "no base expression");
// Perform default conversions.
- DefaultFunctionArrayConversion(BaseExpr);
- if (IsArrow) DefaultLvalueConversion(BaseExpr);
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- QualType BaseType = BaseExpr->getType();
+ if (IsArrow) {
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+ }
+
+ QualType BaseType = BaseExpr.get()->getType();
assert(!BaseType->isDependentType());
DeclarationName MemberName = R.getLookupName();
@@ -3700,19 +4067,21 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// overloaded operator->, but that should have been dealt with
// by now.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, ".");
IsArrow = false;
+ } else if (BaseType == Context.BoundMemberTy) {
+ goto fail;
} else {
Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr->getSourceRange();
+ << BaseType << BaseExpr.get()->getSourceRange();
return ExprError();
}
}
// Handle field access to simple records.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(),
+ if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
RTy, OpLoc, SS, HasTemplateArgs))
return ExprError();
@@ -3735,7 +4104,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// But we only actually find it this way on objects of type 'id',
// apparently.
if (OTy->isObjCId() && Member->isStr("isa"))
- return Owned(new (Context) ObjCIsaExpr(BaseExpr, IsArrow, MemberLoc,
+ return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
Context.getObjCClassType()));
if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
@@ -3768,7 +4137,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
<< IDecl->getDeclName() << MemberName
- << BaseExpr->getSourceRange();
+ << BaseExpr.get()->getSourceRange();
return ExprError();
}
}
@@ -3814,7 +4183,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
}
return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, BaseExpr,
+ MemberLoc, BaseExpr.take(),
IsArrow));
}
@@ -3822,8 +4191,11 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
const ObjCObjectPointerType *OPT;
if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
// This actually uses the base as an r-value.
- DefaultLvalueConversion(BaseExpr);
- assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr->getType()));
+ BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ if (BaseExpr.isInvalid())
+ return ExprError();
+
+ assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
@@ -3843,7 +4215,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
- BaseExpr));
+ BaseExpr.take()));
}
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
@@ -3867,11 +4239,12 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
VK, OK,
- MemberLoc, BaseExpr));
+ MemberLoc, BaseExpr.take()));
}
}
-
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
+ // Use of id.member can only be for a property reference. Do not
+ // use the 'id' redefinition in this case.
+ if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
@@ -3937,7 +4310,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// FIXME: we must check that the setter has property type.
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK,
- MemberLoc, BaseExpr));
+ MemberLoc, BaseExpr.take()));
}
if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
@@ -3949,7 +4322,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
}
// Normal property access.
- return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc,
+ return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc,
SourceLocation(), QualType(), false);
}
@@ -3957,13 +4330,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (BaseType->isExtVectorType()) {
// FIXME: this expr should store IsArrow.
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr->getValueKind());
+ ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc,
Member, MemberLoc);
if (ret.isNull())
return ExprError();
- return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr,
+ return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
*Member, MemberLoc));
}
@@ -3972,7 +4345,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (IsArrow &&
BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
!Context.ObjCSelRedefinitionType->isObjCSelType()) {
- ImpCastExprToType(BaseExpr, Context.ObjCSelRedefinitionType, CK_BitCast);
+ BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType,
+ CK_BitCast);
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
}
@@ -3991,7 +4365,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, "->");
// Recurse as an -> access.
@@ -4006,11 +4380,11 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
bool TryCall = false;
bool Overloaded = false;
UnresolvedSet<8> AllOverloads;
- if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr)) {
+ if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) {
AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end());
TryCall = true;
Overloaded = true;
- } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr)) {
+ } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) {
if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
AllOverloads.addDecl(Fun);
TryCall = true;
@@ -4024,22 +4398,25 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
bool HasViableZeroArgOverload = false;
for (OverloadExpr::decls_iterator it = AllOverloads.begin(),
DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it);
- QualType ResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType())) {
- ViableOverloads.addDecl(*it);
- if (OverloadDecl->getMinRequiredArguments() == 0) {
- HasViableZeroArgOverload = true;
+ // Our overload set may include TemplateDecls, which we'll ignore for the
+ // purposes of determining whether we can issue a '()' fixit.
+ if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
+ QualType ResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && ResultTy->isRecordType()) ||
+ (IsArrow && ResultTy->isPointerType() &&
+ ResultTy->getPointeeType()->isRecordType())) {
+ ViableOverloads.addDecl(*it);
+ if (OverloadDecl->getMinRequiredArguments() == 0) {
+ HasViableZeroArgOverload = true;
+ }
}
}
}
if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) {
- Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
- << 1 << 0
- << BaseExpr->getSourceRange();
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (AllOverloads.size() > 1) << 0
+ << BaseExpr.get()->getSourceRange();
int ViableOverloadCount = ViableOverloads.size();
int I;
for (I = 0; I < ViableOverloadCount; ++I) {
@@ -4052,7 +4429,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
diag::note_member_ref_possible_intended_overload);
}
if (I != ViableOverloadCount) {
- Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates)
+ Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates)
<< int(ViableOverloadCount - I);
}
return ExprError();
@@ -4068,6 +4445,16 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
}
} else if ((Fun = BaseType->getAs<FunctionType>())) {
TryCall = true;
+ } else if (BaseType == Context.BoundMemberTy) {
+ // Look for the bound-member type. If it's still overloaded,
+ // give up, although we probably should have fallen into the
+ // OverloadExpr case above if we actually have an overloaded
+ // bound member.
+ QualType fnType = Expr::findBoundMemberType(BaseExpr.get());
+ if (!fnType.isNull()) {
+ TryCall = true;
+ Fun = fnType->castAs<FunctionType>();
+ }
}
if (TryCall) {
@@ -4088,24 +4475,24 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// can emit a fixit and carry on pretending that BaseExpr was actually a
// CallExpr.
SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr->getLocEnd());
- Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
+ PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
<< int(Overloaded) << 1
- << BaseExpr->getSourceRange()
+ << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- ExprResult NewBase = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc,
+ ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
MultiExprArg(*this, 0, 0),
ParenInsertionLoc);
if (NewBase.isInvalid())
return ExprError();
- BaseExpr = NewBase.takeAs<Expr>();
- DefaultFunctionArrayConversion(BaseExpr);
+ BaseExpr = NewBase;
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
}
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseType << BaseExpr->getSourceRange();
+ << BaseType << BaseExpr.get()->getSourceRange();
return ExprError();
}
@@ -4167,8 +4554,12 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
NameInfo, TemplateArgs);
} else {
LookupResult R(*this, NameInfo, LookupMemberName);
- Result = LookupMemberExpr(R, Base, IsArrow, OpLoc,
+ ExprResult BaseResult = Owned(Base);
+ Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
SS, ObjCImpDecl, TemplateArgs != 0);
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
if (Result.isInvalid()) {
Owned(Base);
@@ -4313,6 +4704,13 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
<< NumArgsInProto << NumArgs << Fn->getSourceRange()
<< SourceRange(Args[NumArgsInProto]->getLocStart(),
Args[NumArgs-1]->getLocEnd());
+
+ // Emit the location of the prototype.
+ if (FDecl && !FDecl->getBuiltinID())
+ Diag(FDecl->getLocStart(),
+ diag::note_typecheck_call_too_many_args)
+ << FDecl;
+
// This deletes the extra arguments.
Call->setNumArgs(Context, NumArgsInProto);
return true;
@@ -4394,16 +4792,37 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// If this is a variadic call, handle args passed through "...".
if (CallType != VariadicDoesNotApply) {
- // Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = ArgIx; i != NumArgs; ++i) {
- Expr *Arg = Args[i];
- Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType, FDecl);
- AllArgs.push_back(Arg);
+
+ // Assume that extern "C" functions with variadic arguments that
+ // return __unknown_anytype aren't *really* variadic.
+ if (Proto->getResultType() == Context.UnknownAnyTy &&
+ FDecl && FDecl->isExternC()) {
+ for (unsigned i = ArgIx; i != NumArgs; ++i) {
+ ExprResult arg;
+ if (isa<ExplicitCastExpr>(Args[i]->IgnoreParens()))
+ arg = DefaultFunctionArrayLvalueConversion(Args[i]);
+ else
+ arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
+ Invalid |= arg.isInvalid();
+ AllArgs.push_back(arg.take());
+ }
+
+ // Otherwise do argument promotion, (C99 6.5.2.2p7).
+ } else {
+ for (unsigned i = ArgIx; i != NumArgs; ++i) {
+ ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
+ Invalid |= Arg.isInvalid();
+ AllArgs.push_back(Arg.take());
+ }
}
}
return Invalid;
}
+/// Given a function expression of unknown-any type, try to rebuild it
+/// to have a function type.
+static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn);
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -4464,94 +4883,39 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
RParenLoc));
- Expr *NakedFn = Fn->IgnoreParens();
-
- // Determine whether this is a call to an unresolved member function.
- if (UnresolvedMemberExpr *MemE = dyn_cast<UnresolvedMemberExpr>(NakedFn)) {
- // If lookup was unresolved but not dependent (i.e. didn't find
- // an unresolved using declaration), it has to be an overloaded
- // function set, which means it must contain either multiple
- // declarations (all methods or method templates) or a single
- // method template.
- assert((MemE->getNumDecls() > 1) ||
- isa<FunctionTemplateDecl>(
- (*MemE->decls_begin())->getUnderlyingDecl()));
- (void)MemE;
+ if (Fn->getType() == Context.UnknownAnyTy) {
+ ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
+ if (result.isInvalid()) return ExprError();
+ Fn = result.take();
+ }
+ if (Fn->getType() == Context.BoundMemberTy) {
return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
RParenLoc);
}
+ }
- // Determine whether this is a call to a member function.
- if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) {
- NamedDecl *MemDecl = MemExpr->getMemberDecl();
- if (isa<CXXMethodDecl>(MemDecl))
+ // Check for overloaded calls. This can happen even in C due to extensions.
+ if (Fn->getType() == Context.OverloadTy) {
+ OverloadExpr::FindResult find = OverloadExpr::find(Fn);
+
+ // We aren't supposed to apply this logic if there's an '&' involved.
+ if (!find.IsAddressOfOperand) {
+ OverloadExpr *ovl = find.Expression;
+ if (isa<UnresolvedLookupExpr>(ovl)) {
+ UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl);
+ return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs,
+ RParenLoc, ExecConfig);
+ } else {
return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
RParenLoc);
- }
-
- // Determine whether this is a call to a pointer-to-member function.
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(NakedFn)) {
- if (BO->getOpcode() == BO_PtrMemD ||
- BO->getOpcode() == BO_PtrMemI) {
- if (const FunctionProtoType *FPT
- = BO->getType()->getAs<FunctionProtoType>()) {
- QualType ResultTy = FPT->getCallResultType(Context);
- ExprValueKind VK = Expr::getValueKindForType(FPT->getResultType());
-
- // Check that the object type isn't more qualified than the
- // member function we're calling.
- Qualifiers FuncQuals = Qualifiers::fromCVRMask(FPT->getTypeQuals());
- Qualifiers ObjectQuals
- = BO->getOpcode() == BO_PtrMemD
- ? BO->getLHS()->getType().getQualifiers()
- : BO->getLHS()->getType()->getAs<PointerType>()
- ->getPointeeType().getQualifiers();
-
- Qualifiers Difference = ObjectQuals - FuncQuals;
- Difference.removeObjCGCAttr();
- Difference.removeAddressSpace();
- if (Difference) {
- std::string QualsString = Difference.getAsString();
- Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals)
- << BO->getType().getUnqualifiedType()
- << QualsString
- << (QualsString.find(' ') == std::string::npos? 1 : 2);
- }
-
- CXXMemberCallExpr *TheCall
- = new (Context) CXXMemberCallExpr(Context, Fn, Args,
- NumArgs, ResultTy, VK,
- RParenLoc);
-
- if (CheckCallReturnType(FPT->getResultType(),
- BO->getRHS()->getSourceRange().getBegin(),
- TheCall, 0))
- return ExprError();
-
- if (ConvertArgumentsForCall(TheCall, BO, 0, FPT, Args, NumArgs,
- RParenLoc))
- return ExprError();
-
- return MaybeBindToTemporary(TheCall);
- }
- return ExprError(Diag(Fn->getLocStart(),
- diag::err_typecheck_call_not_function)
- << Fn->getType() << Fn->getSourceRange());
}
}
}
// If we're directly calling a function, get the appropriate declaration.
- // Also, in C++, keep track of whether we should perform argument-dependent
- // lookup and whether there were any explicitly-specified template arguments.
Expr *NakedFn = Fn->IgnoreParens();
- if (isa<UnresolvedLookupExpr>(NakedFn)) {
- UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn);
- return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs,
- RParenLoc, ExecConfig);
- }
NamedDecl *NDecl = 0;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn))
@@ -4560,6 +4924,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
if (isa<DeclRefExpr>(NakedFn))
NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
+ else if (isa<MemberExpr>(NakedFn))
+ NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc,
ExecConfig);
@@ -4595,7 +4961,10 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
// Promote the function operand.
- UsualUnaryConversions(Fn);
+ ExprResult Result = UsualUnaryConversions(Fn);
+ if (Result.isInvalid())
+ return ExprError();
+ Fn = Result.take();
// Make the call expr early, before semantic checks. This guarantees cleanup
// of arguments and function on error.
@@ -4621,6 +4990,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID))
return CheckBuiltinFunctionCall(BuiltinID, TheCall);
+ retry:
const FunctionType *FuncT;
if (const PointerType *PT = Fn->getType()->getAs<PointerType>()) {
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
@@ -4633,6 +5003,15 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
Fn->getType()->getAs<BlockPointerType>()) {
FuncT = BPT->getPointeeType()->castAs<FunctionType>();
} else {
+ // Handle calls to expressions of unknown-any type.
+ if (Fn->getType() == Context.UnknownAnyTy) {
+ ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn);
+ if (rewrite.isInvalid()) return ExprError();
+ Fn = rewrite.take();
+ TheCall->setCallee(Fn);
+ goto retry;
+ }
+
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
}
@@ -4703,7 +5082,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
Arg = ArgE.takeAs<Expr>();
} else {
- DefaultArgumentPromotion(Arg);
+ ExprResult ArgE = DefaultArgumentPromotion(Arg);
+
+ if (ArgE.isInvalid())
+ return true;
+
+ Arg = ArgE.takeAs<Expr>();
}
if (RequireCompleteType(Arg->getSourceRange().getBegin(),
@@ -4819,12 +5203,12 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
/// Prepares for a scalar cast, performing all the necessary stages
/// except the final cast and returning the kind required.
-static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) {
+static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) {
// Both Src and Dest are scalar types, i.e. arithmetic or pointer.
// Also, callers should have filtered out the invalid cases with
// pointers. Everything else should be possible.
- QualType SrcTy = Src->getType();
+ QualType SrcTy = Src.get()->getType();
if (S.Context.hasSameUnqualifiedType(SrcTy, DestTy))
return CK_NoOp;
@@ -4854,7 +5238,7 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) {
case Type::STK_Integral:
switch (DestTy->getScalarTypeKind()) {
case Type::STK_Pointer:
- if (Src->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull))
+ if (Src.get()->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull))
return CK_NullToPointer;
return CK_IntegralToPointer;
case Type::STK_Bool:
@@ -4864,12 +5248,12 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) {
case Type::STK_Floating:
return CK_IntegralToFloating;
case Type::STK_IntegralComplex:
- S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(),
- CK_IntegralCast);
+ Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
+ CK_IntegralCast);
return CK_IntegralRealToComplex;
case Type::STK_FloatingComplex:
- S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(),
- CK_IntegralToFloating);
+ Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
+ CK_IntegralToFloating);
return CK_FloatingRealToComplex;
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
@@ -4885,12 +5269,12 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) {
case Type::STK_Integral:
return CK_FloatingToIntegral;
case Type::STK_FloatingComplex:
- S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(),
- CK_FloatingCast);
+ Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
+ CK_FloatingCast);
return CK_FloatingRealToComplex;
case Type::STK_IntegralComplex:
- S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(),
- CK_FloatingToIntegral);
+ Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(),
+ CK_FloatingToIntegral);
return CK_IntegralRealToComplex;
case Type::STK_Pointer:
llvm_unreachable("valid float->pointer cast?");
@@ -4909,14 +5293,14 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) {
QualType ET = SrcTy->getAs<ComplexType>()->getElementType();
if (S.Context.hasSameType(ET, DestTy))
return CK_FloatingComplexToReal;
- S.ImpCastExprToType(Src, ET, CK_FloatingComplexToReal);
+ Src = S.ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal);
return CK_FloatingCast;
}
case Type::STK_Bool:
return CK_FloatingComplexToBoolean;
case Type::STK_Integral:
- S.ImpCastExprToType(Src, SrcTy->getAs<ComplexType>()->getElementType(),
- CK_FloatingComplexToReal);
+ Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(),
+ CK_FloatingComplexToReal);
return CK_FloatingToIntegral;
case Type::STK_Pointer:
llvm_unreachable("valid complex float->pointer cast?");
@@ -4935,14 +5319,14 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) {
QualType ET = SrcTy->getAs<ComplexType>()->getElementType();
if (S.Context.hasSameType(ET, DestTy))
return CK_IntegralComplexToReal;
- S.ImpCastExprToType(Src, ET, CK_IntegralComplexToReal);
+ Src = S.ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal);
return CK_IntegralCast;
}
case Type::STK_Bool:
return CK_IntegralComplexToBoolean;
case Type::STK_Floating:
- S.ImpCastExprToType(Src, SrcTy->getAs<ComplexType>()->getElementType(),
- CK_IntegralComplexToReal);
+ Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(),
+ CK_IntegralComplexToReal);
return CK_IntegralToFloating;
case Type::STK_Pointer:
llvm_unreachable("valid complex int->pointer cast?");
@@ -4957,15 +5341,20 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) {
}
/// CheckCastTypes - Check type constraints for casting between types.
-bool Sema::CheckCastTypes(SourceRange TyR, QualType castType,
- Expr *&castExpr, CastKind& Kind, ExprValueKind &VK,
- CXXCastPath &BasePath, bool FunctionalStyle) {
+ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
+ Expr *castExpr, CastKind& Kind, ExprValueKind &VK,
+ CXXCastPath &BasePath, bool FunctionalStyle) {
+ if (castExpr->getType() == Context.UnknownAnyTy)
+ return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath);
+
if (getLangOptions().CPlusPlus)
return CXXCheckCStyleCast(SourceRange(TyR.getBegin(),
castExpr->getLocEnd()),
castType, VK, castExpr, Kind, BasePath,
FunctionalStyle);
+ assert(!castExpr->getType()->isPlaceholderType());
+
// We only support r-value casts in C.
VK = VK_RValue;
@@ -4973,18 +5362,24 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType,
// type needs to be scalar.
if (castType->isVoidType()) {
// We don't necessarily do lvalue-to-rvalue conversions on this.
- IgnoredValueConversions(castExpr);
+ ExprResult castExprRes = IgnoredValueConversions(castExpr);
+ if (castExprRes.isInvalid())
+ return ExprError();
+ castExpr = castExprRes.take();
// Cast to void allows any expr type.
Kind = CK_ToVoid;
- return false;
+ return Owned(castExpr);
}
- DefaultFunctionArrayLvalueConversion(castExpr);
+ ExprResult castExprRes = DefaultFunctionArrayLvalueConversion(castExpr);
+ if (castExprRes.isInvalid())
+ return ExprError();
+ castExpr = castExprRes.take();
if (RequireCompleteType(TyR.getBegin(), castType,
diag::err_typecheck_cast_to_incomplete))
- return true;
+ return ExprError();
if (!castType->isScalarType() && !castType->isVectorType()) {
if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) &&
@@ -4994,7 +5389,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType,
Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar)
<< castType << castExpr->getSourceRange();
Kind = CK_NoOp;
- return false;
+ return Owned(castExpr);
}
if (castType->isUnionType()) {
@@ -5011,16 +5406,19 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType,
break;
}
}
- if (Field == FieldEnd)
- return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
+ if (Field == FieldEnd) {
+ Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< castExpr->getType() << castExpr->getSourceRange();
+ return ExprError();
+ }
Kind = CK_ToUnion;
- return false;
+ return Owned(castExpr);
}
// Reject any other conversions to non-scalar types.
- return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
+ Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar)
<< castType << castExpr->getSourceRange();
+ return ExprError();
}
// The type we're casting to is known to be a scalar or vector.
@@ -5028,49 +5426,73 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType,
// Require the operand to be a scalar or vector.
if (!castExpr->getType()->isScalarType() &&
!castExpr->getType()->isVectorType()) {
- return Diag(castExpr->getLocStart(),
+ Diag(castExpr->getLocStart(),
diag::err_typecheck_expect_scalar_operand)
<< castExpr->getType() << castExpr->getSourceRange();
+ return ExprError();
}
if (castType->isExtVectorType())
return CheckExtVectorCast(TyR, castType, castExpr, Kind);
- if (castType->isVectorType())
- return CheckVectorCast(TyR, castType, castExpr->getType(), Kind);
- if (castExpr->getType()->isVectorType())
- return CheckVectorCast(TyR, castExpr->getType(), castType, Kind);
+ if (castType->isVectorType()) {
+ if (castType->getAs<VectorType>()->getVectorKind() ==
+ VectorType::AltiVecVector &&
+ (castExpr->getType()->isIntegerType() ||
+ castExpr->getType()->isFloatingType())) {
+ Kind = CK_VectorSplat;
+ return Owned(castExpr);
+ } else if (CheckVectorCast(TyR, castType, castExpr->getType(), Kind)) {
+ return ExprError();
+ } else
+ return Owned(castExpr);
+ }
+ if (castExpr->getType()->isVectorType()) {
+ if (CheckVectorCast(TyR, castExpr->getType(), castType, Kind))
+ return ExprError();
+ else
+ return Owned(castExpr);
+ }
// The source and target types are both scalars, i.e.
// - arithmetic types (fundamental, enum, and complex)
// - all kinds of pointers
// Note that member pointers were filtered out with C++, above.
- if (isa<ObjCSelectorExpr>(castExpr))
- return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
+ if (isa<ObjCSelectorExpr>(castExpr)) {
+ Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
+ return ExprError();
+ }
// If either type is a pointer, the other type has to be either an
// integer or a pointer.
if (!castType->isArithmeticType()) {
QualType castExprType = castExpr->getType();
if (!castExprType->isIntegralType(Context) &&
- castExprType->isArithmeticType())
- return Diag(castExpr->getLocStart(),
- diag::err_cast_pointer_from_non_pointer_int)
+ castExprType->isArithmeticType()) {
+ Diag(castExpr->getLocStart(),
+ diag::err_cast_pointer_from_non_pointer_int)
<< castExprType << castExpr->getSourceRange();
+ return ExprError();
+ }
} else if (!castExpr->getType()->isArithmeticType()) {
- if (!castType->isIntegralType(Context) && castType->isArithmeticType())
- return Diag(castExpr->getLocStart(),
- diag::err_cast_pointer_to_non_pointer_int)
+ if (!castType->isIntegralType(Context) && castType->isArithmeticType()) {
+ Diag(castExpr->getLocStart(), diag::err_cast_pointer_to_non_pointer_int)
<< castType << castExpr->getSourceRange();
+ return ExprError();
+ }
}
- Kind = PrepareScalarCast(*this, castExpr, castType);
+ castExprRes = Owned(castExpr);
+ Kind = PrepareScalarCast(*this, castExprRes, castType);
+ if (castExprRes.isInvalid())
+ return ExprError();
+ castExpr = castExprRes.take();
if (Kind == CK_BitCast)
CheckCastAlign(castExpr, castType, TyR);
- return false;
+ return Owned(castExpr);
}
bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
@@ -5093,8 +5515,8 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
return false;
}
-bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
- CastKind &Kind) {
+ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
+ Expr *CastExpr, CastKind &Kind) {
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
QualType SrcTy = CastExpr->getType();
@@ -5102,11 +5524,13 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
// If SrcTy is a VectorType, the total size must match to explicitly cast to
// an ExtVectorType.
if (SrcTy->isVectorType()) {
- if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy))
- return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
+ if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) {
+ Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
<< DestTy << SrcTy << R;
+ return ExprError();
+ }
Kind = CK_BitCast;
- return false;
+ return Owned(CastExpr);
}
// All non-pointer scalars can be cast to ExtVector type. The appropriate
@@ -5118,11 +5542,14 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
<< DestTy << SrcTy << R;
QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType();
- ImpCastExprToType(CastExpr, DestElemTy,
- PrepareScalarCast(*this, CastExpr, DestElemTy));
+ ExprResult CastExprRes = Owned(CastExpr);
+ CastKind CK = PrepareScalarCast(*this, CastExprRes, DestElemTy);
+ if (CastExprRes.isInvalid())
+ return ExprError();
+ CastExpr = ImpCastExprToType(CastExprRes.take(), DestElemTy, CK).take();
Kind = CK_VectorSplat;
- return false;
+ return Owned(CastExpr);
}
ExprResult
@@ -5150,12 +5577,15 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
CastKind Kind = CK_Invalid;
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
- if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
- Kind, VK, BasePath))
+ ExprResult CastResult =
+ CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
+ Kind, VK, BasePath);
+ if (CastResult.isInvalid())
return ExprError();
+ castExpr = CastResult.take();
return Owned(CStyleCastExpr::Create(Context,
- Ty->getType().getNonLValueExprType(Context),
+ Ty->getType().getNonLValueExprType(Context),
VK, Kind, castExpr, &BasePath, Ty,
LParenLoc, RParenLoc));
}
@@ -5185,9 +5615,9 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
TypeSourceInfo *TInfo) {
ParenListExpr *PE = cast<ParenListExpr>(Op);
QualType Ty = TInfo->getType();
- bool isAltiVecLiteral = false;
+ bool isVectorLiteral = false;
- // Check for an altivec literal,
+ // Check for an altivec or OpenCL literal,
// i.e. all the elements are integer constants.
if (getLangOptions().AltiVec && Ty->isVectorType()) {
if (PE->getNumExprs() == 0) {
@@ -5196,18 +5626,45 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
}
if (PE->getNumExprs() == 1) {
if (!PE->getExpr(0)->getType()->isVectorType())
- isAltiVecLiteral = true;
+ isVectorLiteral = true;
}
else
- isAltiVecLiteral = true;
+ isVectorLiteral = true;
}
- // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')'
+ // If this is a vector initializer, '(' type ')' '(' init, ..., init ')'
// then handle it as such.
- if (isAltiVecLiteral) {
+ if (isVectorLiteral) {
llvm::SmallVector<Expr *, 8> initExprs;
- for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
- initExprs.push_back(PE->getExpr(i));
+ // '(...)' form of vector initialization in AltiVec: the number of
+ // initializers must be one or must match the size of the vector.
+ // If a single value is specified in the initializer then it will be
+ // replicated to all the components of the vector
+ if (Ty->getAs<VectorType>()->getVectorKind() ==
+ VectorType::AltiVecVector) {
+ unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
+ // The number of initializers must be one or must match the size of the
+ // vector. If a single value is specified in the initializer then it will
+ // be replicated to all the components of the vector
+ if (PE->getNumExprs() == 1) {
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ ExprResult Literal = Owned(PE->getExpr(0));
+ Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ PrepareScalarCast(*this, Literal, ElemTy));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ }
+ else if (PE->getNumExprs() < numElems) {
+ Diag(PE->getExprLoc(),
+ diag::err_incorrect_number_of_vector_initializers);
+ return ExprError();
+ }
+ else
+ for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
+ initExprs.push_back(PE->getExpr(i));
+ }
+ else
+ for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i)
+ initExprs.push_back(PE->getExpr(i));
// FIXME: This means that pretty-printing the final AST will produce curly
// braces instead of the original commas.
@@ -5265,11 +5722,8 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
// In this case, check to make sure that we got here from a "NULL"
// string in the source code.
NullExpr = NullExpr->IgnoreParenImpCasts();
- SourceManager& SM = Context.getSourceManager();
- SourceLocation Loc = SM.getInstantiationLoc(NullExpr->getExprLoc());
- unsigned Len =
- Lexer::MeasureTokenLength(Loc, SM, Context.getLangOptions());
- if (Len != 4 || memcmp(SM.getCharacterData(Loc), "NULL", 4))
+ SourceLocation loc = NullExpr->getExprLoc();
+ if (!findMacroSpelling(loc, "NULL"))
return false;
}
@@ -5283,23 +5737,17 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension.
/// In that case, lhs = cond.
/// C99 6.5.15
-QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
+QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
ExprValueKind &VK, ExprObjectKind &OK,
SourceLocation QuestionLoc) {
- // If both LHS and RHS are overloaded functions, try to resolve them.
- if (Context.hasSameType(LHS->getType(), RHS->getType()) &&
- LHS->getType()->isSpecificBuiltinType(BuiltinType::Overload)) {
- ExprResult LHSResult = CheckPlaceholderExpr(LHS, QuestionLoc);
- if (LHSResult.isInvalid())
- return QualType();
- ExprResult RHSResult = CheckPlaceholderExpr(RHS, QuestionLoc);
- if (RHSResult.isInvalid())
- return QualType();
+ ExprResult lhsResult = CheckPlaceholderExpr(LHS.get());
+ if (!lhsResult.isUsable()) return QualType();
+ LHS = move(lhsResult);
- LHS = LHSResult.take();
- RHS = RHSResult.take();
- }
+ ExprResult rhsResult = CheckPlaceholderExpr(RHS.get());
+ if (!rhsResult.isUsable()) return QualType();
+ RHS = move(rhsResult);
// C++ is sufficiently different to merit its own checker.
if (getLangOptions().CPlusPlus)
@@ -5308,12 +5756,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
VK = VK_RValue;
OK = OK_Ordinary;
- UsualUnaryConversions(Cond);
- UsualUnaryConversions(LHS);
- UsualUnaryConversions(RHS);
- QualType CondTy = Cond->getType();
- QualType LHSTy = LHS->getType();
- QualType RHSTy = RHS->getType();
+ Cond = UsualUnaryConversions(Cond.take());
+ if (Cond.isInvalid())
+ return QualType();
+ LHS = UsualUnaryConversions(LHS.take());
+ if (LHS.isInvalid())
+ return QualType();
+ RHS = UsualUnaryConversions(RHS.take());
+ if (RHS.isInvalid())
+ return QualType();
+
+ QualType CondTy = Cond.get()->getType();
+ QualType LHSTy = LHS.get()->getType();
+ QualType RHSTy = RHS.get()->getType();
// first, check the condition.
if (!CondTy->isScalarType()) { // C99 6.5.15p2
@@ -5321,14 +5776,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// Throw an error if its not either.
if (getLangOptions().OpenCL) {
if (!CondTy->isVectorType()) {
- Diag(Cond->getLocStart(),
+ Diag(Cond.get()->getLocStart(),
diag::err_typecheck_cond_expect_scalar_or_vector)
<< CondTy;
return QualType();
}
}
else {
- Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar)
+ Diag(Cond.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return QualType();
}
@@ -5344,25 +5799,27 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (getLangOptions().OpenCL && CondTy->isVectorType()) {
// Both operands should be of scalar type.
if (!LHSTy->isScalarType()) {
- Diag(LHS->getLocStart(), diag::err_typecheck_cond_expect_scalar)
+ Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return QualType();
}
if (!RHSTy->isScalarType()) {
- Diag(RHS->getLocStart(), diag::err_typecheck_cond_expect_scalar)
+ Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return QualType();
}
// Implicity convert these scalars to the type of the condition.
- ImpCastExprToType(LHS, CondTy, CK_IntegralCast);
- ImpCastExprToType(RHS, CondTy, CK_IntegralCast);
+ LHS = ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast);
+ RHS = ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast);
}
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) {
UsualArithmeticConversions(LHS, RHS);
- return LHS->getType();
+ if (LHS.isInvalid() || RHS.isInvalid())
+ return QualType();
+ return LHS.get()->getType();
}
// If both operands are the same structure or union type, the result is that
@@ -5380,32 +5837,34 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// The following || allows only one side to be void (a GCC-ism).
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
if (!LHSTy->isVoidType())
- Diag(RHS->getLocStart(), diag::ext_typecheck_cond_one_void)
- << RHS->getSourceRange();
+ Diag(RHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void)
+ << RHS.get()->getSourceRange();
if (!RHSTy->isVoidType())
- Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void)
- << LHS->getSourceRange();
- ImpCastExprToType(LHS, Context.VoidTy, CK_ToVoid);
- ImpCastExprToType(RHS, Context.VoidTy, CK_ToVoid);
+ Diag(LHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void)
+ << LHS.get()->getSourceRange();
+ LHS = ImpCastExprToType(LHS.take(), Context.VoidTy, CK_ToVoid);
+ RHS = ImpCastExprToType(RHS.take(), Context.VoidTy, CK_ToVoid);
return Context.VoidTy;
}
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
// the type of the other operand."
if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
- RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
+ RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
// promote the null to a pointer.
- ImpCastExprToType(RHS, LHSTy, CK_NullToPointer);
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_NullToPointer);
return LHSTy;
}
if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
- LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- ImpCastExprToType(LHS, RHSTy, CK_NullToPointer);
+ LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
+ LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_NullToPointer);
return RHSTy;
}
// All objective-c pointer type analysis is done here.
QualType compositeType = FindCompositeObjCPointerType(LHS, RHS,
QuestionLoc);
+ if (LHS.isInvalid() || RHS.isInvalid())
+ return QualType();
if (!compositeType.isNull())
return compositeType;
@@ -5415,12 +5874,12 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
QualType destType = Context.getPointerType(Context.VoidTy);
- ImpCastExprToType(LHS, destType, CK_BitCast);
- ImpCastExprToType(RHS, destType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
return destType;
}
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
// We have 2 block pointer types.
@@ -5435,18 +5894,18 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy = Context.getPointerType(Context.VoidTy);
- ImpCastExprToType(LHS, incompatTy, CK_BitCast);
- ImpCastExprToType(RHS, incompatTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
return incompatTy;
}
// The block pointer types are compatible.
- ImpCastExprToType(LHS, LHSTy, CK_BitCast);
- ImpCastExprToType(RHS, LHSTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
@@ -5463,9 +5922,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- ImpCastExprToType(LHS, destType, CK_NoOp);
+ LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp);
// Promote to void*.
- ImpCastExprToType(RHS, destType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
return destType;
}
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
@@ -5473,9 +5932,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- ImpCastExprToType(RHS, destType, CK_NoOp);
+ RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp);
// Promote to void*.
- ImpCastExprToType(LHS, destType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
return destType;
}
@@ -5486,13 +5945,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy = Context.getPointerType(Context.VoidTy);
- ImpCastExprToType(LHS, incompatTy, CK_BitCast);
- ImpCastExprToType(RHS, incompatTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
return incompatTy;
}
// The pointer types are compatible.
@@ -5502,8 +5961,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// type.
// FIXME: Need to calculate the composite type.
// FIXME: Need to add qualifiers
- ImpCastExprToType(LHS, LHSTy, CK_BitCast);
- ImpCastExprToType(RHS, LHSTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
@@ -5511,69 +5970,69 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// null pointers have been filtered out by this point.
if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
- ImpCastExprToType(LHS, RHSTy, CK_IntegralToPointer);
+ << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_IntegralToPointer);
return RHSTy;
}
if (LHSTy->isPointerType() && RHSTy->isIntegerType()) {
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
- ImpCastExprToType(RHS, LHSTy, CK_IntegralToPointer);
+ << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_IntegralToPointer);
return LHSTy;
}
// Emit a better diagnostic if one of the expressions is a null pointer
// constant and the other is not a pointer type. In this case, the user most
// likely forgot to take the address of the other expression.
- if (DiagnoseConditionalForNull(LHS, RHS, QuestionLoc))
+ if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc))
return QualType();
// Otherwise, the operands are not compatible.
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
- << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
/// FindCompositeObjCPointerType - Helper method to find composite type of
/// two objective-c pointer types of the two input expressions.
-QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
+QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc) {
- QualType LHSTy = LHS->getType();
- QualType RHSTy = RHS->getType();
+ QualType LHSTy = LHS.get()->getType();
+ QualType RHSTy = RHS.get()->getType();
// Handle things like Class and struct objc_class*. Here we case the result
// to the pseudo-builtin, because that will be implicitly cast back to the
// redefinition type if an attempt is made to access its fields.
if (LHSTy->isObjCClassType() &&
(Context.hasSameType(RHSTy, Context.ObjCClassRedefinitionType))) {
- ImpCastExprToType(RHS, LHSTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
if (RHSTy->isObjCClassType() &&
(Context.hasSameType(LHSTy, Context.ObjCClassRedefinitionType))) {
- ImpCastExprToType(LHS, RHSTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast);
return RHSTy;
}
// And the same for struct objc_object* / id
if (LHSTy->isObjCIdType() &&
(Context.hasSameType(RHSTy, Context.ObjCIdRedefinitionType))) {
- ImpCastExprToType(RHS, LHSTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
if (RHSTy->isObjCIdType() &&
(Context.hasSameType(LHSTy, Context.ObjCIdRedefinitionType))) {
- ImpCastExprToType(LHS, RHSTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast);
return RHSTy;
}
// And the same for struct objc_selector* / SEL
if (Context.isObjCSelType(LHSTy) &&
(Context.hasSameType(RHSTy, Context.ObjCSelRedefinitionType))) {
- ImpCastExprToType(RHS, LHSTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
if (Context.isObjCSelType(RHSTy) &&
(Context.hasSameType(LHSTy, Context.ObjCSelRedefinitionType))) {
- ImpCastExprToType(LHS, RHSTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast);
return RHSTy;
}
// Check constraints for Objective-C object pointers types.
@@ -5620,15 +6079,15 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
else {
Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands)
<< LHSTy << RHSTy
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
QualType incompatTy = Context.getObjCIdType();
- ImpCastExprToType(LHS, incompatTy, CK_BitCast);
- ImpCastExprToType(RHS, incompatTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
return incompatTy;
}
// The object pointer types are compatible.
- ImpCastExprToType(LHS, compositeType, CK_BitCast);
- ImpCastExprToType(RHS, compositeType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), compositeType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), compositeType, CK_BitCast);
return compositeType;
}
// Check Objective-C object pointer types and 'void *'
@@ -5639,9 +6098,9 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- ImpCastExprToType(LHS, destType, CK_NoOp);
+ LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp);
// Promote to void*.
- ImpCastExprToType(RHS, destType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
return destType;
}
if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
@@ -5651,9 +6110,9 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- ImpCastExprToType(RHS, destType, CK_NoOp);
+ RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp);
// Promote to void*.
- ImpCastExprToType(LHS, destType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
return destType;
}
return QualType();
@@ -5681,7 +6140,10 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
&& commonExpr->isOrdinaryOrBitFieldObject()
&& RHSExpr->isOrdinaryOrBitFieldObject()
&& Context.hasSameType(commonExpr->getType(), RHSExpr->getType()))) {
- UsualUnaryConversions(commonExpr);
+ ExprResult commonRes = UsualUnaryConversions(commonExpr);
+ if (commonRes.isInvalid())
+ return ExprError();
+ commonExpr = commonRes.take();
}
opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
@@ -5693,19 +6155,21 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
- QualType result = CheckConditionalOperands(CondExpr, LHSExpr, RHSExpr,
+ ExprResult Cond = Owned(CondExpr), LHS = Owned(LHSExpr), RHS = Owned(RHSExpr);
+ QualType result = CheckConditionalOperands(Cond, LHS, RHS,
VK, OK, QuestionLoc);
- if (result.isNull())
+ if (result.isNull() || Cond.isInvalid() || LHS.isInvalid() ||
+ RHS.isInvalid())
return ExprError();
if (!commonExpr)
- return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc,
- LHSExpr, ColonLoc,
- RHSExpr, result, VK, OK));
+ return Owned(new (Context) ConditionalOperator(Cond.take(), QuestionLoc,
+ LHS.take(), ColonLoc,
+ RHS.take(), result, VK, OK));
return Owned(new (Context)
- BinaryConditionalOperator(commonExpr, opaqueValue, CondExpr, LHSExpr,
- RHSExpr, QuestionLoc, ColonLoc, result, VK, OK));
+ BinaryConditionalOperator(commonExpr, opaqueValue, Cond.take(), LHS.take(),
+ RHS.take(), QuestionLoc, ColonLoc, result, VK, OK));
}
// checkPointerTypesForAssignment - This is a very tricky routine (despite
@@ -5736,6 +6200,12 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) {
if (lhq.getAddressSpace() != rhq.getAddressSpace())
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
+ // It's okay to add or remove GC qualifiers when converting to
+ // and from void*.
+ else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr())
+ && (lhptee->isVoidType() || rhptee->isVoidType()))
+ ; // keep old
+
// For GCC compatibility, other qualifier mismatches are treated
// as still compatible in C.
else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
@@ -5885,7 +6355,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
// adds casts to this they'll be wasted, but fortunately that doesn't
// usually happen on valid code.
OpaqueValueExpr rhs(Loc, rhsType, VK_RValue);
- Expr *rhsPtr = &rhs;
+ ExprResult rhsPtr = &rhs;
CastKind K = CK_Invalid;
return CheckAssignmentConstraints(lhsType, rhsPtr, K);
@@ -5909,9 +6379,9 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
///
/// Sets 'Kind' for any result kind except Incompatible.
Sema::AssignConvertType
-Sema::CheckAssignmentConstraints(QualType lhsType, Expr *&rhs,
+Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs,
CastKind &Kind) {
- QualType rhsType = rhs->getType();
+ QualType rhsType = rhs.get()->getType();
// Get canonical types. We're not formatting these types, just comparing
// them.
@@ -5950,7 +6420,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, Expr *&rhs,
QualType elType = cast<ExtVectorType>(lhsType)->getElementType();
if (elType != rhsType) {
Kind = PrepareScalarCast(*this, rhs, elType);
- ImpCastExprToType(rhs, elType, Kind);
+ rhs = ImpCastExprToType(rhs.take(), elType, Kind);
}
Kind = CK_VectorSplat;
return Compatible;
@@ -6151,10 +6621,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, Expr *&rhs,
/// \brief Constructs a transparent union from an expression that is
/// used to initialize the transparent union.
-static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
+static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResult,
QualType UnionType, FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
+ Expr *E = EResult.take();
InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(),
&E, 1,
SourceLocation());
@@ -6164,13 +6635,14 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
// Build a compound literal constructing a value of the transparent
// union type from this initializer list.
TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType);
- E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType,
- VK_RValue, Initializer, false);
+ EResult = S.Owned(
+ new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType,
+ VK_RValue, Initializer, false));
}
Sema::AssignConvertType
-Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
- QualType FromType = rExpr->getType();
+Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rExpr) {
+ QualType FromType = rExpr.get()->getType();
// If the ArgType is a Union type, we want to handle a potential
// transparent_union GCC extension.
@@ -6191,25 +6663,23 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
// 2) null pointer constant
if (FromType->isPointerType())
if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
- ImpCastExprToType(rExpr, it->getType(), CK_BitCast);
+ rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_BitCast);
InitField = *it;
break;
}
- if (rExpr->isNullPointerConstant(Context,
+ if (rExpr.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- ImpCastExprToType(rExpr, it->getType(), CK_NullToPointer);
+ rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_NullToPointer);
InitField = *it;
break;
}
}
- Expr *rhs = rExpr;
CastKind Kind = CK_Invalid;
- if (CheckAssignmentConstraints(it->getType(), rhs, Kind)
+ if (CheckAssignmentConstraints(it->getType(), rExpr, Kind)
== Compatible) {
- ImpCastExprToType(rhs, it->getType(), Kind);
- rExpr = rhs;
+ rExpr = ImpCastExprToType(rExpr.take(), it->getType(), Kind);
InitField = *it;
break;
}
@@ -6218,20 +6688,23 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) {
if (!InitField)
return Incompatible;
- ConstructTransparentUnion(Context, rExpr, ArgType, InitField);
+ ConstructTransparentUnion(*this, Context, rExpr, ArgType, InitField);
return Compatible;
}
Sema::AssignConvertType
-Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
+Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) {
if (getLangOptions().CPlusPlus) {
if (!lhsType->isRecordType()) {
// C++ 5.17p3: If the left operand is not of class type, the
// expression is implicitly converted (C++ 4) to the
// cv-unqualified type of the left operand.
- if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(),
- AA_Assigning))
+ ExprResult Res = PerformImplicitConversion(rExpr.get(),
+ lhsType.getUnqualifiedType(),
+ AA_Assigning);
+ if (Res.isInvalid())
return Incompatible;
+ rExpr = move(Res);
return Compatible;
}
@@ -6244,9 +6717,9 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
if ((lhsType->isPointerType() ||
lhsType->isObjCObjectPointerType() ||
lhsType->isBlockPointerType())
- && rExpr->isNullPointerConstant(Context,
+ && rExpr.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- ImpCastExprToType(rExpr, lhsType, CK_NullToPointer);
+ rExpr = ImpCastExprToType(rExpr.take(), lhsType, CK_NullToPointer);
return Compatible;
}
@@ -6256,8 +6729,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
// expressions that suppress this implicit conversion (&, sizeof).
//
// Suppress this for references: C++ 8.5.3p5.
- if (!lhsType->isReferenceType())
- DefaultFunctionArrayLvalueConversion(rExpr);
+ if (!lhsType->isReferenceType()) {
+ rExpr = DefaultFunctionArrayLvalueConversion(rExpr.take());
+ if (rExpr.isInvalid())
+ return Incompatible;
+ }
CastKind Kind = CK_Invalid;
Sema::AssignConvertType result =
@@ -6269,25 +6745,25 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
// so that we can use references in built-in functions even in C.
// The getNonReferenceType() call makes sure that the resulting expression
// does not have reference type.
- if (result != Incompatible && rExpr->getType() != lhsType)
- ImpCastExprToType(rExpr, lhsType.getNonLValueExprType(Context), Kind);
+ if (result != Incompatible && rExpr.get()->getType() != lhsType)
+ rExpr = ImpCastExprToType(rExpr.take(), lhsType.getNonLValueExprType(Context), Kind);
return result;
}
-QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
+QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) {
Diag(Loc, diag::err_typecheck_invalid_operands)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getType() << rex.get()->getType()
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
-QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
+QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) {
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhsType =
- Context.getCanonicalType(lex->getType()).getUnqualifiedType();
+ Context.getCanonicalType(lex.get()->getType()).getUnqualifiedType();
QualType rhsType =
- Context.getCanonicalType(rex->getType()).getUnqualifiedType();
+ Context.getCanonicalType(rex.get()->getType()).getUnqualifiedType();
// If the vector types are identical, return.
if (lhsType == rhsType)
@@ -6301,17 +6777,17 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
if (LV->getElementType() == RV->getElementType() &&
LV->getNumElements() == RV->getNumElements()) {
if (lhsType->isExtVectorType()) {
- ImpCastExprToType(rex, lhsType, CK_BitCast);
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
return lhsType;
}
- ImpCastExprToType(lex, rhsType, CK_BitCast);
+ lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
return rhsType;
} else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a
// bitcast; no bits are changed but the result type is different.
- ImpCastExprToType(rex, lhsType, CK_BitCast);
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast);
return lhsType;
}
}
@@ -6321,7 +6797,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
// Handle the case of equivalent AltiVec and GCC vector types
if (lhsType->isVectorType() && rhsType->isVectorType() &&
Context.areCompatibleVectorTypes(lhsType, rhsType)) {
- ImpCastExprToType(lex, rhsType, CK_BitCast);
+ lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast);
return rhsType;
}
@@ -6340,9 +6816,9 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
if (EltTy->isIntegralType(Context) && rhsType->isIntegralType(Context)) {
int order = Context.getIntegerTypeOrder(EltTy, rhsType);
if (order > 0)
- ImpCastExprToType(rex, EltTy, CK_IntegralCast);
+ rex = ImpCastExprToType(rex.take(), EltTy, CK_IntegralCast);
if (order >= 0) {
- ImpCastExprToType(rex, lhsType, CK_VectorSplat);
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat);
if (swapped) std::swap(rex, lex);
return lhsType;
}
@@ -6351,9 +6827,9 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
rhsType->isRealFloatingType()) {
int order = Context.getFloatingTypeOrder(EltTy, rhsType);
if (order > 0)
- ImpCastExprToType(rex, EltTy, CK_FloatingCast);
+ rex = ImpCastExprToType(rex.take(), EltTy, CK_FloatingCast);
if (order >= 0) {
- ImpCastExprToType(rex, lhsType, CK_VectorSplat);
+ rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat);
if (swapped) std::swap(rex, lex);
return lhsType;
}
@@ -6362,72 +6838,78 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
// Vectors of different size or scalar and non-ext-vector are errors.
Diag(Loc, diag::err_typecheck_vector_not_convertable)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getType() << rex.get()->getType()
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
QualType Sema::CheckMultiplyDivideOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
+ ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
+ if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+ if (lex.isInvalid() || rex.isInvalid())
+ return QualType();
- if (!lex->getType()->isArithmeticType() ||
- !rex->getType()->isArithmeticType())
+ if (!lex.get()->getType()->isArithmeticType() ||
+ !rex.get()->getType()->isArithmeticType())
return InvalidOperands(Loc, lex, rex);
// Check for division by zero.
if (isDiv &&
- rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, rex, PDiag(diag::warn_division_by_zero)
- << rex->getSourceRange());
+ rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_division_by_zero)
+ << rex.get()->getSourceRange());
return compType;
}
QualType Sema::CheckRemainderOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
- if (lex->getType()->hasIntegerRepresentation() &&
- rex->getType()->hasIntegerRepresentation())
+ ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) {
+ if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
+ if (lex.get()->getType()->hasIntegerRepresentation() &&
+ rex.get()->getType()->hasIntegerRepresentation())
return CheckVectorOperands(Loc, lex, rex);
return InvalidOperands(Loc, lex, rex);
}
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+ if (lex.isInvalid() || rex.isInvalid())
+ return QualType();
- if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType())
+ if (!lex.get()->getType()->isIntegerType() || !rex.get()->getType()->isIntegerType())
return InvalidOperands(Loc, lex, rex);
// Check for remainder by zero.
- if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
- DiagRuntimeBehavior(Loc, rex, PDiag(diag::warn_remainder_by_zero)
- << rex->getSourceRange());
+ if (rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_remainder_by_zero)
+ << rex.get()->getSourceRange());
return compType;
}
QualType Sema::CheckAdditionOperands( // C99 6.5.6
- Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) {
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
+ ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) {
+ if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(Loc, lex, rex);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
+ if (lex.isInvalid() || rex.isInvalid())
+ return QualType();
// handle the common case first (both operands are arithmetic).
- if (lex->getType()->isArithmeticType() &&
- rex->getType()->isArithmeticType()) {
+ if (lex.get()->getType()->isArithmeticType() &&
+ rex.get()->getType()->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
// Put any potential pointer into PExp
- Expr* PExp = lex, *IExp = rex;
+ Expr* PExp = lex.get(), *IExp = rex.get();
if (IExp->getType()->isAnyPointerType())
std::swap(PExp, IExp);
@@ -6440,23 +6922,23 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
// GNU extension: arithmetic on pointer to void
Diag(Loc, diag::ext_gnu_void_ptr)
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
} else if (PointeeTy->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex->getType() << lex->getSourceRange();
+ << lex.get()->getType() << lex.get()->getSourceRange();
return QualType();
}
// GNU extension: arithmetic on pointer to function
Diag(Loc, diag::ext_gnu_ptr_func_arith)
- << lex->getType() << lex->getSourceRange();
+ << lex.get()->getType() << lex.get()->getSourceRange();
} else {
// Check if we require a complete type.
if (((PExp->getType()->isPointerType() &&
@@ -6476,9 +6958,9 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
}
if (CompLHSTy) {
- QualType LHSTy = Context.isPromotableBitField(lex);
+ QualType LHSTy = Context.isPromotableBitField(lex.get());
if (LHSTy.isNull()) {
- LHSTy = lex->getType();
+ LHSTy = lex.get()->getType();
if (LHSTy->isPromotableIntegerType())
LHSTy = Context.getPromotedIntegerType(LHSTy);
}
@@ -6492,28 +6974,30 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
}
// C99 6.5.6
-QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
+QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
SourceLocation Loc, QualType* CompLHSTy) {
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
+ if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(Loc, lex, rex);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy);
+ if (lex.isInvalid() || rex.isInvalid())
+ return QualType();
// Enforce type constraints: C99 6.5.6p3.
// Handle the common case first (both operands are arithmetic).
- if (lex->getType()->isArithmeticType()
- && rex->getType()->isArithmeticType()) {
+ if (lex.get()->getType()->isArithmeticType() &&
+ rex.get()->getType()->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
// Either ptr - int or ptr - ptr.
- if (lex->getType()->isAnyPointerType()) {
- QualType lpointee = lex->getType()->getPointeeType();
+ if (lex.get()->getType()->isAnyPointerType()) {
+ QualType lpointee = lex.get()->getType()->getPointeeType();
// The LHS must be an completely-defined object type.
@@ -6522,7 +7006,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
if (lpointee->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
@@ -6531,42 +7015,42 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
} else if (lpointee->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << lex->getType() << lex->getSourceRange();
+ << lex.get()->getType() << lex.get()->getSourceRange();
return QualType();
}
// GNU C extension: arithmetic on pointer to function
- ComplainAboutFunc = lex;
+ ComplainAboutFunc = lex.get();
} else if (!lpointee->isDependentType() &&
RequireCompleteType(Loc, lpointee,
PDiag(diag::err_typecheck_sub_ptr_object)
- << lex->getSourceRange()
- << lex->getType()))
+ << lex.get()->getSourceRange()
+ << lex.get()->getType()))
return QualType();
// Diagnose bad cases where we step over interface counts.
if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface)
- << lpointee << lex->getSourceRange();
+ << lpointee << lex.get()->getSourceRange();
return QualType();
}
// The result type of a pointer-int computation is the pointer type.
- if (rex->getType()->isIntegerType()) {
+ if (rex.get()->getType()->isIntegerType()) {
if (ComplainAboutVoid)
Diag(Loc, diag::ext_gnu_void_ptr)
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
- if (CompLHSTy) *CompLHSTy = lex->getType();
- return lex->getType();
+ if (CompLHSTy) *CompLHSTy = lex.get()->getType();
+ return lex.get()->getType();
}
// Handle pointer-pointer subtractions.
- if (const PointerType *RHSPTy = rex->getType()->getAs<PointerType>()) {
+ if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
// RHS must be a completely-type object type.
@@ -6574,7 +7058,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
if (rpointee->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
@@ -6582,26 +7066,26 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
} else if (rpointee->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
- << rex->getType() << rex->getSourceRange();
+ << rex.get()->getType() << rex.get()->getSourceRange();
return QualType();
}
// GNU extension: arithmetic on pointer to function
if (!ComplainAboutFunc)
- ComplainAboutFunc = rex;
+ ComplainAboutFunc = rex.get();
} else if (!rpointee->isDependentType() &&
RequireCompleteType(Loc, rpointee,
PDiag(diag::err_typecheck_sub_ptr_object)
- << rex->getSourceRange()
- << rex->getType()))
+ << rex.get()->getSourceRange()
+ << rex.get()->getType()))
return QualType();
if (getLangOptions().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getType() << rex.get()->getType()
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
} else {
@@ -6610,21 +7094,21 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex,
Context.getCanonicalType(lpointee).getUnqualifiedType(),
Context.getCanonicalType(rpointee).getUnqualifiedType())) {
Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getType() << rex.get()->getType()
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
}
if (ComplainAboutVoid)
Diag(Loc, diag::ext_gnu_void_ptr)
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
- if (CompLHSTy) *CompLHSTy = lex->getType();
+ if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return Context.getPointerDiffType();
}
}
@@ -6638,22 +7122,26 @@ static bool isScopedEnumerationType(QualType T) {
return false;
}
-static void DiagnoseBadShiftValues(Sema& S, Expr *&lex, Expr *&rex,
+static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex,
SourceLocation Loc, unsigned Opc,
QualType LHSTy) {
llvm::APSInt Right;
// Check right/shifter operand
- if (rex->isValueDependent() || !rex->isIntegerConstantExpr(Right, S.Context))
+ if (rex.get()->isValueDependent() || !rex.get()->isIntegerConstantExpr(Right, S.Context))
return;
if (Right.isNegative()) {
- S.Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange();
+ S.DiagRuntimeBehavior(Loc, rex.get(),
+ S.PDiag(diag::warn_shift_negative)
+ << rex.get()->getSourceRange());
return;
}
llvm::APInt LeftBits(Right.getBitWidth(),
- S.Context.getTypeSize(lex->getType()));
+ S.Context.getTypeSize(lex.get()->getType()));
if (Right.uge(LeftBits)) {
- S.Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange();
+ S.DiagRuntimeBehavior(Loc, rex.get(),
+ S.PDiag(diag::warn_shift_gt_typewidth)
+ << rex.get()->getSourceRange());
return;
}
if (Opc != BO_Shl)
@@ -6664,7 +7152,7 @@ static void DiagnoseBadShiftValues(Sema& S, Expr *&lex, Expr *&rex,
// integers have defined behavior modulo one more than the maximum value
// representable in the result type, so never warn for those.
llvm::APSInt Left;
- if (lex->isValueDependent() || !lex->isIntegerConstantExpr(Left, S.Context) ||
+ if (lex.get()->isValueDependent() || !lex.get()->isIntegerConstantExpr(Left, S.Context) ||
LHSTy->hasUnsignedIntegerRepresentation())
return;
llvm::APInt ResultBits =
@@ -6681,32 +7169,32 @@ static void DiagnoseBadShiftValues(Sema& S, Expr *&lex, Expr *&rex,
if (LeftBits == ResultBits - 1) {
S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit)
<< Result.toString(10) << LHSTy
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return;
}
S.Diag(Loc, diag::warn_shift_result_gt_typewidth)
<< Result.toString(10) << Result.getMinSignedBits() << LHSTy
- << Left.getBitWidth() << lex->getSourceRange() << rex->getSourceRange();
+ << Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
// C99 6.5.7
-QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
+QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc,
unsigned Opc, bool isCompAssign) {
// C99 6.5.7p2: Each of the operands shall have integer type.
- if (!lex->getType()->hasIntegerRepresentation() ||
- !rex->getType()->hasIntegerRepresentation())
+ if (!lex.get()->getType()->hasIntegerRepresentation() ||
+ !rex.get()->getType()->hasIntegerRepresentation())
return InvalidOperands(Loc, lex, rex);
// C++0x: Don't allow scoped enums. FIXME: Use something better than
// hasIntegerRepresentation() above instead of this.
- if (isScopedEnumerationType(lex->getType()) ||
- isScopedEnumerationType(rex->getType())) {
+ if (isScopedEnumerationType(lex.get()->getType()) ||
+ isScopedEnumerationType(rex.get()->getType())) {
return InvalidOperands(Loc, lex, rex);
}
// Vector shifts promote their scalar inputs to vector type.
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
+ if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
// Shifts don't perform usual arithmetic conversions, they just do integer
@@ -6714,13 +7202,17 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// For the LHS, do usual unary conversions, but then reset them away
// if this is a compound assignment.
- Expr *old_lex = lex;
- UsualUnaryConversions(lex);
- QualType LHSTy = lex->getType();
+ ExprResult old_lex = lex;
+ lex = UsualUnaryConversions(lex.take());
+ if (lex.isInvalid())
+ return QualType();
+ QualType LHSTy = lex.get()->getType();
if (isCompAssign) lex = old_lex;
// The RHS is simpler.
- UsualUnaryConversions(rex);
+ rex = UsualUnaryConversions(rex.take());
+ if (rex.isInvalid())
+ return QualType();
// Sanity-check shift operands
DiagnoseBadShiftValues(*this, lex, rex, Loc, Opc, LHSTy);
@@ -6740,22 +7232,24 @@ static bool IsWithinTemplateSpecialization(Decl *D) {
}
// C99 6.5.8, C++ [expr.rel]
-QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
+QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc,
unsigned OpaqueOpc, bool isRelational) {
BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc;
// Handle vector comparisons separately.
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
+ if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType())
return CheckVectorCompareOperands(lex, rex, Loc, isRelational);
- QualType lType = lex->getType();
- QualType rType = rex->getType();
-
- Expr *LHSStripped = lex->IgnoreParenImpCasts();
- Expr *RHSStripped = rex->IgnoreParenImpCasts();
+ QualType lType = lex.get()->getType();
+ QualType rType = rex.get()->getType();
+
+ Expr *LHSStripped = lex.get()->IgnoreParenImpCasts();
+ Expr *RHSStripped = rex.get()->IgnoreParenImpCasts();
QualType LHSStrippedType = LHSStripped->getType();
QualType RHSStrippedType = RHSStripped->getType();
+
+
// Two different enums will raise a warning when compared.
if (const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>()) {
if (const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>()) {
@@ -6764,15 +7258,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
!Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) {
Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
<< LHSStrippedType << RHSStrippedType
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
}
}
if (!lType->hasFloatingRepresentation() &&
!(lType->isBlockPointerType() && isRelational) &&
- !lex->getLocStart().isMacroID() &&
- !rex->getLocStart().isMacroID()) {
+ !lex.get()->getLocStart().isMacroID() &&
+ !rex.get()->getLocStart().isMacroID()) {
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
@@ -6828,13 +7322,13 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
!RHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- literalString = lex;
+ literalString = lex.get();
literalStringStripped = LHSStripped;
} else if ((isa<StringLiteral>(RHSStripped) ||
isa<ObjCEncodeExpr>(RHSStripped)) &&
!LHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- literalString = rex;
+ literalString = rex.get();
literalStringStripped = RHSStripped;
}
@@ -6858,15 +7352,23 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
}
// C99 6.5.8p3 / C99 6.5.9p4
- if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
+ if (lex.get()->getType()->isArithmeticType() && rex.get()->getType()->isArithmeticType()) {
UsualArithmeticConversions(lex, rex);
+ if (lex.isInvalid() || rex.isInvalid())
+ return QualType();
+ }
else {
- UsualUnaryConversions(lex);
- UsualUnaryConversions(rex);
+ lex = UsualUnaryConversions(lex.take());
+ if (lex.isInvalid())
+ return QualType();
+
+ rex = UsualUnaryConversions(rex.take());
+ if (rex.isInvalid())
+ return QualType();
}
- lType = lex->getType();
- rType = rex->getType();
+ lType = lex.get()->getType();
+ rType = rex.get()->getType();
// The result of comparisons is 'bool' in C++, 'int' in C.
QualType ResultTy = Context.getLogicalOperationType();
@@ -6877,15 +7379,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
} else {
// Check for comparisons of floating point operands using != and ==.
if (lType->hasFloatingRepresentation())
- CheckFloatComparison(Loc,lex,rex);
+ CheckFloatComparison(Loc, lex.get(), rex.get());
if (lType->isArithmeticType() && rType->isArithmeticType())
return ResultTy;
}
- bool LHSIsNull = lex->isNullPointerConstant(Context,
+ bool LHSIsNull = lex.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
- bool RHSIsNull = rex->isNullPointerConstant(Context,
+ bool RHSIsNull = rex.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
// All of the following pointer-related warnings are GCC extensions, except
@@ -6911,12 +7413,12 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
isSFINAEContext()?
diag::err_typecheck_comparison_of_fptr_to_void
: diag::ext_typecheck_comparison_of_fptr_to_void)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
if (isSFINAEContext())
return QualType();
- ImpCastExprToType(rex, lType, CK_BitCast);
+ rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
return ResultTy;
}
}
@@ -6934,17 +7436,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
} else if (NonStandardCompositeType) {
Diag(Loc,
diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
<< lType << rType << T
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
- ImpCastExprToType(lex, T, CK_BitCast);
- ImpCastExprToType(rex, T, CK_BitCast);
+ lex = ImpCastExprToType(lex.take(), T, CK_BitCast);
+ rex = ImpCastExprToType(rex.take(), T, CK_BitCast);
return ResultTy;
}
// C99 6.5.9p2 and C99 6.5.8p2
@@ -6953,7 +7455,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// Valid unless a relational comparison of function pointers
if (isRelational && LCanPointeeTy->isFunctionType()) {
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
} else if (!isRelational &&
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
@@ -6961,15 +7463,19 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
&& !LHSIsNull && !RHSIsNull) {
Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
} else {
// Invalid
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ }
+ if (LCanPointeeTy != RCanPointeeTy) {
+ if (LHSIsNull && !RHSIsNull)
+ lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ else
+ rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
}
- if (LCanPointeeTy != RCanPointeeTy)
- ImpCastExprToType(rex, lType, CK_BitCast);
return ResultTy;
}
@@ -6983,7 +7489,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (RHSIsNull &&
((lType->isPointerType() || lType->isNullPtrType()) ||
(!isRelational && lType->isMemberPointerType()))) {
- ImpCastExprToType(rex, lType,
+ rex = ImpCastExprToType(rex.take(), lType,
lType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
@@ -6992,7 +7498,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (LHSIsNull &&
((rType->isPointerType() || rType->isNullPtrType()) ||
(!isRelational && rType->isMemberPointerType()))) {
- ImpCastExprToType(lex, rType,
+ lex = ImpCastExprToType(lex.take(), rType,
rType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
@@ -7017,19 +7523,25 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
} else if (NonStandardCompositeType) {
Diag(Loc,
diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
<< lType << rType << T
- << lex->getSourceRange() << rex->getSourceRange();
+ << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
- ImpCastExprToType(lex, T, CK_BitCast);
- ImpCastExprToType(rex, T, CK_BitCast);
+ lex = ImpCastExprToType(lex.take(), T, CK_BitCast);
+ rex = ImpCastExprToType(rex.take(), T, CK_BitCast);
return ResultTy;
}
+
+ // Handle scoped enumeration types specifically, since they don't promote
+ // to integers.
+ if (lex.get()->getType()->isEnumeralType() &&
+ Context.hasSameUnqualifiedType(lex.get()->getType(), rex.get()->getType()))
+ return ResultTy;
}
// Handle block pointer types.
@@ -7040,49 +7552,57 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (!LHSIsNull && !RHSIsNull &&
!Context.typesAreCompatible(lpointee, rpointee)) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
- ImpCastExprToType(rex, lType, CK_BitCast);
+ rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
return ResultTy;
}
+
// Allow block pointers to be compared with null pointer constants.
if (!isRelational
&& ((lType->isBlockPointerType() && rType->isPointerType())
|| (lType->isPointerType() && rType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
- if (!((rType->isPointerType() && rType->getAs<PointerType>()
+ if (!((rType->isPointerType() && rType->castAs<PointerType>()
->getPointeeType()->isVoidType())
- || (lType->isPointerType() && lType->getAs<PointerType>()
+ || (lType->isPointerType() && lType->castAs<PointerType>()
->getPointeeType()->isVoidType())))
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
- ImpCastExprToType(rex, lType, CK_BitCast);
+ if (LHSIsNull && !RHSIsNull)
+ lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ else
+ rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
return ResultTy;
}
- if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) {
- if (lType->isPointerType() || rType->isPointerType()) {
- const PointerType *LPT = lType->getAs<PointerType>();
- const PointerType *RPT = rType->getAs<PointerType>();
- bool LPtrToVoid = LPT ?
- Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false;
- bool RPtrToVoid = RPT ?
- Context.getCanonicalType(RPT->getPointeeType())->isVoidType() : false;
+ if (lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType()) {
+ const PointerType *LPT = lType->getAs<PointerType>();
+ const PointerType *RPT = rType->getAs<PointerType>();
+ if (LPT || RPT) {
+ bool LPtrToVoid = LPT ? LPT->getPointeeType()->isVoidType() : false;
+ bool RPtrToVoid = RPT ? RPT->getPointeeType()->isVoidType() : false;
if (!LPtrToVoid && !RPtrToVoid &&
!Context.typesAreCompatible(lType, rType)) {
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
}
- ImpCastExprToType(rex, lType, CK_BitCast);
+ if (LHSIsNull && !RHSIsNull)
+ lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ else
+ rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
return ResultTy;
}
if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) {
if (!Context.areComparableObjCPointerTypes(lType, rType))
Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
- ImpCastExprToType(rex, lType, CK_BitCast);
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
+ if (LHSIsNull && !RHSIsNull)
+ lex = ImpCastExprToType(lex.take(), rType, CK_BitCast);
+ else
+ rex = ImpCastExprToType(rex.take(), lType, CK_BitCast);
return ResultTy;
}
}
@@ -7104,16 +7624,16 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (DiagID) {
Diag(Loc, DiagID)
- << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+ << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange();
if (isError)
return QualType();
}
if (lType->isIntegerType())
- ImpCastExprToType(lex, rType,
+ lex = ImpCastExprToType(lex.take(), rType,
LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
else
- ImpCastExprToType(rex, lType,
+ rex = ImpCastExprToType(rex.take(), lType,
RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
return ResultTy;
}
@@ -7121,14 +7641,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// Handle block pointers.
if (!isRelational && RHSIsNull
&& lType->isBlockPointerType() && rType->isIntegerType()) {
- ImpCastExprToType(rex, lType, CK_NullToPointer);
+ rex = ImpCastExprToType(rex.take(), lType, CK_NullToPointer);
return ResultTy;
}
if (!isRelational && LHSIsNull
&& lType->isIntegerType() && rType->isBlockPointerType()) {
- ImpCastExprToType(lex, rType, CK_NullToPointer);
+ lex = ImpCastExprToType(lex.take(), rType, CK_NullToPointer);
return ResultTy;
}
+
return InvalidOperands(Loc, lex, rex);
}
@@ -7136,7 +7657,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
/// operates on extended vector types. Instead of producing an IntTy result,
/// like a scalar comparison, a vector comparison produces a vector of integer
/// types.
-QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
+QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex,
SourceLocation Loc,
bool isRelational) {
// Check to make sure we're operating on vectors of the same type and width,
@@ -7145,20 +7666,20 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
if (vType.isNull())
return vType;
+ QualType lType = lex.get()->getType();
+ QualType rType = rex.get()->getType();
+
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
- if (getLangOptions().AltiVec)
+ if (vType->getAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector)
return Context.getLogicalOperationType();
- QualType lType = lex->getType();
- QualType rType = rex->getType();
-
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
if (!lType->hasFloatingRepresentation()) {
- if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
- if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
+ if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex.get()->IgnoreParens()))
+ if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex.get()->IgnoreParens()))
if (DRL->getDecl() == DRR->getDecl())
DiagRuntimeBehavior(Loc, 0,
PDiag(diag::warn_comparison_always)
@@ -7170,7 +7691,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
// Check for comparisons of floating point operands using != and ==.
if (!isRelational && lType->hasFloatingRepresentation()) {
assert (rType->hasFloatingRepresentation());
- CheckFloatComparison(Loc,lex,rex);
+ CheckFloatComparison(Loc, lex.get(), rex.get());
}
// Return the type for the comparison, which is the same as vector type for
@@ -7192,51 +7713,61 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
}
inline QualType Sema::CheckBitwiseOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
- if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
- if (lex->getType()->hasIntegerRepresentation() &&
- rex->getType()->hasIntegerRepresentation())
+ ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) {
+ if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
+ if (lex.get()->getType()->hasIntegerRepresentation() &&
+ rex.get()->getType()->hasIntegerRepresentation())
return CheckVectorOperands(Loc, lex, rex);
return InvalidOperands(Loc, lex, rex);
}
- QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+ ExprResult lexResult = Owned(lex), rexResult = Owned(rex);
+ QualType compType = UsualArithmeticConversions(lexResult, rexResult, isCompAssign);
+ if (lexResult.isInvalid() || rexResult.isInvalid())
+ return QualType();
+ lex = lexResult.take();
+ rex = rexResult.take();
- if (lex->getType()->isIntegralOrUnscopedEnumerationType() &&
- rex->getType()->isIntegralOrUnscopedEnumerationType())
+ if (lex.get()->getType()->isIntegralOrUnscopedEnumerationType() &&
+ rex.get()->getType()->isIntegralOrUnscopedEnumerationType())
return compType;
return InvalidOperands(Loc, lex, rex);
}
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
- Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned Opc) {
+ ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned Opc) {
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
- if (lex->getType()->isIntegerType() && !lex->getType()->isBooleanType() &&
- rex->getType()->isIntegerType() && !rex->isValueDependent() &&
+ if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() &&
+ rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() &&
// Don't warn in macros.
!Loc.isMacroID()) {
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
Expr::EvalResult Result;
- if (rex->Evaluate(Result, Context) && !Result.HasSideEffects &&
+ if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects &&
Result.Val.getInt() != 0 && Result.Val.getInt() != 1) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
- << rex->getSourceRange()
+ << rex.get()->getSourceRange()
<< (Opc == BO_LAnd ? "&&" : "||")
<< (Opc == BO_LAnd ? "&" : "|");
}
}
if (!Context.getLangOptions().CPlusPlus) {
- UsualUnaryConversions(lex);
- UsualUnaryConversions(rex);
+ lex = UsualUnaryConversions(lex.take());
+ if (lex.isInvalid())
+ return QualType();
+
+ rex = UsualUnaryConversions(rex.take());
+ if (rex.isInvalid())
+ return QualType();
- if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType())
+ if (!lex.get()->getType()->isScalarType() || !rex.get()->getType()->isScalarType())
return InvalidOperands(Loc, lex, rex);
return Context.IntTy;
@@ -7248,9 +7779,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// C++ [expr.log.and]p1
// C++ [expr.log.or]p1
// The operands are both contextually converted to type bool.
- if (PerformContextuallyConvertToBool(lex) ||
- PerformContextuallyConvertToBool(rex))
+ ExprResult lexRes = PerformContextuallyConvertToBool(lex.get());
+ if (lexRes.isInvalid())
+ return InvalidOperands(Loc, lex, rex);
+ lex = move(lexRes);
+
+ ExprResult rexRes = PerformContextuallyConvertToBool(rex.get());
+ if (rexRes.isInvalid())
return InvalidOperands(Loc, lex, rex);
+ rex = move(rexRes);
// C++ [expr.log.and]p2
// C++ [expr.log.or]p2
@@ -7281,6 +7818,35 @@ static bool IsReadonlyProperty(Expr *E, Sema &S) {
return false;
}
+static bool IsConstProperty(Expr *E, Sema &S) {
+ if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
+ const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
+ if (PropExpr->isImplicitProperty()) return false;
+
+ ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
+ QualType T = PDecl->getType();
+ if (T->isReferenceType())
+ T = T->getAs<ReferenceType>()->getPointeeType();
+ CanQualType CT = S.Context.getCanonicalType(T);
+ return CT.isConstQualified();
+ }
+ return false;
+}
+
+static bool IsReadonlyMessage(Expr *E, Sema &S) {
+ if (E->getStmtClass() != Expr::MemberExprClass)
+ return false;
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ NamedDecl *Member = ME->getMemberDecl();
+ if (isa<FieldDecl>(Member)) {
+ Expr *Base = ME->getBase()->IgnoreParenImpCasts();
+ if (Base->getStmtClass() != Expr::ObjCMessageExprClass)
+ return false;
+ return cast<ObjCMessageExpr>(Base)->getMethodDecl() != 0;
+ }
+ return false;
+}
+
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
@@ -7289,6 +7855,10 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
&Loc);
if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
IsLV = Expr::MLV_ReadonlyProperty;
+ else if (Expr::MLV_ConstQualified && IsConstProperty(E, S))
+ IsLV = Expr::MLV_Valid;
+ else if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S))
+ IsLV = Expr::MLV_InvalidMessageExpression;
if (IsLV == Expr::MLV_Valid)
return false;
@@ -7331,6 +7901,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_NoSetterProperty:
Diag = diag::error_nosetter_property_assignment;
break;
+ case Expr::MLV_InvalidMessageExpression:
+ Diag = diag::error_readonly_message_assignment;
+ break;
case Expr::MLV_SubObjCPropertySetting:
Diag = diag::error_no_subobject_property_setting;
break;
@@ -7349,7 +7922,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
// C99 6.5.16.1
-QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
+QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS,
SourceLocation Loc,
QualType CompoundType) {
// Verify that LHS is a modifiable lvalue, and emit error if not.
@@ -7357,14 +7930,21 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
return QualType();
QualType LHSType = LHS->getType();
- QualType RHSType = CompoundType.isNull() ? RHS->getType() : CompoundType;
+ QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType;
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
QualType LHSTy(LHSType);
// Simple assignment "x = y".
- if (LHS->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForLValue(LHS, RHS, LHSTy);
+ if (LHS->getObjectKind() == OK_ObjCProperty) {
+ ExprResult LHSResult = Owned(LHS);
+ ConvertPropertyForLValue(LHSResult, RHS, LHSTy);
+ if (LHSResult.isInvalid())
+ return QualType();
+ LHS = LHSResult.take();
+ }
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
+ if (RHS.isInvalid())
+ return QualType();
// Special case of NSObject attributes on c-style pointer types.
if (ConvTy == IncompatiblePointer &&
((Context.isObjCNSObjectType(LHSType) &&
@@ -7382,7 +7962,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
// If the RHS is a unary plus or minus, check to see if they = and + are
// right next to each other. If so, the user may have typo'd "x =+ 4"
// instead of "x += 4".
- Expr *RHSCheck = RHS;
+ Expr *RHSCheck = RHS.get();
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RHSCheck))
RHSCheck = ICE->getSubExpr();
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(RHSCheck)) {
@@ -7406,32 +7986,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
}
if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType,
- RHS, AA_Assigning))
+ RHS.get(), AA_Assigning))
return QualType();
-
- // Check to see if the destination operand is a dereferenced null pointer. If
- // so, and if not volatile-qualified, this is undefined behavior that the
- // optimizer will delete, so warn about it. People sometimes try to use this
- // to get a deterministic trap and are surprised by clang's behavior. This
- // only handles the pattern "*null = whatever", which is a very syntactic
- // check.
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(LHS->IgnoreParenCasts()))
- if (UO->getOpcode() == UO_Deref &&
- UO->getSubExpr()->IgnoreParenCasts()->
- isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) &&
- !UO->getType().isVolatileQualified()) {
- DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
- PDiag(diag::warn_indirection_through_null)
- << UO->getSubExpr()->getSourceRange());
- DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
- PDiag(diag::note_indirection_through_null));
- }
-
+ CheckForNullPointerDereference(*this, LHS);
// Check for trivial buffer overflows.
- if (const ArraySubscriptExpr *ae
- = dyn_cast<ArraySubscriptExpr>(LHS->IgnoreParenCasts()))
- CheckArrayAccess(ae);
+ CheckArrayAccess(LHS->IgnoreParenCasts());
// C99 6.5.16p3: The type of an assignment expression is the type of the
// left operand unless the left operand has qualified type, in which case
@@ -7445,34 +8005,34 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
}
// C99 6.5.17
-static QualType CheckCommaOperands(Sema &S, Expr *&LHS, Expr *&RHS,
+static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
- S.DiagnoseUnusedExprResult(LHS);
+ S.DiagnoseUnusedExprResult(LHS.get());
- ExprResult LHSResult = S.CheckPlaceholderExpr(LHS, Loc);
- if (LHSResult.isInvalid())
+ LHS = S.CheckPlaceholderExpr(LHS.take());
+ RHS = S.CheckPlaceholderExpr(RHS.take());
+ if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- ExprResult RHSResult = S.CheckPlaceholderExpr(RHS, Loc);
- if (RHSResult.isInvalid())
- return QualType();
- RHS = RHSResult.take();
-
// C's comma performs lvalue conversion (C99 6.3.2.1) on both its
// operands, but not unary promotions.
// C++'s comma does not do any conversions at all (C++ [expr.comma]p1).
// So we treat the LHS as a ignored value, and in C++ we allow the
// containing site to determine what should be done with the RHS.
- S.IgnoredValueConversions(LHS);
+ LHS = S.IgnoredValueConversions(LHS.take());
+ if (LHS.isInvalid())
+ return QualType();
if (!S.getLangOptions().CPlusPlus) {
- S.DefaultFunctionArrayLvalueConversion(RHS);
- if (!RHS->getType()->isVoidType())
- S.RequireCompleteType(Loc, RHS->getType(), diag::err_incomplete_type);
+ RHS = S.DefaultFunctionArrayLvalueConversion(RHS.take());
+ if (RHS.isInvalid())
+ return QualType();
+ if (!RHS.get()->getType()->isVoidType())
+ S.RequireCompleteType(Loc, RHS.get()->getType(), diag::err_incomplete_type);
}
- return RHS->getType();
+ return RHS.get()->getType();
}
/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine
@@ -7535,7 +8095,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
S.Diag(OpLoc, diag::ext_integer_increment_complex)
<< ResType << Op->getSourceRange();
} else if (ResType->isPlaceholderType()) {
- ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc);
+ ExprResult PR = S.CheckPlaceholderExpr(Op);
if (PR.isInvalid()) return QualType();
return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc,
isInc, isPrefix);
@@ -7562,7 +8122,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
}
}
-void Sema::ConvertPropertyForRValue(Expr *&E) {
+ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
assert(E->getValueKind() == VK_LValue &&
E->getObjectKind() == OK_ObjCProperty);
const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
@@ -7586,28 +8146,30 @@ void Sema::ConvertPropertyForRValue(Expr *&E) {
ExprResult Result = MaybeBindToTemporary(E);
if (!Result.isInvalid())
E = Result.take();
+
+ return Owned(E);
}
-void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) {
- assert(LHS->getValueKind() == VK_LValue &&
- LHS->getObjectKind() == OK_ObjCProperty);
- const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty();
+void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &LHSTy) {
+ assert(LHS.get()->getValueKind() == VK_LValue &&
+ LHS.get()->getObjectKind() == OK_ObjCProperty);
+ const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
- if (PRE->isImplicitProperty()) {
+ if (PropRef->isImplicitProperty()) {
// If using property-dot syntax notation for assignment, and there is a
// setter, RHS expression is being passed to the setter argument. So,
// type conversion (and comparison) is RHS to setter's argument type.
- if (const ObjCMethodDecl *SetterMD = PRE->getImplicitPropertySetter()) {
+ if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
LHSTy = (*P)->getType();
// Otherwise, if the getter returns an l-value, just call that.
} else {
- QualType Result = PRE->getImplicitPropertyGetter()->getResultType();
+ QualType Result = PropRef->getImplicitPropertyGetter()->getResultType();
ExprValueKind VK = Expr::getValueKindForType(Result);
if (VK == VK_LValue) {
- LHS = ImplicitCastExpr::Create(Context, LHS->getType(),
- CK_GetObjCProperty, LHS, 0, VK);
+ LHS = ImplicitCastExpr::Create(Context, LHS.get()->getType(),
+ CK_GetObjCProperty, LHS.take(), 0, VK);
return;
}
}
@@ -7616,11 +8178,9 @@ void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) {
if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) {
InitializedEntity Entity =
InitializedEntity::InitializeParameter(Context, LHSTy);
- Expr *Arg = RHS;
- ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(),
- Owned(Arg));
+ ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
if (!ArgE.isInvalid())
- RHS = ArgE.takeAs<Expr>();
+ RHS = ArgE;
}
}
@@ -7695,10 +8255,15 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
return S.Context.DependentTy;
if (OrigOp->getType() == S.Context.OverloadTy)
return S.Context.OverloadTy;
+ if (OrigOp->getType() == S.Context.UnknownAnyTy)
+ return S.Context.UnknownAnyTy;
+ if (OrigOp->getType() == S.Context.BoundMemberTy) {
+ S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+ << OrigOp->getSourceRange();
+ return QualType();
+ }
- ExprResult PR = S.CheckPlaceholderExpr(OrigOp, OpLoc);
- if (PR.isInvalid()) return QualType();
- OrigOp = PR.take();
+ assert(!OrigOp->getType()->isPlaceholderType());
// Make sure to ignore parentheses in subsequent checks
Expr *op = OrigOp->IgnoreParens();
@@ -7717,7 +8282,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
ValueDecl *dcl = getPrimaryDecl(op);
Expr::LValueClassification lval = op->ClassifyLValue(S.Context);
- if (lval == Expr::LV_ClassTemporary) {
+ if (lval == Expr::LV_ClassTemporary) {
bool sfinae = S.isSFINAEContext();
S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary
: diag::ext_typecheck_addrof_class_temporary)
@@ -7833,7 +8398,10 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
if (Op->isTypeDependent())
return S.Context.DependentTy;
- S.UsualUnaryConversions(Op);
+ ExprResult ConvResult = S.UsualUnaryConversions(Op);
+ if (ConvResult.isInvalid())
+ return QualType();
+ Op = ConvResult.take();
QualType OpTy = Op->getType();
QualType Result;
@@ -7847,7 +8415,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
OpTy->getAs<ObjCObjectPointerType>())
Result = OPT->getPointeeType();
else {
- ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc);
+ ExprResult PR = S.CheckPlaceholderExpr(Op);
if (PR.isInvalid()) return QualType();
if (PR.take() != Op)
return CheckIndirectionOperand(S, PR.take(), VK, OpLoc);
@@ -7970,7 +8538,8 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs,
/// built-in operations; ActOnBinOp handles overloaded operators.
ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
- Expr *lhs, Expr *rhs) {
+ Expr *lhsExpr, Expr *rhsExpr) {
+ ExprResult lhs = Owned(lhsExpr), rhs = Owned(rhsExpr);
QualType ResultTy; // Result type of the binary operator.
// The following two variables are used for compound assignment operators
QualType CompLHSTy; // Type of LHS after promotions for computation
@@ -7978,16 +8547,33 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
+ // Check if a 'foo<int>' involved in a binary op, identifies a single
+ // function unambiguously (i.e. an lvalue ala 13.4)
+ // But since an assignment can trigger target based overload, exclude it in
+ // our blind search. i.e:
+ // template<class T> void f(); template<class T, class U> void f(U);
+ // f<int> == 0; // resolve f<int> blindly
+ // void (*p)(int); p = f<int>; // resolve f<int> using target
+ if (Opc != BO_Assign) {
+ ExprResult resolvedLHS = CheckPlaceholderExpr(lhs.get());
+ if (!resolvedLHS.isUsable()) return ExprError();
+ lhs = move(resolvedLHS);
+
+ ExprResult resolvedRHS = CheckPlaceholderExpr(rhs.get());
+ if (!resolvedRHS.isUsable()) return ExprError();
+ rhs = move(resolvedRHS);
+ }
+
switch (Opc) {
case BO_Assign:
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType());
+ ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType());
if (getLangOptions().CPlusPlus &&
- lhs->getObjectKind() != OK_ObjCProperty) {
- VK = lhs->getValueKind();
- OK = lhs->getObjectKind();
+ lhs.get()->getObjectKind() != OK_ObjCProperty) {
+ VK = lhs.get()->getValueKind();
+ OK = lhs.get()->getObjectKind();
}
if (!ResultTy.isNull())
- DiagnoseSelfAssignment(*this, lhs, rhs, OpLoc);
+ DiagnoseSelfAssignment(*this, lhs.get(), rhs.get(), OpLoc);
break;
case BO_PtrMemD:
case BO_PtrMemI:
@@ -8036,60 +8622,59 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true,
Opc == BO_DivAssign);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
+ ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
break;
case BO_RemAssign:
CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
+ ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
break;
case BO_AddAssign:
CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy);
- if (!CompResultTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
+ ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
break;
case BO_SubAssign:
CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy);
- if (!CompResultTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
+ ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
break;
case BO_ShlAssign:
case BO_ShrAssign:
CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc, true);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
+ ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
break;
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true);
CompLHSTy = CompResultTy;
- if (!CompResultTy.isNull())
- ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
+ if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid())
+ ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy);
break;
case BO_Comma:
ResultTy = CheckCommaOperands(*this, lhs, rhs, OpLoc);
- if (getLangOptions().CPlusPlus) {
- VK = rhs->getValueKind();
- OK = rhs->getObjectKind();
+ if (getLangOptions().CPlusPlus && !rhs.isInvalid()) {
+ VK = rhs.get()->getValueKind();
+ OK = rhs.get()->getObjectKind();
}
break;
}
- if (ResultTy.isNull())
+ if (ResultTy.isNull() || lhs.isInvalid() || rhs.isInvalid())
return ExprError();
if (CompResultTy.isNull())
- return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy,
- VK, OK, OpLoc));
-
- if (getLangOptions().CPlusPlus && lhs->getObjectKind() != OK_ObjCProperty) {
+ return Owned(new (Context) BinaryOperator(lhs.take(), rhs.take(), Opc,
+ ResultTy, VK, OK, OpLoc));
+ if (getLangOptions().CPlusPlus && lhs.get()->getObjectKind() != OK_ObjCProperty) {
VK = VK_LValue;
- OK = lhs->getObjectKind();
+ OK = lhs.get()->getObjectKind();
}
- return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy,
- VK, OK, CompLHSTy,
+ return Owned(new (Context) CompoundAssignOperator(lhs.take(), rhs.take(), Opc,
+ ResultTy, VK, OK, CompLHSTy,
CompResultTy, OpLoc));
}
@@ -8161,23 +8746,23 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(lhs->getLocStart(), OpLoc)
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
- Self.PDiag(diag::note_precedence_bitwise_first)
- << BinOp::getOpcodeStr(Opc),
- SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()),
Self.PDiag(diag::note_precedence_bitwise_silence)
<< BinOp::getOpcodeStr(lhsopc),
- lhs->getSourceRange());
+ lhs->getSourceRange(),
+ Self.PDiag(diag::note_precedence_bitwise_first)
+ << BinOp::getOpcodeStr(Opc),
+ SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
else if (BinOp::isComparisonOp(rhsopc))
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(OpLoc, rhs->getLocEnd())
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
+ Self.PDiag(diag::note_precedence_bitwise_silence)
+ << BinOp::getOpcodeStr(rhsopc),
+ rhs->getSourceRange(),
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()),
- Self.PDiag(diag::note_precedence_bitwise_silence)
- << BinOp::getOpcodeStr(rhsopc),
- rhs->getSourceRange());
+ SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
}
/// \brief It accepts a '&&' expr that is inside a '||' one.
@@ -8185,14 +8770,13 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
/// in parentheses.
static void
EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
- Expr *E) {
- assert(isa<BinaryOperator>(E) &&
- cast<BinaryOperator>(E)->getOpcode() == BO_LAnd);
- SuggestParentheses(Self, OpLoc,
+ BinaryOperator *Bop) {
+ assert(Bop->getOpcode() == BO_LAnd);
+ SuggestParentheses(Self, Bop->getOperatorLoc(),
Self.PDiag(diag::warn_logical_and_in_logical_or)
- << E->getSourceRange(),
+ << Bop->getSourceRange() << OpLoc,
Self.PDiag(diag::note_logical_and_in_logical_or_silence),
- E->getSourceRange(),
+ Bop->getSourceRange(),
Self.PDiag(0), SourceRange());
}
@@ -8316,7 +8900,8 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
UnaryOperatorKind Opc,
- Expr *Input) {
+ Expr *InputExpr) {
+ ExprResult Input = Owned(InputExpr);
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
QualType resultType;
@@ -8325,23 +8910,28 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_PreDec:
case UO_PostInc:
case UO_PostDec:
- resultType = CheckIncrementDecrementOperand(*this, Input, VK, OpLoc,
+ resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OpLoc,
Opc == UO_PreInc ||
Opc == UO_PostInc,
Opc == UO_PreInc ||
Opc == UO_PreDec);
break;
case UO_AddrOf:
- resultType = CheckAddressOfOperand(*this, Input, OpLoc);
+ resultType = CheckAddressOfOperand(*this, Input.get(), OpLoc);
break;
- case UO_Deref:
- DefaultFunctionArrayLvalueConversion(Input);
- resultType = CheckIndirectionOperand(*this, Input, VK, OpLoc);
+ case UO_Deref: {
+ ExprResult resolved = CheckPlaceholderExpr(Input.get());
+ if (!resolved.isUsable()) return ExprError();
+ Input = move(resolved);
+ Input = DefaultFunctionArrayLvalueConversion(Input.take());
+ resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
break;
+ }
case UO_Plus:
case UO_Minus:
- UsualUnaryConversions(Input);
- resultType = Input->getType();
+ Input = UsualUnaryConversions(Input.take());
+ if (Input.isInvalid()) return ExprError();
+ resultType = Input.get()->getType();
if (resultType->isDependentType())
break;
if (resultType->isArithmeticType() || // C99 6.5.3.3p1
@@ -8355,49 +8945,59 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType->isPointerType())
break;
else if (resultType->isPlaceholderType()) {
- ExprResult PR = CheckPlaceholderExpr(Input, OpLoc);
- if (PR.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take());
+ Input = CheckPlaceholderExpr(Input.take());
+ if (Input.isInvalid()) return ExprError();
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
}
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
- << resultType << Input->getSourceRange());
+ << resultType << Input.get()->getSourceRange());
+
case UO_Not: // bitwise complement
- UsualUnaryConversions(Input);
- resultType = Input->getType();
+ Input = UsualUnaryConversions(Input.take());
+ if (Input.isInvalid()) return ExprError();
+ resultType = Input.get()->getType();
if (resultType->isDependentType())
break;
// C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
if (resultType->isComplexType() || resultType->isComplexIntegerType())
// C99 does not support '~' for complex conjugation.
Diag(OpLoc, diag::ext_integer_complement_complex)
- << resultType << Input->getSourceRange();
+ << resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
else if (resultType->isPlaceholderType()) {
- ExprResult PR = CheckPlaceholderExpr(Input, OpLoc);
- if (PR.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take());
+ Input = CheckPlaceholderExpr(Input.take());
+ if (Input.isInvalid()) return ExprError();
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
- << resultType << Input->getSourceRange());
+ << resultType << Input.get()->getSourceRange());
}
break;
+
case UO_LNot: // logical negation
// Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
- DefaultFunctionArrayLvalueConversion(Input);
- resultType = Input->getType();
+ Input = DefaultFunctionArrayLvalueConversion(Input.take());
+ if (Input.isInvalid()) return ExprError();
+ resultType = Input.get()->getType();
if (resultType->isDependentType())
break;
- if (resultType->isScalarType()) { // C99 6.5.3.3p1
- // ok, fallthrough
+ if (resultType->isScalarType()) {
+ // C99 6.5.3.3p1: ok, fallthrough;
+ if (Context.getLangOptions().CPlusPlus) {
+ // C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9:
+ // operand contextually converted to bool.
+ Input = ImpCastExprToType(Input.take(), Context.BoolTy,
+ ScalarTypeToBooleanCastKind(resultType));
+ }
} else if (resultType->isPlaceholderType()) {
- ExprResult PR = CheckPlaceholderExpr(Input, OpLoc);
- if (PR.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take());
+ Input = CheckPlaceholderExpr(Input.take());
+ if (Input.isInvalid()) return ExprError();
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
- << resultType << Input->getSourceRange());
+ << resultType << Input.get()->getSourceRange());
}
// LNot always has type int. C99 6.5.3.3p5.
@@ -8408,20 +9008,21 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Imag:
resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real);
// _Real and _Imag map ordinary l-values into ordinary l-values.
- if (Input->getValueKind() != VK_RValue &&
- Input->getObjectKind() == OK_Ordinary)
- VK = Input->getValueKind();
+ if (Input.isInvalid()) return ExprError();
+ if (Input.get()->getValueKind() != VK_RValue &&
+ Input.get()->getObjectKind() == OK_Ordinary)
+ VK = Input.get()->getValueKind();
break;
case UO_Extension:
- resultType = Input->getType();
- VK = Input->getValueKind();
- OK = Input->getObjectKind();
+ resultType = Input.get()->getType();
+ VK = Input.get()->getValueKind();
+ OK = Input.get()->getObjectKind();
break;
}
- if (resultType.isNull())
+ if (resultType.isNull() || Input.isInvalid())
return ExprError();
- return Owned(new (Context) UnaryOperator(Input, Opc, resultType,
+ return Owned(new (Context) UnaryOperator(Input.take(), Opc, resultType,
VK, OK, OpLoc));
}
@@ -8488,26 +9089,28 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
LastLabelStmt = Label;
LastStmt = Label->getSubStmt();
}
- if (Expr *LastExpr = dyn_cast<Expr>(LastStmt)) {
+ if (Expr *LastE = dyn_cast<Expr>(LastStmt)) {
// Do function/array conversion on the last expression, but not
// lvalue-to-rvalue. However, initialize an unqualified type.
- DefaultFunctionArrayConversion(LastExpr);
- Ty = LastExpr->getType().getUnqualifiedType();
+ ExprResult LastExpr = DefaultFunctionArrayConversion(LastE);
+ if (LastExpr.isInvalid())
+ return ExprError();
+ Ty = LastExpr.get()->getType().getUnqualifiedType();
- if (!Ty->isDependentType() && !LastExpr->isTypeDependent()) {
- ExprResult Res = PerformCopyInitialization(
+ if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) {
+ LastExpr = PerformCopyInitialization(
InitializedEntity::InitializeResult(LPLoc,
Ty,
false),
SourceLocation(),
- Owned(LastExpr));
- if (Res.isInvalid())
+ LastExpr);
+ if (LastExpr.isInvalid())
return ExprError();
- if ((LastExpr = Res.takeAs<Expr>())) {
+ if (LastExpr.get() != 0) {
if (!LastLabelStmt)
- Compound->setLastStmt(LastExpr);
+ Compound->setLastStmt(LastExpr.take());
else
- LastLabelStmt->setSubStmt(LastExpr);
+ LastLabelStmt->setSubStmt(LastExpr.take());
StmtExprMayBindToTemp = true;
}
}
@@ -8779,8 +9382,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// Check whether that explicit signature was synthesized by
// GetTypeForDeclarator. If so, don't save that as part of the
// written signature.
- if (ExplicitSignature.getLParenLoc() ==
- ExplicitSignature.getRParenLoc()) {
+ if (ExplicitSignature.getLocalRangeBegin() ==
+ ExplicitSignature.getLocalRangeEnd()) {
// This would be much cheaper if we stored TypeLocs instead of
// TypeSourceInfos.
TypeLoc Result = ExplicitSignature.getResultLoc();
@@ -8942,7 +9545,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If we don't have a function type, just build one from nothing.
} else {
FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, 0, CC_Default);
+ EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default);
BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
}
@@ -8984,7 +9587,10 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
// a pointer for va_arg.
VaListType = Context.getArrayDecayedType(VaListType);
// Make sure the input expression also decays appropriately.
- UsualUnaryConversions(E);
+ ExprResult Result = UsualUnaryConversions(E);
+ if (Result.isInvalid())
+ return ExprError();
+ E = Result.take();
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
@@ -9260,6 +9866,8 @@ Sema::PopExpressionEvaluationContext() {
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
assert(D && "No declaration?");
+ D->setReferenced();
+
if (D->isUsed(false))
return;
@@ -9393,6 +10001,9 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (MSInfo->getPointOfInstantiation().isInvalid() &&
MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
MSInfo->setPointOfInstantiation(Loc);
+ // This is a modification of an existing AST node. Notify listeners.
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->StaticDataMemberInstantiated(Var);
PendingInstantiations.push_back(std::make_pair(Var, Loc));
}
}
@@ -9624,10 +10235,13 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
return;
}
+ Diag(Loc, diagnostic) << E->getSourceRange();
+
SourceLocation Open = E->getSourceRange().getBegin();
SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
-
- Diag(Loc, diagnostic) << E->getSourceRange();
+ Diag(Loc, diag::note_condition_assign_silence)
+ << FixItHint::CreateInsertion(Open, "(")
+ << FixItHint::CreateInsertion(Close, ")");
if (IsOrAssign)
Diag(Loc, diag::note_condition_or_assign_to_comparison)
@@ -9635,10 +10249,6 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
else
Diag(Loc, diag::note_condition_assign_to_comparison)
<< FixItHint::CreateReplacement(Loc, "==");
-
- Diag(Loc, diag::note_condition_assign_silence)
- << FixItHint::CreateInsertion(Open, "(")
- << FixItHint::CreateInsertion(Close, ")");
}
/// \brief Redundant parentheses over an equality comparison can indicate
@@ -9648,6 +10258,9 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) {
SourceLocation parenLoc = parenE->getLocStart();
if (parenLoc.isInvalid() || parenLoc.isMacroID())
return;
+ // Don't warn for dependent expressions.
+ if (parenE->isTypeDependent())
+ return;
Expr *E = parenE->IgnoreParens();
@@ -9658,68 +10271,467 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) {
SourceLocation Loc = opE->getOperatorLoc();
Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange();
- Diag(Loc, diag::note_equality_comparison_to_assign)
- << FixItHint::CreateReplacement(Loc, "=");
Diag(Loc, diag::note_equality_comparison_silence)
<< FixItHint::CreateRemoval(parenE->getSourceRange().getBegin())
<< FixItHint::CreateRemoval(parenE->getSourceRange().getEnd());
+ Diag(Loc, diag::note_equality_comparison_to_assign)
+ << FixItHint::CreateReplacement(Loc, "=");
}
}
-bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
+ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
DiagnoseAssignmentAsCondition(E);
if (ParenExpr *parenE = dyn_cast<ParenExpr>(E))
DiagnoseEqualityWithExtraParens(parenE);
- if (!E->isTypeDependent()) {
- if (E->isBoundMemberFunction(Context))
- return Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << E->getSourceRange();
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return ExprError();
+ E = result.take();
+ if (!E->isTypeDependent()) {
if (getLangOptions().CPlusPlus)
return CheckCXXBooleanCondition(E); // C++ 6.4p4
- DefaultFunctionArrayLvalueConversion(E);
+ ExprResult ERes = DefaultFunctionArrayLvalueConversion(E);
+ if (ERes.isInvalid())
+ return ExprError();
+ E = ERes.take();
QualType T = E->getType();
- if (!T->isScalarType()) // C99 6.8.4.1p1
- return Diag(Loc, diag::err_typecheck_statement_requires_scalar)
- << T << E->getSourceRange();
+ if (!T->isScalarType()) { // C99 6.8.4.1p1
+ Diag(Loc, diag::err_typecheck_statement_requires_scalar)
+ << T << E->getSourceRange();
+ return ExprError();
+ }
}
- return false;
+ return Owned(E);
}
ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
Expr *Sub) {
if (!Sub)
return ExprError();
-
- if (CheckBooleanCondition(Sub, Loc))
+
+ return CheckBooleanCondition(Sub, Loc);
+}
+
+namespace {
+ /// A visitor for rebuilding a call to an __unknown_any expression
+ /// to have an appropriate type.
+ struct RebuildUnknownAnyFunction
+ : StmtVisitor<RebuildUnknownAnyFunction, ExprResult> {
+
+ Sema &S;
+
+ RebuildUnknownAnyFunction(Sema &S) : S(S) {}
+
+ ExprResult VisitStmt(Stmt *S) {
+ llvm_unreachable("unexpected statement!");
+ return ExprError();
+ }
+
+ ExprResult VisitExpr(Expr *expr) {
+ S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_call)
+ << expr->getSourceRange();
+ return ExprError();
+ }
+
+ /// Rebuild an expression which simply semantically wraps another
+ /// expression which it shares the type and value kind of.
+ template <class T> ExprResult rebuildSugarExpr(T *expr) {
+ ExprResult subResult = Visit(expr->getSubExpr());
+ if (subResult.isInvalid()) return ExprError();
+
+ Expr *subExpr = subResult.take();
+ expr->setSubExpr(subExpr);
+ expr->setType(subExpr->getType());
+ expr->setValueKind(subExpr->getValueKind());
+ assert(expr->getObjectKind() == OK_Ordinary);
+ return expr;
+ }
+
+ ExprResult VisitParenExpr(ParenExpr *paren) {
+ return rebuildSugarExpr(paren);
+ }
+
+ ExprResult VisitUnaryExtension(UnaryOperator *op) {
+ return rebuildSugarExpr(op);
+ }
+
+ ExprResult VisitUnaryAddrOf(UnaryOperator *op) {
+ ExprResult subResult = Visit(op->getSubExpr());
+ if (subResult.isInvalid()) return ExprError();
+
+ Expr *subExpr = subResult.take();
+ op->setSubExpr(subExpr);
+ op->setType(S.Context.getPointerType(subExpr->getType()));
+ assert(op->getValueKind() == VK_RValue);
+ assert(op->getObjectKind() == OK_Ordinary);
+ return op;
+ }
+
+ ExprResult resolveDecl(Expr *expr, ValueDecl *decl) {
+ if (!isa<FunctionDecl>(decl)) return VisitExpr(expr);
+
+ expr->setType(decl->getType());
+
+ assert(expr->getValueKind() == VK_RValue);
+ if (S.getLangOptions().CPlusPlus &&
+ !(isa<CXXMethodDecl>(decl) &&
+ cast<CXXMethodDecl>(decl)->isInstance()))
+ expr->setValueKind(VK_LValue);
+
+ return expr;
+ }
+
+ ExprResult VisitMemberExpr(MemberExpr *mem) {
+ return resolveDecl(mem, mem->getMemberDecl());
+ }
+
+ ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
+ return resolveDecl(ref, ref->getDecl());
+ }
+ };
+}
+
+/// Given a function expression of unknown-any type, try to rebuild it
+/// to have a function type.
+static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn) {
+ ExprResult result = RebuildUnknownAnyFunction(S).Visit(fn);
+ if (result.isInvalid()) return ExprError();
+ return S.DefaultFunctionArrayConversion(result.take());
+}
+
+namespace {
+ /// A visitor for rebuilding an expression of type __unknown_anytype
+ /// into one which resolves the type directly on the referring
+ /// expression. Strict preservation of the original source
+ /// structure is not a goal.
+ struct RebuildUnknownAnyExpr
+ : StmtVisitor<RebuildUnknownAnyExpr, ExprResult> {
+
+ Sema &S;
+
+ /// The current destination type.
+ QualType DestType;
+
+ RebuildUnknownAnyExpr(Sema &S, QualType castType)
+ : S(S), DestType(castType) {}
+
+ ExprResult VisitStmt(Stmt *S) {
+ llvm_unreachable("unexpected statement!");
+ return ExprError();
+ }
+
+ ExprResult VisitExpr(Expr *expr) {
+ S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_expr)
+ << expr->getSourceRange();
+ return ExprError();
+ }
+
+ ExprResult VisitCallExpr(CallExpr *call);
+ ExprResult VisitObjCMessageExpr(ObjCMessageExpr *message);
+
+ /// Rebuild an expression which simply semantically wraps another
+ /// expression which it shares the type and value kind of.
+ template <class T> ExprResult rebuildSugarExpr(T *expr) {
+ ExprResult subResult = Visit(expr->getSubExpr());
+ if (subResult.isInvalid()) return ExprError();
+ Expr *subExpr = subResult.take();
+ expr->setSubExpr(subExpr);
+ expr->setType(subExpr->getType());
+ expr->setValueKind(subExpr->getValueKind());
+ assert(expr->getObjectKind() == OK_Ordinary);
+ return expr;
+ }
+
+ ExprResult VisitParenExpr(ParenExpr *paren) {
+ return rebuildSugarExpr(paren);
+ }
+
+ ExprResult VisitUnaryExtension(UnaryOperator *op) {
+ return rebuildSugarExpr(op);
+ }
+
+ ExprResult VisitUnaryAddrOf(UnaryOperator *op) {
+ const PointerType *ptr = DestType->getAs<PointerType>();
+ if (!ptr) {
+ S.Diag(op->getOperatorLoc(), diag::err_unknown_any_addrof)
+ << op->getSourceRange();
+ return ExprError();
+ }
+ assert(op->getValueKind() == VK_RValue);
+ assert(op->getObjectKind() == OK_Ordinary);
+ op->setType(DestType);
+
+ // Build the sub-expression as if it were an object of the pointee type.
+ DestType = ptr->getPointeeType();
+ ExprResult subResult = Visit(op->getSubExpr());
+ if (subResult.isInvalid()) return ExprError();
+ op->setSubExpr(subResult.take());
+ return op;
+ }
+
+ ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice);
+
+ ExprResult resolveDecl(Expr *expr, ValueDecl *decl);
+
+ ExprResult VisitMemberExpr(MemberExpr *mem) {
+ return resolveDecl(mem, mem->getMemberDecl());
+ }
+
+ ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
+ return resolveDecl(ref, ref->getDecl());
+ }
+ };
+}
+
+/// Rebuilds a call expression which yielded __unknown_anytype.
+ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
+ Expr *callee = call->getCallee();
+
+ enum FnKind {
+ FK_MemberFunction,
+ FK_FunctionPointer,
+ FK_BlockPointer
+ };
+
+ FnKind kind;
+ QualType type = callee->getType();
+ if (type == S.Context.BoundMemberTy) {
+ assert(isa<CXXMemberCallExpr>(call) || isa<CXXOperatorCallExpr>(call));
+ kind = FK_MemberFunction;
+ type = Expr::findBoundMemberType(callee);
+ } else if (const PointerType *ptr = type->getAs<PointerType>()) {
+ type = ptr->getPointeeType();
+ kind = FK_FunctionPointer;
+ } else {
+ type = type->castAs<BlockPointerType>()->getPointeeType();
+ kind = FK_BlockPointer;
+ }
+ const FunctionType *fnType = type->castAs<FunctionType>();
+
+ // Verify that this is a legal result type of a function.
+ if (DestType->isArrayType() || DestType->isFunctionType()) {
+ unsigned diagID = diag::err_func_returning_array_function;
+ if (kind == FK_BlockPointer)
+ diagID = diag::err_block_returning_array_function;
+
+ S.Diag(call->getExprLoc(), diagID)
+ << DestType->isFunctionType() << DestType;
return ExprError();
-
- return Owned(Sub);
+ }
+
+ // Otherwise, go ahead and set DestType as the call's result.
+ call->setType(DestType.getNonLValueExprType(S.Context));
+ call->setValueKind(Expr::getValueKindForType(DestType));
+ assert(call->getObjectKind() == OK_Ordinary);
+
+ // Rebuild the function type, replacing the result type with DestType.
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType))
+ DestType = S.Context.getFunctionType(DestType,
+ proto->arg_type_begin(),
+ proto->getNumArgs(),
+ proto->getExtProtoInfo());
+ else
+ DestType = S.Context.getFunctionNoProtoType(DestType,
+ fnType->getExtInfo());
+
+ // Rebuild the appropriate pointer-to-function type.
+ switch (kind) {
+ case FK_MemberFunction:
+ // Nothing to do.
+ break;
+
+ case FK_FunctionPointer:
+ DestType = S.Context.getPointerType(DestType);
+ break;
+
+ case FK_BlockPointer:
+ DestType = S.Context.getBlockPointerType(DestType);
+ break;
+ }
+
+ // Finally, we can recurse.
+ ExprResult calleeResult = Visit(callee);
+ if (!calleeResult.isUsable()) return ExprError();
+ call->setCallee(calleeResult.take());
+
+ // Bind a temporary if necessary.
+ return S.MaybeBindToTemporary(call);
}
-/// Check for operands with placeholder types and complain if found.
-/// Returns true if there was an error and no recovery was possible.
-ExprResult Sema::CheckPlaceholderExpr(Expr *E, SourceLocation Loc) {
- const BuiltinType *BT = E->getType()->getAs<BuiltinType>();
- if (!BT || !BT->isPlaceholderType()) return Owned(E);
-
- // If this is overload, check for a single overload.
- assert(BT->getKind() == BuiltinType::Overload);
-
- if (FunctionDecl *Specialization
- = ResolveSingleFunctionTemplateSpecialization(E)) {
- // The access doesn't really matter in this case.
- DeclAccessPair Found = DeclAccessPair::make(Specialization,
- Specialization->getAccess());
- E = FixOverloadedFunctionReference(E, Found, Specialization);
- if (!E) return ExprError();
- return Owned(E);
+ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
+ ObjCMethodDecl *method = msg->getMethodDecl();
+ assert(method && "__unknown_anytype message without result type?");
+
+ // Verify that this is a legal result type of a call.
+ if (DestType->isArrayType() || DestType->isFunctionType()) {
+ S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function)
+ << DestType->isFunctionType() << DestType;
+ return ExprError();
}
- Diag(Loc, diag::err_ovl_unresolvable) << E->getSourceRange();
+ assert(method->getResultType() == S.Context.UnknownAnyTy);
+ method->setResultType(DestType);
+
+ // Change the type of the message.
+ msg->setType(DestType.getNonReferenceType());
+ msg->setValueKind(Expr::getValueKindForType(DestType));
+
+ return S.MaybeBindToTemporary(msg);
+}
+
+ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *ice) {
+ // The only case we should ever see here is a function-to-pointer decay.
+ assert(ice->getCastKind() == CK_FunctionToPointerDecay);
+ assert(ice->getValueKind() == VK_RValue);
+ assert(ice->getObjectKind() == OK_Ordinary);
+
+ ice->setType(DestType);
+
+ // Rebuild the sub-expression as the pointee (function) type.
+ DestType = DestType->castAs<PointerType>()->getPointeeType();
+
+ ExprResult result = Visit(ice->getSubExpr());
+ if (!result.isUsable()) return ExprError();
+
+ ice->setSubExpr(result.take());
+ return S.Owned(ice);
+}
+
+ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, ValueDecl *decl) {
+ ExprValueKind valueKind = VK_LValue;
+ QualType type = DestType;
+
+ // We know how to make this work for certain kinds of decls:
+
+ // - functions
+ if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) {
+ // This is true because FunctionDecls must always have function
+ // type, so we can't be resolving the entire thing at once.
+ assert(type->isFunctionType());
+
+ if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(fn))
+ if (method->isInstance()) {
+ valueKind = VK_RValue;
+ type = S.Context.BoundMemberTy;
+ }
+
+ // Function references aren't l-values in C.
+ if (!S.getLangOptions().CPlusPlus)
+ valueKind = VK_RValue;
+
+ // - variables
+ } else if (isa<VarDecl>(decl)) {
+ if (const ReferenceType *refTy = type->getAs<ReferenceType>()) {
+ type = refTy->getPointeeType();
+ } else if (type->isFunctionType()) {
+ S.Diag(expr->getExprLoc(), diag::err_unknown_any_var_function_type)
+ << decl << expr->getSourceRange();
+ return ExprError();
+ }
+
+ // - nothing else
+ } else {
+ S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_decl)
+ << decl << expr->getSourceRange();
+ return ExprError();
+ }
+
+ decl->setType(DestType);
+ expr->setType(type);
+ expr->setValueKind(valueKind);
+ return S.Owned(expr);
+}
+
+/// Check a cast of an unknown-any type. We intentionally only
+/// trigger this for C-style casts.
+ExprResult Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType,
+ Expr *castExpr, CastKind &castKind,
+ ExprValueKind &VK, CXXCastPath &path) {
+ // Rewrite the casted expression from scratch.
+ ExprResult result = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr);
+ if (!result.isUsable()) return ExprError();
+
+ castExpr = result.take();
+ VK = castExpr->getValueKind();
+ castKind = CK_NoOp;
+
+ return castExpr;
+}
+
+static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) {
+ Expr *orig = e;
+ unsigned diagID = diag::err_uncasted_use_of_unknown_any;
+ while (true) {
+ e = e->IgnoreParenImpCasts();
+ if (CallExpr *call = dyn_cast<CallExpr>(e)) {
+ e = call->getCallee();
+ diagID = diag::err_uncasted_call_of_unknown_any;
+ } else {
+ break;
+ }
+ }
+
+ SourceLocation loc;
+ NamedDecl *d;
+ if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) {
+ loc = ref->getLocation();
+ d = ref->getDecl();
+ } else if (MemberExpr *mem = dyn_cast<MemberExpr>(e)) {
+ loc = mem->getMemberLoc();
+ d = mem->getMemberDecl();
+ } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(e)) {
+ diagID = diag::err_uncasted_call_of_unknown_any;
+ loc = msg->getSelectorLoc();
+ d = msg->getMethodDecl();
+ assert(d && "unknown method returning __unknown_any?");
+ } else {
+ S.Diag(e->getExprLoc(), diag::err_unsupported_unknown_any_expr)
+ << e->getSourceRange();
+ return ExprError();
+ }
+
+ S.Diag(loc, diagID) << d << orig->getSourceRange();
+
+ // Never recoverable.
return ExprError();
}
+
+/// Check for operands with placeholder types and complain if found.
+/// Returns true if there was an error and no recovery was possible.
+ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
+ // Placeholder types are always *exactly* the appropriate builtin type.
+ QualType type = E->getType();
+
+ // Overloaded expressions.
+ if (type == Context.OverloadTy)
+ return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true,
+ E->getSourceRange(),
+ QualType(),
+ diag::err_ovl_unresolvable);
+
+ // Bound member functions.
+ if (type == Context.BoundMemberTy) {
+ Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
+ << E->getSourceRange();
+ return ExprError();
+ }
+
+ // Expressions of unknown type.
+ if (type == Context.UnknownAnyTy)
+ return diagnoseUnknownAnyExpr(*this, E);
+
+ assert(!type->isPlaceholderType());
+ return Owned(E);
+}
+
+bool Sema::CheckCaseExpression(Expr *expr) {
+ if (expr->isTypeDependent())
+ return true;
+ if (expr->isValueDependent() || expr->isIntegerConstantExpr(Context))
+ return expr->getType()->isIntegralOrEnumerationType();
+ return false;
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 6dd7aabaa1f0..7f1bf596a237 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -28,6 +28,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace sema;
@@ -138,10 +139,11 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
LookInScope = true;
}
+ TypeDecl *NonMatchingTypeDecl = 0;
LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName);
for (unsigned Step = 0; Step != 2; ++Step) {
// Look for the name first in the computed lookup context (if we
- // have one) and, if that fails to find a match, in the sope (if
+ // have one) and, if that fails to find a match, in the scope (if
// we're allowed to look there).
Found.clear();
if (Step == 0 && LookupCtx)
@@ -164,6 +166,9 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
return ParsedType::make(T);
}
+
+ if (!SearchType.isNull())
+ NonMatchingTypeDecl = Type;
}
// If the name that we found is a class template name, and it is
@@ -236,24 +241,22 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
if (isDependent) {
// We didn't find our type, but that's okay: it's dependent
// anyway.
- NestedNameSpecifier *NNS = 0;
- SourceRange Range;
- if (SS.isSet()) {
- NNS = (NestedNameSpecifier *)SS.getScopeRep();
- Range = SourceRange(SS.getRange().getBegin(), NameLoc);
- } else {
- NNS = NestedNameSpecifier::Create(Context, &II);
- Range = SourceRange(NameLoc);
- }
-
- QualType T = CheckTypenameType(ETK_None, NNS, II,
- SourceLocation(),
- Range, NameLoc);
+
+ // FIXME: What if we have no nested-name-specifier?
+ QualType T = CheckTypenameType(ETK_None, SourceLocation(),
+ SS.getWithLocInContext(Context),
+ II, NameLoc);
return ParsedType::make(T);
}
- if (ObjectTypePtr)
- Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ if (NonMatchingTypeDecl) {
+ QualType T = Context.getTypeDeclType(NonMatchingTypeDecl);
+ Diag(NameLoc, diag::err_destructor_expr_type_mismatch)
+ << T << SearchType;
+ Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here)
+ << T;
+ } else if (ObjectTypePtr)
+ Diag(NameLoc, diag::err_ident_in_dtor_not_a_type)
<< &II;
else
Diag(NameLoc, diag::err_destructor_class_name);
@@ -321,7 +324,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals);
if (!Context.hasSameType(T, UnqualT)) {
T = UnqualT;
- ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E));
+ E = ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)).take();
}
}
@@ -341,7 +344,7 @@ ExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
// Find the std::type_info type.
- if (!StdNamespace)
+ if (!getStdNamespace())
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
if (!CXXTypeInfoDecl) {
@@ -477,17 +480,21 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
ExprResult
Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) {
// Don't report an error if 'throw' is used in system headers.
- if (!getLangOptions().Exceptions &&
+ if (!getLangOptions().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
- if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex))
- return ExprError();
+ if (Ex && !Ex->isTypeDependent()) {
+ ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex);
+ if (ExRes.isInvalid())
+ return ExprError();
+ Ex = ExRes.take();
+ }
return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc));
}
/// CheckCXXThrowOperand - Validate the operand of a throw.
-bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
+ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
// C++ [except.throw]p3:
// A throw-expression initializes a temporary object, called the exception
// object, the type of which is determined by removing any top-level
@@ -495,10 +502,13 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// the type from "array of T" or "function returning T" to "pointer to T"
// or "pointer to function returning T", [...]
if (E->getType().hasQualifiers())
- ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp,
- CastCategory(E));
+ E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp,
+ CastCategory(E)).take();
- DefaultFunctionArrayConversion(E);
+ ExprResult Res = DefaultFunctionArrayConversion(E);
+ if (Res.isInvalid())
+ return ExprError();
+ E = Res.take();
// If the type of the exception would be an incomplete type or a pointer
// to an incomplete type other than (cv) void the program is ill-formed.
@@ -513,12 +523,12 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
PDiag(isPointer ? diag::err_throw_incomplete_ptr
: diag::err_throw_incomplete)
<< E->getSourceRange()))
- return true;
+ return ExprError();
if (RequireNonAbstractType(ThrowLoc, E->getType(),
PDiag(diag::err_throw_abstract_type)
<< E->getSourceRange()))
- return true;
+ return ExprError();
}
// Initialize the exception result. This implicitly weeds out
@@ -529,16 +539,16 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
InitializedEntity Entity =
InitializedEntity::InitializeException(ThrowLoc, E->getType(),
/*NRVO=*/false);
- ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
- QualType(), E);
+ Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
+ QualType(), E);
if (Res.isInvalid())
- return true;
- E = Res.takeAs<Expr>();
+ return ExprError();
+ E = Res.take();
// If the exception has class type, we need additional handling.
const RecordType *RecordTy = Ty->getAs<RecordType>();
if (!RecordTy)
- return false;
+ return Owned(E);
CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
// If we are throwing a polymorphic class type or pointer thereof,
@@ -547,21 +557,21 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// If a pointer is thrown, the referenced object will not be destroyed.
if (isPointer)
- return false;
+ return Owned(E);
// If the class has a non-trivial destructor, we must be able to call it.
if (RD->hasTrivialDestructor())
- return false;
+ return Owned(E);
CXXDestructorDecl *Destructor
= const_cast<CXXDestructorDecl*>(LookupDestructor(RD));
if (!Destructor)
- return false;
+ return Owned(E);
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_exception) << Ty);
- return false;
+ return Owned(E);
}
CXXMethodDecl *Sema::tryCaptureCXXThis() {
@@ -666,10 +676,13 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
CastKind Kind = CK_Invalid;
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
- if (CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
- Kind, VK, BasePath,
- /*FunctionalStyle=*/true))
+ ExprResult CastExpr =
+ CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
+ Kind, VK, BasePath,
+ /*FunctionalStyle=*/true);
+ if (CastExpr.isInvalid())
return ExprError();
+ Exprs[0] = CastExpr.take();
exprs.release();
@@ -846,16 +859,18 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
diag::err_auto_new_ctor_multiple_expressions)
<< AllocType << TypeRange);
}
- QualType DeducedType;
- if (!DeduceAutoType(AllocType, ConstructorArgs.get()[0], DeducedType))
+ TypeSourceInfo *DeducedType = 0;
+ if (!DeduceAutoType(AllocTypeInfo, ConstructorArgs.get()[0], DeducedType))
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
<< AllocType
<< ConstructorArgs.get()[0]->getType()
<< TypeRange
<< ConstructorArgs.get()[0]->getSourceRange());
+ if (!DeducedType)
+ return ExprError();
- AllocType = DeducedType;
- AllocTypeInfo = Context.getTrivialTypeSourceInfo(AllocType, StartLoc);
+ AllocTypeInfo = DeducedType;
+ AllocType = AllocTypeInfo->getType();
}
// Per C++0x [expr.new]p5, the type being constructed may be a
@@ -935,8 +950,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- ImpCastExprToType(ArraySize, Context.getSizeType(),
- CK_IntegralCast);
+ ArraySize = ImpCastExprToType(ArraySize, Context.getSizeType(),
+ CK_IntegralCast).take();
}
FunctionDecl *OperatorNew = 0;
@@ -1090,7 +1105,10 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (AllocType->isVariablyModifiedType())
return Diag(Loc, diag::err_variably_modified_new_type)
<< AllocType;
-
+ else if (unsigned AddressSpace = AllocType.getAddressSpace())
+ return Diag(Loc, diag::err_address_space_qualified_new)
+ << AllocType.getUnqualifiedType() << AddressSpace;
+
return false;
}
@@ -1384,16 +1402,16 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
return true;
- case OR_Deleted:
+ case OR_Deleted: {
Diag(StartLoc, diag::err_ovl_deleted_call)
<< Best->Function->isDeleted()
<< Name
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
+ << getDeletedOrUnavailableSuffix(Best->Function)
<< Range;
Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
return true;
}
+ }
assert(false && "Unreachable, bad result from BestViableFunction");
return true;
}
@@ -1402,11 +1420,18 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
/// DeclareGlobalNewDelete - Declare the global forms of operator new and
/// delete. These are:
/// @code
+/// // C++03:
/// void* operator new(std::size_t) throw(std::bad_alloc);
/// void* operator new[](std::size_t) throw(std::bad_alloc);
/// void operator delete(void *) throw();
/// void operator delete[](void *) throw();
+/// // C++0x:
+/// void* operator new(std::size_t);
+/// void* operator new[](std::size_t);
+/// void operator delete(void *);
+/// void operator delete[](void *);
/// @endcode
+/// C++0x operator delete is implicitly noexcept.
/// Note that the placement and nothrow forms of new are *not* implicitly
/// declared. Their use requires including \<new\>.
void Sema::DeclareGlobalNewDelete() {
@@ -1418,10 +1443,16 @@ void Sema::DeclareGlobalNewDelete() {
// implicitly declared in global scope in each translation unit of a
// program
//
+ // C++03:
// void* operator new(std::size_t) throw(std::bad_alloc);
// void* operator new[](std::size_t) throw(std::bad_alloc);
// void operator delete(void*) throw();
// void operator delete[](void*) throw();
+ // C++0x:
+ // void* operator new(std::size_t);
+ // void* operator new[](std::size_t);
+ // void operator delete(void*);
+ // void operator delete[](void*);
//
// These implicit declarations introduce only the function names operator
// new, operator new[], operator delete, operator delete[].
@@ -1430,14 +1461,16 @@ void Sema::DeclareGlobalNewDelete() {
// "std" or "bad_alloc" as necessary to form the exception specification.
// However, we do not make these implicit declarations visible to name
// lookup.
- if (!StdBadAlloc) {
+ // Note that the C++0x versions of operator delete are deallocation functions,
+ // and thus are implicitly noexcept.
+ if (!StdBadAlloc && !getLangOptions().CPlusPlus0x) {
// The "std::bad_alloc" class has not yet been declared, so build it
// implicitly.
StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class,
getOrCreateStdNamespace(),
- SourceLocation(),
+ SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("bad_alloc"),
- SourceLocation(), 0);
+ 0);
getStdBadAlloc()->setImplicit(true);
}
@@ -1493,21 +1526,27 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
bool HasBadAllocExceptionSpec
= (Name.getCXXOverloadedOperator() == OO_New ||
Name.getCXXOverloadedOperator() == OO_Array_New);
- if (HasBadAllocExceptionSpec) {
+ if (HasBadAllocExceptionSpec && !getLangOptions().CPlusPlus0x) {
assert(StdBadAlloc && "Must have std::bad_alloc declared");
BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
}
FunctionProtoType::ExtProtoInfo EPI;
- EPI.HasExceptionSpec = true;
if (HasBadAllocExceptionSpec) {
- EPI.NumExceptions = 1;
- EPI.Exceptions = &BadAllocType;
+ if (!getLangOptions().CPlusPlus0x) {
+ EPI.ExceptionSpecType = EST_Dynamic;
+ EPI.NumExceptions = 1;
+ EPI.Exceptions = &BadAllocType;
+ }
+ } else {
+ EPI.ExceptionSpecType = getLangOptions().CPlusPlus0x ?
+ EST_BasicNoexcept : EST_DynamicNone;
}
QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI);
FunctionDecl *Alloc =
- FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
+ FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
+ SourceLocation(), Name,
FnType, /*TInfo=*/0, SC_None,
SC_None, false, true);
Alloc->setImplicit();
@@ -1516,9 +1555,9 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context));
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
- 0, Argument, /*TInfo=*/0,
- SC_None,
- SC_None, 0);
+ SourceLocation(), 0,
+ Argument, /*TInfo=*/0,
+ SC_None, SC_None, 0);
Alloc->setParams(&Param, 1);
// FIXME: Also add this declaration to the IdentifierResolver, but
@@ -1608,19 +1647,20 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
/// @code delete [] ptr; @endcode
ExprResult
Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
- bool ArrayForm, Expr *Ex) {
+ bool ArrayForm, Expr *ExE) {
// C++ [expr.delete]p1:
// The operand shall have a pointer type, or a class type having a single
// conversion function to a pointer type. The result has type void.
//
// DR599 amends "pointer type" to "pointer to object type" in both cases.
+ ExprResult Ex = Owned(ExE);
FunctionDecl *OperatorDelete = 0;
bool ArrayFormAsWritten = ArrayForm;
bool UsualArrayDeleteWantsSize = false;
- if (!Ex->isTypeDependent()) {
- QualType Type = Ex->getType();
+ if (!Ex.get()->isTypeDependent()) {
+ QualType Type = Ex.get()->getType();
if (const RecordType *Record = Type->getAs<RecordType>()) {
if (RequireCompleteType(StartLoc, Type,
@@ -1652,15 +1692,18 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// We have a single conversion to a pointer-to-object type. Perform
// that conversion.
// TODO: don't redo the conversion calculation.
- if (!PerformImplicitConversion(Ex,
+ ExprResult Res =
+ PerformImplicitConversion(Ex.get(),
ObjectPtrConversions.front()->getConversionType(),
- AA_Converting)) {
- Type = Ex->getType();
+ AA_Converting);
+ if (Res.isUsable()) {
+ Ex = move(Res);
+ Type = Ex.get()->getType();
}
}
else if (ObjectPtrConversions.size() > 1) {
Diag(StartLoc, diag::err_ambiguous_delete_operand)
- << Type << Ex->getSourceRange();
+ << Type << Ex.get()->getSourceRange();
for (unsigned i= 0; i < ObjectPtrConversions.size(); i++)
NoteOverloadCandidate(ObjectPtrConversions[i]);
return ExprError();
@@ -1669,7 +1712,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (!Type->isPointerType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
- << Type << Ex->getSourceRange());
+ << Type << Ex.get()->getSourceRange());
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
if (Pointee->isVoidType() && !isSFINAEContext()) {
@@ -1677,27 +1720,30 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// effectively bans deletion of "void*". However, most compilers support
// this, so we treat it as a warning unless we're in a SFINAE context.
Diag(StartLoc, diag::ext_delete_void_ptr_operand)
- << Type << Ex->getSourceRange();
+ << Type << Ex.get()->getSourceRange();
} else if (Pointee->isFunctionType() || Pointee->isVoidType())
return ExprError(Diag(StartLoc, diag::err_delete_operand)
- << Type << Ex->getSourceRange());
+ << Type << Ex.get()->getSourceRange());
else if (!Pointee->isDependentType() &&
RequireCompleteType(StartLoc, Pointee,
PDiag(diag::warn_delete_incomplete)
- << Ex->getSourceRange()))
+ << Ex.get()->getSourceRange()))
return ExprError();
-
+ else if (unsigned AddressSpace = Pointee.getAddressSpace())
+ return Diag(Ex.get()->getLocStart(),
+ diag::err_address_space_qualified_delete)
+ << Pointee.getUnqualifiedType() << AddressSpace;
// C++ [expr.delete]p2:
// [Note: a pointer to a const type can be the operand of a
// delete-expression; it is not necessary to cast away the constness
// (5.2.11) of the pointer expression before it is used as the operand
// of the delete-expression. ]
- ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy),
+ Ex = ImpCastExprToType(Ex.take(), Context.getPointerType(Context.VoidTy),
CK_NoOp);
if (Pointee->isArrayType() && !ArrayForm) {
Diag(StartLoc, diag::warn_delete_array_type)
- << Type << Ex->getSourceRange()
+ << Type << Ex.get()->getSourceRange()
<< FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc), "[]");
ArrayForm = true;
}
@@ -1740,8 +1786,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// Look for a global declaration.
DeclareGlobalNewDelete();
DeclContext *TUDecl = Context.getTranslationUnitDecl();
+ Expr *Arg = Ex.get();
if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
- &Ex, 1, TUDecl, /*AllowMissing=*/false,
+ &Arg, 1, TUDecl, /*AllowMissing=*/false,
OperatorDelete))
return ExprError();
}
@@ -1752,7 +1799,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (const RecordType *RT = PointeeElem->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) {
- CheckDestructorAccess(Ex->getExprLoc(), Dtor,
+ CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor,
PDiag(diag::err_access_dtor) << PointeeElem);
}
}
@@ -1762,7 +1809,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
ArrayFormAsWritten,
UsualArrayDeleteWantsSize,
- OperatorDelete, Ex, StartLoc));
+ OperatorDelete, Ex.take(), StartLoc));
}
/// \brief Check the use of the given variable as a C++ condition in an if,
@@ -1783,18 +1830,23 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
diag::err_invalid_use_of_array_type)
<< ConditionVar->getSourceRange());
- Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
+ ExprResult Condition =
+ Owned(DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
+ ConditionVar,
ConditionVar->getLocation(),
ConditionVar->getType().getNonReferenceType(),
- VK_LValue);
- if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc))
- return ExprError();
+ VK_LValue));
+ if (ConvertToBoolean) {
+ Condition = CheckBooleanCondition(Condition.take(), StmtLoc);
+ if (Condition.isInvalid())
+ return ExprError();
+ }
- return Owned(Condition);
+ return move(Condition);
}
/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
-bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
+ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) {
// C++ 6.4p4:
// The value of a condition that is an initialized declaration in a statement
// other than a switch statement is the value of the declared variable
@@ -1880,20 +1932,22 @@ static ExprResult BuildCXXCastArgument(Sema &S,
/// PerformImplicitConversion - Perform an implicit conversion of the
/// expression From to the type ToType using the pre-computed implicit
-/// conversion sequence ICS. Returns true if there was an error, false
-/// otherwise. The expression From is replaced with the converted
+/// conversion sequence ICS. Returns the converted
/// expression. Action is the kind of conversion we're performing,
/// used in the error message.
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ExprResult
+Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence &ICS,
AssignmentAction Action, bool CStyle) {
switch (ICS.getKind()) {
- case ImplicitConversionSequence::StandardConversion:
- if (PerformImplicitConversion(From, ToType, ICS.Standard, Action,
- CStyle))
- return true;
+ case ImplicitConversionSequence::StandardConversion: {
+ ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard,
+ Action, CStyle);
+ if (Res.isInvalid())
+ return ExprError();
+ From = Res.take();
break;
+ }
case ImplicitConversionSequence::UserDefinedConversion: {
@@ -1920,10 +1974,13 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
}
// Watch out for elipsis conversion.
if (!ICS.UserDefined.EllipsisConversion) {
- if (PerformImplicitConversion(From, BeforeToType,
- ICS.UserDefined.Before, AA_Converting,
- CStyle))
- return true;
+ ExprResult Res =
+ PerformImplicitConversion(From, BeforeToType,
+ ICS.UserDefined.Before, AA_Converting,
+ CStyle);
+ if (Res.isInvalid())
+ return ExprError();
+ From = Res.take();
}
ExprResult CastArg
@@ -1935,9 +1992,9 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
From);
if (CastArg.isInvalid())
- return true;
+ return ExprError();
- From = CastArg.takeAs<Expr>();
+ From = CastArg.take();
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
AA_Converting, CStyle);
@@ -1947,28 +2004,27 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(),
PDiag(diag::err_typecheck_ambiguous_condition)
<< From->getSourceRange());
- return true;
+ return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
assert(false && "Cannot perform an ellipsis conversion");
- return false;
+ return Owned(From);
case ImplicitConversionSequence::BadConversion:
- return true;
+ return ExprError();
}
// Everything went well.
- return false;
+ return Owned(From);
}
/// PerformImplicitConversion - Perform an implicit conversion of the
/// expression From to the type ToType by following the standard
-/// conversion sequence SCS. Returns true if there was an error, false
-/// otherwise. The expression From is replaced with the converted
+/// conversion sequence SCS. Returns the converted
/// expression. Flavor is the context in which we're performing this
/// conversion, for use in error messages.
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ExprResult
+Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence& SCS,
AssignmentAction Action, bool CStyle) {
// Overall FIXME: we are recomputing too many types here and doing far too
@@ -1986,32 +2042,20 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
MultiExprArg(*this, &From, 1),
/*FIXME:ConstructLoc*/SourceLocation(),
ConstructorArgs))
- return true;
- ExprResult FromResult =
- BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
- ToType, SCS.CopyConstructor,
- move_arg(ConstructorArgs),
- /*ZeroInit*/ false,
- CXXConstructExpr::CK_Complete,
- SourceRange());
- if (FromResult.isInvalid())
- return true;
- From = FromResult.takeAs<Expr>();
- return false;
+ return ExprError();
+ return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ move_arg(ConstructorArgs),
+ /*ZeroInit*/ false,
+ CXXConstructExpr::CK_Complete,
+ SourceRange());
}
- ExprResult FromResult =
- BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
- ToType, SCS.CopyConstructor,
- MultiExprArg(*this, &From, 1),
- /*ZeroInit*/ false,
- CXXConstructExpr::CK_Complete,
- SourceRange());
-
- if (FromResult.isInvalid())
- return true;
-
- From = FromResult.takeAs<Expr>();
- return false;
+ return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
+ ToType, SCS.CopyConstructor,
+ MultiExprArg(*this, &From, 1),
+ /*ZeroInit*/ false,
+ CXXConstructExpr::CK_Complete,
+ SourceRange());
}
// Resolve overloaded function references.
@@ -2020,10 +2064,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
true, Found);
if (!Fn)
- return true;
+ return ExprError();
if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
- return true;
+ return ExprError();
From = FixOverloadedFunctionReference(From, Found, Fn);
FromType = From->getType();
@@ -2038,13 +2082,15 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Lvalue_To_Rvalue:
// Should this get its own ICK?
if (From->getObjectKind() == OK_ObjCProperty) {
- ConvertPropertyForRValue(From);
+ ExprResult FromRes = ConvertPropertyForRValue(From);
+ if (FromRes.isInvalid())
+ return ExprError();
+ From = FromRes.take();
if (!From->isGLValue()) break;
}
// Check for trivial buffer overflows.
- if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(From))
- CheckArrayAccess(AE);
+ CheckArrayAccess(From);
FromType = FromType.getUnqualifiedType();
From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue,
@@ -2053,12 +2099,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
- ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay);
+ From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay).take();
break;
case ICK_Function_To_Pointer:
FromType = Context.getPointerType(FromType);
- ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay);
+ From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay).take();
break;
default:
@@ -2072,7 +2118,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// If both sides are functions (or pointers/references to them), there could
// be incompatible exception declarations.
if (CheckExceptionSpecCompatibility(From, ToType))
- return true;
+ return ExprError();
// Nothing else to do.
break;
@@ -2080,19 +2126,19 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// If both sides are functions (or pointers/references to them), there could
// be incompatible exception declarations.
if (CheckExceptionSpecCompatibility(From, ToType))
- return true;
+ return ExprError();
- ImpCastExprToType(From, ToType, CK_NoOp);
+ From = ImpCastExprToType(From, ToType, CK_NoOp).take();
break;
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
- ImpCastExprToType(From, ToType, CK_IntegralCast);
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast).take();
break;
case ICK_Floating_Promotion:
case ICK_Floating_Conversion:
- ImpCastExprToType(From, ToType, CK_FloatingCast);
+ From = ImpCastExprToType(From, ToType, CK_FloatingCast).take();
break;
case ICK_Complex_Promotion:
@@ -2110,35 +2156,41 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
} else {
CK = CK_IntegralComplexCast;
}
- ImpCastExprToType(From, ToType, CK);
+ From = ImpCastExprToType(From, ToType, CK).take();
break;
}
case ICK_Floating_Integral:
if (ToType->isRealFloatingType())
- ImpCastExprToType(From, ToType, CK_IntegralToFloating);
+ From = ImpCastExprToType(From, ToType, CK_IntegralToFloating).take();
else
- ImpCastExprToType(From, ToType, CK_FloatingToIntegral);
+ From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral).take();
break;
case ICK_Compatible_Conversion:
- ImpCastExprToType(From, ToType, CK_NoOp);
+ From = ImpCastExprToType(From, ToType, CK_NoOp).take();
break;
case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC && Action != AA_Casting) {
// Diagnose incompatible Objective-C conversions
- Diag(From->getSourceRange().getBegin(),
- diag::ext_typecheck_convert_incompatible_pointer)
- << From->getType() << ToType << Action
- << From->getSourceRange();
+ if (Action == AA_Initializing)
+ Diag(From->getSourceRange().getBegin(),
+ diag::ext_typecheck_convert_incompatible_pointer)
+ << ToType << From->getType() << Action
+ << From->getSourceRange();
+ else
+ Diag(From->getSourceRange().getBegin(),
+ diag::ext_typecheck_convert_incompatible_pointer)
+ << From->getType() << ToType << Action
+ << From->getSourceRange();
}
CastKind Kind = CK_Invalid;
CXXCastPath BasePath;
if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
- return true;
- ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath);
+ return ExprError();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
break;
}
@@ -2146,27 +2198,17 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
CastKind Kind = CK_Invalid;
CXXCastPath BasePath;
if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle))
- return true;
+ return ExprError();
if (CheckExceptionSpecCompatibility(From, ToType))
- return true;
- ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath);
+ return ExprError();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
break;
}
- case ICK_Boolean_Conversion: {
- CastKind Kind = CK_Invalid;
- switch (FromType->getScalarTypeKind()) {
- case Type::STK_Pointer: Kind = CK_PointerToBoolean; break;
- case Type::STK_MemberPointer: Kind = CK_MemberPointerToBoolean; break;
- case Type::STK_Bool: llvm_unreachable("bool -> bool conversion?");
- case Type::STK_Integral: Kind = CK_IntegralToBoolean; break;
- case Type::STK_Floating: Kind = CK_FloatingToBoolean; break;
- case Type::STK_IntegralComplex: Kind = CK_IntegralComplexToBoolean; break;
- case Type::STK_FloatingComplex: Kind = CK_FloatingComplexToBoolean; break;
- }
- ImpCastExprToType(From, Context.BoolTy, Kind);
+ case ICK_Boolean_Conversion:
+ From = ImpCastExprToType(From, Context.BoolTy,
+ ScalarTypeToBooleanCastKind(FromType)).take();
break;
- }
case ICK_Derived_To_Base: {
CXXCastPath BasePath;
@@ -2176,20 +2218,20 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
From->getSourceRange(),
&BasePath,
CStyle))
- return true;
+ return ExprError();
- ImpCastExprToType(From, ToType.getNonReferenceType(),
+ From = ImpCastExprToType(From, ToType.getNonReferenceType(),
CK_DerivedToBase, CastCategory(From),
- &BasePath);
+ &BasePath).take();
break;
}
case ICK_Vector_Conversion:
- ImpCastExprToType(From, ToType, CK_BitCast);
+ From = ImpCastExprToType(From, ToType, CK_BitCast).take();
break;
case ICK_Vector_Splat:
- ImpCastExprToType(From, ToType, CK_VectorSplat);
+ From = ImpCastExprToType(From, ToType, CK_VectorSplat).take();
break;
case ICK_Complex_Real:
@@ -2202,17 +2244,17 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
if (Context.hasSameUnqualifiedType(ElType, From->getType())) {
// do nothing
} else if (From->getType()->isRealFloatingType()) {
- ImpCastExprToType(From, ElType,
- isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral);
+ From = ImpCastExprToType(From, ElType,
+ isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral).take();
} else {
assert(From->getType()->isIntegerType());
- ImpCastExprToType(From, ElType,
- isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast);
+ From = ImpCastExprToType(From, ElType,
+ isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast).take();
}
// y -> _Complex y
- ImpCastExprToType(From, ToType,
+ From = ImpCastExprToType(From, ToType,
isFloatingComplex ? CK_FloatingRealToComplex
- : CK_IntegralRealToComplex);
+ : CK_IntegralRealToComplex).take();
// Case 2. _Complex x -> y
} else {
@@ -2223,29 +2265,43 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
bool isFloatingComplex = ElType->isRealFloatingType();
// _Complex x -> x
- ImpCastExprToType(From, ElType,
+ From = ImpCastExprToType(From, ElType,
isFloatingComplex ? CK_FloatingComplexToReal
- : CK_IntegralComplexToReal);
+ : CK_IntegralComplexToReal).take();
// x -> y
if (Context.hasSameUnqualifiedType(ElType, ToType)) {
// do nothing
} else if (ToType->isRealFloatingType()) {
- ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating);
+ From = ImpCastExprToType(From, ToType,
+ isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating).take();
} else {
assert(ToType->isIntegerType());
- ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast);
+ From = ImpCastExprToType(From, ToType,
+ isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast).take();
}
}
break;
case ICK_Block_Pointer_Conversion: {
- ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue);
+ From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
+ VK_RValue).take();
break;
}
+ case ICK_TransparentUnionConversion: {
+ ExprResult FromRes = Owned(From);
+ Sema::AssignConvertType ConvTy =
+ CheckTransparentUnionArgumentConstraints(ToType, FromRes);
+ if (FromRes.isInvalid())
+ return ExprError();
+ From = FromRes.take();
+ assert ((ConvTy == Sema::Compatible) &&
+ "Improper transparent union conversion");
+ (void)ConvTy;
+ break;
+ }
+
case ICK_Lvalue_To_Rvalue:
case ICK_Array_To_Pointer:
case ICK_Function_To_Pointer:
@@ -2265,10 +2321,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// target type isn't a reference.
ExprValueKind VK = ToType->isReferenceType() ?
CastCategory(From) : VK_RValue;
- ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
- CK_NoOp, VK);
+ From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
+ CK_NoOp, VK).take();
- if (SCS.DeprecatedStringLiteralToCharPtr)
+ if (SCS.DeprecatedStringLiteralToCharPtr &&
+ !getLangOptions().WritableStrings)
Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
<< ToType.getNonReferenceType();
@@ -2280,7 +2337,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
}
- return false;
+ return Owned(From);
}
ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT,
@@ -2295,41 +2352,197 @@ ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT,
return BuildUnaryTypeTrait(UTT, KWLoc, TSInfo, RParen);
}
-static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
- SourceLocation KeyLoc) {
- // FIXME: For many of these traits, we need a complete type before we can
- // check these properties.
- assert(!T->isDependentType() &&
- "Cannot evaluate traits for dependent types.");
+/// \brief Check the completeness of a type in a unary type trait.
+///
+/// If the particular type trait requires a complete type, tries to complete
+/// it. If completing the type fails, a diagnostic is emitted and false
+/// returned. If completing the type succeeds or no completion was required,
+/// returns true.
+static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
+ UnaryTypeTrait UTT,
+ SourceLocation Loc,
+ QualType ArgTy) {
+ // C++0x [meta.unary.prop]p3:
+ // For all of the class templates X declared in this Clause, instantiating
+ // that template with a template argument that is a class template
+ // specialization may result in the implicit instantiation of the template
+ // argument if and only if the semantics of X require that the argument
+ // must be a complete type.
+ // We apply this rule to all the type trait expressions used to implement
+ // these class templates. We also try to follow any GCC documented behavior
+ // in these expressions to ensure portability of standard libraries.
+ switch (UTT) {
+ // is_complete_type somewhat obviously cannot require a complete type.
+ case UTT_IsCompleteType:
+ // Fall-through
+
+ // These traits are modeled on the type predicates in C++0x
+ // [meta.unary.cat] and [meta.unary.comp]. They are not specified as
+ // requiring a complete type, as whether or not they return true cannot be
+ // impacted by the completeness of the type.
+ case UTT_IsVoid:
+ case UTT_IsIntegral:
+ case UTT_IsFloatingPoint:
+ case UTT_IsArray:
+ case UTT_IsPointer:
+ case UTT_IsLvalueReference:
+ case UTT_IsRvalueReference:
+ case UTT_IsMemberFunctionPointer:
+ case UTT_IsMemberObjectPointer:
+ case UTT_IsEnum:
+ case UTT_IsUnion:
+ case UTT_IsClass:
+ case UTT_IsFunction:
+ case UTT_IsReference:
+ case UTT_IsArithmetic:
+ case UTT_IsFundamental:
+ case UTT_IsObject:
+ case UTT_IsScalar:
+ case UTT_IsCompound:
+ case UTT_IsMemberPointer:
+ // Fall-through
+
+ // These traits are modeled on type predicates in C++0x [meta.unary.prop]
+ // which requires some of its traits to have the complete type. However,
+ // the completeness of the type cannot impact these traits' semantics, and
+ // so they don't require it. This matches the comments on these traits in
+ // Table 49.
+ case UTT_IsConst:
+ case UTT_IsVolatile:
+ case UTT_IsSigned:
+ case UTT_IsUnsigned:
+ return true;
+
+ // C++0x [meta.unary.prop] Table 49 requires the following traits to be
+ // applied to a complete type.
+ case UTT_IsTrivial:
+ case UTT_IsStandardLayout:
+ case UTT_IsPOD:
+ case UTT_IsLiteral:
+ case UTT_IsEmpty:
+ case UTT_IsPolymorphic:
+ case UTT_IsAbstract:
+ // Fall-through
+
+ // These trait expressions are designed to help implement predicates in
+ // [meta.unary.prop] despite not being named the same. They are specified
+ // by both GCC and the Embarcadero C++ compiler, and require the complete
+ // type due to the overarching C++0x type predicates being implemented
+ // requiring the complete type.
+ case UTT_HasNothrowAssign:
+ case UTT_HasNothrowConstructor:
+ case UTT_HasNothrowCopy:
+ case UTT_HasTrivialAssign:
+ case UTT_HasTrivialConstructor:
+ case UTT_HasTrivialCopy:
+ case UTT_HasTrivialDestructor:
+ case UTT_HasVirtualDestructor:
+ // Arrays of unknown bound are expressly allowed.
+ QualType ElTy = ArgTy;
+ if (ArgTy->isIncompleteArrayType())
+ ElTy = S.Context.getAsArrayType(ArgTy)->getElementType();
+
+ // The void type is expressly allowed.
+ if (ElTy->isVoidType())
+ return true;
+
+ return !S.RequireCompleteType(
+ Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr);
+ }
+ llvm_unreachable("Type trait not handled by switch");
+}
+
+static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
+ SourceLocation KeyLoc, QualType T) {
+ assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
+
ASTContext &C = Self.Context;
switch(UTT) {
- default: assert(false && "Unknown type trait or not implemented");
- case UTT_IsPOD: return T->isPODType();
- case UTT_IsLiteral: return T->isLiteralType();
- case UTT_IsClass: // Fallthrough
+ // Type trait expressions corresponding to the primary type category
+ // predicates in C++0x [meta.unary.cat].
+ case UTT_IsVoid:
+ return T->isVoidType();
+ case UTT_IsIntegral:
+ return T->isIntegralType(C);
+ case UTT_IsFloatingPoint:
+ return T->isFloatingType();
+ case UTT_IsArray:
+ return T->isArrayType();
+ case UTT_IsPointer:
+ return T->isPointerType();
+ case UTT_IsLvalueReference:
+ return T->isLValueReferenceType();
+ case UTT_IsRvalueReference:
+ return T->isRValueReferenceType();
+ case UTT_IsMemberFunctionPointer:
+ return T->isMemberFunctionPointerType();
+ case UTT_IsMemberObjectPointer:
+ return T->isMemberDataPointerType();
+ case UTT_IsEnum:
+ return T->isEnumeralType();
case UTT_IsUnion:
- if (const RecordType *Record = T->getAs<RecordType>()) {
- bool Union = Record->getDecl()->isUnion();
- return UTT == UTT_IsUnion ? Union : !Union;
- }
+ return T->isUnionType();
+ case UTT_IsClass:
+ return T->isClassType() || T->isStructureType();
+ case UTT_IsFunction:
+ return T->isFunctionType();
+
+ // Type trait expressions which correspond to the convenient composition
+ // predicates in C++0x [meta.unary.comp].
+ case UTT_IsReference:
+ return T->isReferenceType();
+ case UTT_IsArithmetic:
+ return T->isArithmeticType() && !T->isEnumeralType();
+ case UTT_IsFundamental:
+ return T->isFundamentalType();
+ case UTT_IsObject:
+ return T->isObjectType();
+ case UTT_IsScalar:
+ return T->isScalarType();
+ case UTT_IsCompound:
+ return T->isCompoundType();
+ case UTT_IsMemberPointer:
+ return T->isMemberPointerType();
+
+ // Type trait expressions which correspond to the type property predicates
+ // in C++0x [meta.unary.prop].
+ case UTT_IsConst:
+ return T.isConstQualified();
+ case UTT_IsVolatile:
+ return T.isVolatileQualified();
+ case UTT_IsTrivial:
+ return T->isTrivialType();
+ case UTT_IsStandardLayout:
+ return T->isStandardLayoutType();
+ case UTT_IsPOD:
+ return T->isPODType();
+ case UTT_IsLiteral:
+ return T->isLiteralType();
+ case UTT_IsEmpty:
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return !RD->isUnion() && RD->isEmpty();
return false;
- case UTT_IsEnum: return T->isEnumeralType();
case UTT_IsPolymorphic:
- if (const RecordType *Record = T->getAs<RecordType>()) {
- // Type traits are only parsed in C++, so we've got CXXRecords.
- return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic();
- }
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->isPolymorphic();
return false;
case UTT_IsAbstract:
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
- return false;
- case UTT_IsEmpty:
- if (const RecordType *Record = T->getAs<RecordType>()) {
- return !Record->getDecl()->isUnion()
- && cast<CXXRecordDecl>(Record->getDecl())->isEmpty();
- }
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->isAbstract();
return false;
+ case UTT_IsSigned:
+ return T->isSignedIntegerType();
+ case UTT_IsUnsigned:
+ return T->isUnsignedIntegerType();
+
+ // Type trait expressions which query classes regarding their construction,
+ // destruction, and copying. Rather than being based directly on the
+ // related type predicates in the standard, they are specified by both
+ // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those
+ // specifications.
+ //
+ // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
+ // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
case UTT_HasTrivialConstructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If __is_pod (type) is true then the trait is true, else if type is
@@ -2418,7 +2631,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
FoundAssign = true;
const FunctionProtoType *CPT
= Operator->getType()->getAs<FunctionProtoType>();
- if (!CPT->hasEmptyExceptionSpec()) {
+ if (!CPT->isNothrow(Self.Context)) {
AllNoThrow = false;
break;
}
@@ -2458,9 +2671,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
FoundConstructor = true;
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
- // TODO: check whether evaluating default arguments can throw.
+ // FIXME: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- if (!CPT->hasEmptyExceptionSpec() || CPT->getNumArgs() > 1) {
+ if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) {
AllNoThrow = false;
break;
}
@@ -2495,7 +2708,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
= Constructor->getType()->getAs<FunctionProtoType>();
// TODO: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- return CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0;
+ return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
}
}
}
@@ -2510,7 +2723,17 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T,
return Destructor->isVirtual();
}
return false;
+
+ // These type trait expressions are modeled on the specifications for the
+ // Embarcadero C++0x type trait functions:
+ // http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+ case UTT_IsCompleteType:
+ // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_):
+ // Returns True if and only if T is a complete type at the point of the
+ // function call.
+ return !T->isIncompleteType();
}
+ llvm_unreachable("Type trait not covered by switch");
}
ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT,
@@ -2518,23 +2741,12 @@ ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT,
TypeSourceInfo *TSInfo,
SourceLocation RParen) {
QualType T = TSInfo->getType();
-
- // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
- // all traits except __is_class, __is_enum and __is_union require a the type
- // to be complete, an array of unknown bound, or void.
- if (UTT != UTT_IsClass && UTT != UTT_IsEnum && UTT != UTT_IsUnion) {
- QualType E = T;
- if (T->isIncompleteArrayType())
- E = Context.getAsArrayType(T)->getElementType();
- if (!T->isVoidType() &&
- RequireCompleteType(KWLoc, E,
- diag::err_incomplete_type_used_in_type_trait_expr))
- return ExprError();
- }
+ if (!CheckUnaryTypeTraitTypeCompleteness(*this, UTT, KWLoc, T))
+ return ExprError();
bool Value = false;
if (!T->isDependentType())
- Value = EvaluateUnaryTypeTrait(*this, UTT, T, KWLoc);
+ Value = EvaluateUnaryTypeTrait(*this, UTT, KWLoc, T);
return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, UTT, TSInfo, Value,
RParen, Context.BoolTy));
@@ -2561,8 +2773,8 @@ ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT,
static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
QualType LhsT, QualType RhsT,
SourceLocation KeyLoc) {
- assert((!LhsT->isDependentType() || RhsT->isDependentType()) &&
- "Cannot evaluate traits for dependent types.");
+ assert(!LhsT->isDependentType() && !RhsT->isDependentType() &&
+ "Cannot evaluate traits of dependent types");
switch(BTT) {
case BTT_IsBaseOf: {
@@ -2594,11 +2806,12 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
return cast<CXXRecordDecl>(rhsRecord->getDecl())
->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl()));
}
-
+ case BTT_IsSame:
+ return Self.Context.hasSameType(LhsT, RhsT);
case BTT_TypeCompatible:
return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(),
RhsT.getUnqualifiedType());
-
+ case BTT_IsConvertible:
case BTT_IsConvertibleTo: {
// C++0x [meta.rel]p4:
// Given the following function prototype:
@@ -2673,6 +2886,8 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
QualType ResultType;
switch (BTT) {
case BTT_IsBaseOf: ResultType = Context.BoolTy; break;
+ case BTT_IsConvertible: ResultType = Context.BoolTy; break;
+ case BTT_IsSame: ResultType = Context.BoolTy; break;
case BTT_TypeCompatible: ResultType = Context.IntTy; break;
case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break;
}
@@ -2682,7 +2897,138 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
ResultType));
}
-QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex,
+ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT,
+ SourceLocation KWLoc,
+ ParsedType Ty,
+ Expr* DimExpr,
+ SourceLocation RParen) {
+ TypeSourceInfo *TSInfo;
+ QualType T = GetTypeFromParser(Ty, &TSInfo);
+ if (!TSInfo)
+ TSInfo = Context.getTrivialTypeSourceInfo(T);
+
+ return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen);
+}
+
+static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
+ QualType T, Expr *DimExpr,
+ SourceLocation KeyLoc) {
+ assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
+
+ switch(ATT) {
+ case ATT_ArrayRank:
+ if (T->isArrayType()) {
+ unsigned Dim = 0;
+ while (const ArrayType *AT = Self.Context.getAsArrayType(T)) {
+ ++Dim;
+ T = AT->getElementType();
+ }
+ return Dim;
+ }
+ return 0;
+
+ case ATT_ArrayExtent: {
+ llvm::APSInt Value;
+ uint64_t Dim;
+ if (DimExpr->isIntegerConstantExpr(Value, Self.Context, 0, false)) {
+ if (Value < llvm::APSInt(Value.getBitWidth(), Value.isUnsigned())) {
+ Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) <<
+ DimExpr->getSourceRange();
+ return false;
+ }
+ Dim = Value.getLimitedValue();
+ } else {
+ Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) <<
+ DimExpr->getSourceRange();
+ return false;
+ }
+
+ if (T->isArrayType()) {
+ unsigned D = 0;
+ bool Matched = false;
+ while (const ArrayType *AT = Self.Context.getAsArrayType(T)) {
+ if (Dim == D) {
+ Matched = true;
+ break;
+ }
+ ++D;
+ T = AT->getElementType();
+ }
+
+ if (Matched && T->isArrayType()) {
+ if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T))
+ return CAT->getSize().getLimitedValue();
+ }
+ }
+ return 0;
+ }
+ }
+ llvm_unreachable("Unknown type trait or not implemented");
+}
+
+ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT,
+ SourceLocation KWLoc,
+ TypeSourceInfo *TSInfo,
+ Expr* DimExpr,
+ SourceLocation RParen) {
+ QualType T = TSInfo->getType();
+
+ // FIXME: This should likely be tracked as an APInt to remove any host
+ // assumptions about the width of size_t on the target.
+ uint64_t Value = 0;
+ if (!T->isDependentType())
+ Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc);
+
+ // While the specification for these traits from the Embarcadero C++
+ // compiler's documentation says the return type is 'unsigned int', Clang
+ // returns 'size_t'. On Windows, the primary platform for the Embarcadero
+ // compiler, there is no difference. On several other platforms this is an
+ // important distinction.
+ return Owned(new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value,
+ DimExpr, RParen,
+ Context.getSizeType()));
+}
+
+ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
+ SourceLocation KWLoc,
+ Expr *Queried,
+ SourceLocation RParen) {
+ // If error parsing the expression, ignore.
+ if (!Queried)
+ return ExprError();
+
+ ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen);
+
+ return move(Result);
+}
+
+static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) {
+ switch (ET) {
+ case ET_IsLValueExpr: return E->isLValue();
+ case ET_IsRValueExpr: return E->isRValue();
+ }
+ llvm_unreachable("Expression trait not covered by switch");
+}
+
+ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET,
+ SourceLocation KWLoc,
+ Expr *Queried,
+ SourceLocation RParen) {
+ if (Queried->isTypeDependent()) {
+ // Delay type-checking for type-dependent expressions.
+ } else if (Queried->getType()->isPlaceholderType()) {
+ ExprResult PE = CheckPlaceholderExpr(Queried);
+ if (PE.isInvalid()) return ExprError();
+ return BuildExpressionTrait(ET, KWLoc, PE.take(), RParen);
+ }
+
+ bool Value = EvaluateExpressionTrait(ET, Queried);
+
+ return Owned(new (Context) ExpressionTraitExpr(KWLoc, ET, Queried, Value,
+ RParen, Context.BoolTy));
+}
+
+QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
ExprValueKind &VK,
SourceLocation Loc,
bool isIndirect) {
@@ -2691,11 +3037,11 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex,
// The binary operator .* [p3: ->*] binds its second operand, which shall
// be of type "pointer to member of T" (where T is a completely-defined
// class type) [...]
- QualType RType = rex->getType();
+ QualType RType = rex.get()->getType();
const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>();
if (!MemPtr) {
Diag(Loc, diag::err_bad_memptr_rhs)
- << OpSpelling << RType << rex->getSourceRange();
+ << OpSpelling << RType << rex.get()->getSourceRange();
return QualType();
}
@@ -2711,7 +3057,7 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex,
// [...] to its first operand, which shall be of class T or of a class of
// which T is an unambiguous and accessible base class. [p3: a pointer to
// such a class]
- QualType LType = lex->getType();
+ QualType LType = lex.get()->getType();
if (isIndirect) {
if (const PointerType *Ptr = LType->getAs<PointerType>())
LType = Ptr->getPointeeType();
@@ -2736,20 +3082,20 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex,
if (!IsDerivedFrom(LType, Class, Paths) ||
Paths.isAmbiguous(Context.getCanonicalType(Class))) {
Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling
- << (int)isIndirect << lex->getType();
+ << (int)isIndirect << lex.get()->getType();
return QualType();
}
// Cast LHS to type of use.
QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
ExprValueKind VK =
- isIndirect ? VK_RValue : CastCategory(lex);
+ isIndirect ? VK_RValue : CastCategory(lex.get());
CXXCastPath BasePath;
BuildBasePathArray(Paths, BasePath);
- ImpCastExprToType(lex, UseType, CK_DerivedToBase, VK, &BasePath);
+ lex = ImpCastExprToType(lex.take(), UseType, CK_DerivedToBase, VK, &BasePath);
}
- if (isa<CXXScalarValueInitExpr>(rex->IgnoreParens())) {
+ if (isa<CXXScalarValueInitExpr>(rex.get()->IgnoreParens())) {
// Diagnose use of pointer-to-member type which when used as
// the functional cast in a pointer-to-member expression.
Diag(Loc, diag::err_pointer_to_member_type) << isIndirect;
@@ -2761,13 +3107,6 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex,
// second operand.
// The cv qualifiers are the union of those in the pointer and the left side,
// in accordance with 5.5p5 and 5.2.5.
- // FIXME: This returns a dereferenced member function pointer as a normal
- // function type. However, the only operation valid on such functions is
- // calling them. There's also a GCC extension to get a function pointer to the
- // thing, which is another complication, because this type - unlike the type
- // that is the result of this expression - takes the class as the first
- // argument.
- // We probably need a "MemberFunctionClosureType" or something like that.
QualType Result = MemPtr->getPointeeType();
Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers());
@@ -2784,15 +3123,15 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex,
break;
case RQ_LValue:
- if (!isIndirect && !lex->Classify(Context).isLValue())
+ if (!isIndirect && !lex.get()->Classify(Context).isLValue())
Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
- << RType << 1 << lex->getSourceRange();
+ << RType << 1 << lex.get()->getSourceRange();
break;
case RQ_RValue:
- if (isIndirect || !lex->Classify(Context).isRValue())
+ if (isIndirect || !lex.get()->Classify(Context).isRValue())
Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
- << RType << 0 << lex->getSourceRange();
+ << RType << 0 << lex.get()->getSourceRange();
break;
}
}
@@ -2804,12 +3143,14 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex,
// operand is a pointer to a member function is a prvalue. The
// result of an ->* expression is an lvalue if its second operand
// is a pointer to data member and a prvalue otherwise.
- if (Result->isFunctionType())
+ if (Result->isFunctionType()) {
VK = VK_RValue;
- else if (isIndirect)
+ return Context.BoundMemberTy;
+ } else if (isIndirect) {
VK = VK_LValue;
- else
- VK = lex->getValueKind();
+ } else {
+ VK = lex.get()->getValueKind();
+ }
return Result;
}
@@ -2910,43 +3251,52 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
/// This is part of the parameter validation for the ? operator. If either
/// value operand is a class type, overload resolution is used to find a
/// conversion to a common type.
-static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
+static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc) {
- Expr *Args[2] = { LHS, RHS };
+ Expr *Args[2] = { LHS.get(), RHS.get() };
OverloadCandidateSet CandidateSet(QuestionLoc);
Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, 2,
CandidateSet);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) {
- case OR_Success:
+ case OR_Success: {
// We found a match. Perform the conversions on the arguments and move on.
- if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], Sema::AA_Converting) ||
- Self.PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], Sema::AA_Converting))
+ ExprResult LHSRes =
+ Self.PerformImplicitConversion(LHS.get(), Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], Sema::AA_Converting);
+ if (LHSRes.isInvalid())
+ break;
+ LHS = move(LHSRes);
+
+ ExprResult RHSRes =
+ Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1],
+ Best->Conversions[1], Sema::AA_Converting);
+ if (RHSRes.isInvalid())
break;
+ RHS = move(RHSRes);
if (Best->Function)
Self.MarkDeclarationReferenced(QuestionLoc, Best->Function);
return false;
-
+ }
+
case OR_No_Viable_Function:
// Emit a better diagnostic if one of the expressions is a null pointer
// constant and the other is a pointer type. In this case, the user most
// likely forgot to take the address of the other expression.
- if (Self.DiagnoseConditionalForNull(LHS, RHS, QuestionLoc))
+ if (Self.DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc))
return true;
Self.Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
- << LHS->getType() << RHS->getType()
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return true;
case OR_Ambiguous:
Self.Diag(QuestionLoc, diag::err_conditional_ambiguous_ovl)
- << LHS->getType() << RHS->getType()
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
// FIXME: Print the possible common types by printing the return types of
// the viable candidates.
break;
@@ -2960,16 +3310,17 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// \brief Perform an "extended" implicit conversion as returned by
/// TryClassUnification.
-static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) {
+static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
- InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(),
+ InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getLocStart(),
SourceLocation());
- InitializationSequence InitSeq(Self, Entity, Kind, &E, 1);
- ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&E, 1));
+ Expr *Arg = E.take();
+ InitializationSequence InitSeq(Self, Entity, Kind, &Arg, 1);
+ ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&Arg, 1));
if (Result.isInvalid())
return true;
- E = Result.takeAs<Expr>();
+ E = Result;
return false;
}
@@ -2977,7 +3328,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) {
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
/// extension. In this case, LHS == Cond. (But they're not aliases.)
-QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
+QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
ExprValueKind &VK, ExprObjectKind &OK,
SourceLocation QuestionLoc) {
// FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
@@ -2985,9 +3336,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// C++0x 5.16p1
// The first expression is contextually converted to bool.
- if (!Cond->isTypeDependent()) {
- if (CheckCXXBooleanCondition(Cond))
+ if (!Cond.get()->isTypeDependent()) {
+ ExprResult CondRes = CheckCXXBooleanCondition(Cond.take());
+ if (CondRes.isInvalid())
return QualType();
+ Cond = move(CondRes);
}
// Assume r-value.
@@ -2995,28 +3348,30 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
OK = OK_Ordinary;
// Either of the arguments dependent?
- if (LHS->isTypeDependent() || RHS->isTypeDependent())
+ if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent())
return Context.DependentTy;
// C++0x 5.16p2
// If either the second or the third operand has type (cv) void, ...
- QualType LTy = LHS->getType();
- QualType RTy = RHS->getType();
+ QualType LTy = LHS.get()->getType();
+ QualType RTy = RHS.get()->getType();
bool LVoid = LTy->isVoidType();
bool RVoid = RTy->isVoidType();
if (LVoid || RVoid) {
// ... then the [l2r] conversions are performed on the second and third
// operands ...
- DefaultFunctionArrayLvalueConversion(LHS);
- DefaultFunctionArrayLvalueConversion(RHS);
- LTy = LHS->getType();
- RTy = RHS->getType();
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
+ if (LHS.isInvalid() || RHS.isInvalid())
+ return QualType();
+ LTy = LHS.get()->getType();
+ RTy = RHS.get()->getType();
// ... and one of the following shall hold:
// -- The second or the third operand (but not both) is a throw-
// expression; the result is of the type of the other and is an rvalue.
- bool LThrow = isa<CXXThrowExpr>(LHS);
- bool RThrow = isa<CXXThrowExpr>(RHS);
+ bool LThrow = isa<CXXThrowExpr>(LHS.get());
+ bool RThrow = isa<CXXThrowExpr>(RHS.get());
if (LThrow && !RThrow)
return RTy;
if (RThrow && !LThrow)
@@ -3030,7 +3385,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// Neither holds, error.
Diag(QuestionLoc, diag::err_conditional_void_nonvoid)
<< (LVoid ? RTy : LTy) << (LVoid ? 0 : 1)
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
@@ -3046,15 +3401,15 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// These return true if a single direction is already ambiguous.
QualType L2RType, R2LType;
bool HaveL2R, HaveR2L;
- if (TryClassUnification(*this, LHS, RHS, QuestionLoc, HaveL2R, L2RType))
+ if (TryClassUnification(*this, LHS.get(), RHS.get(), QuestionLoc, HaveL2R, L2RType))
return QualType();
- if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType))
+ if (TryClassUnification(*this, RHS.get(), LHS.get(), QuestionLoc, HaveR2L, R2LType))
return QualType();
// If both can be converted, [...] the program is ill-formed.
if (HaveL2R && HaveR2L) {
Diag(QuestionLoc, diag::err_conditional_ambiguous)
- << LTy << RTy << LHS->getSourceRange() << RHS->getSourceRange();
+ << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
@@ -3062,13 +3417,13 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// the chosen operand and the converted operands are used in place of the
// original operands for the remainder of this section.
if (HaveL2R) {
- if (ConvertForConditional(*this, LHS, L2RType))
+ if (ConvertForConditional(*this, LHS, L2RType) || LHS.isInvalid())
return QualType();
- LTy = LHS->getType();
+ LTy = LHS.get()->getType();
} else if (HaveR2L) {
- if (ConvertForConditional(*this, RHS, R2LType))
+ if (ConvertForConditional(*this, RHS, R2LType) || RHS.isInvalid())
return QualType();
- RTy = RHS->getType();
+ RTy = RHS.get()->getType();
}
}
@@ -3081,13 +3436,13 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// l-values.
bool Same = Context.hasSameType(LTy, RTy);
if (Same &&
- LHS->isGLValue() &&
- LHS->getValueKind() == RHS->getValueKind() &&
- LHS->isOrdinaryOrBitFieldObject() &&
- RHS->isOrdinaryOrBitFieldObject()) {
- VK = LHS->getValueKind();
- if (LHS->getObjectKind() == OK_BitField ||
- RHS->getObjectKind() == OK_BitField)
+ LHS.get()->isGLValue() &&
+ LHS.get()->getValueKind() == RHS.get()->getValueKind() &&
+ LHS.get()->isOrdinaryOrBitFieldObject() &&
+ RHS.get()->isOrdinaryOrBitFieldObject()) {
+ VK = LHS.get()->getValueKind();
+ if (LHS.get()->getObjectKind() == OK_BitField ||
+ RHS.get()->getObjectKind() == OK_BitField)
OK = OK_BitField;
return LTy;
}
@@ -3106,10 +3461,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// C++0x 5.16p6
// LValue-to-rvalue, array-to-pointer, and function-to-pointer standard
// conversions are performed on the second and third operands.
- DefaultFunctionArrayLvalueConversion(LHS);
- DefaultFunctionArrayLvalueConversion(RHS);
- LTy = LHS->getType();
- RTy = RHS->getType();
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
+ if (LHS.isInvalid() || RHS.isInvalid())
+ return QualType();
+ LTy = LHS.get()->getType();
+ RTy = RHS.get()->getType();
// After those conversions, one of the following shall hold:
// -- The second and third operands have the same type; the result
@@ -3123,18 +3480,18 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy);
ExprResult LHSCopy = PerformCopyInitialization(Entity,
SourceLocation(),
- Owned(LHS));
+ LHS);
if (LHSCopy.isInvalid())
return QualType();
ExprResult RHSCopy = PerformCopyInitialization(Entity,
SourceLocation(),
- Owned(RHS));
+ RHS);
if (RHSCopy.isInvalid())
return QualType();
- LHS = LHSCopy.takeAs<Expr>();
- RHS = RHSCopy.takeAs<Expr>();
+ LHS = LHSCopy;
+ RHS = RHSCopy;
}
return LTy;
@@ -3149,7 +3506,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// common type, and the result is of that type.
if (LTy->isArithmeticType() && RTy->isArithmeticType()) {
UsualArithmeticConversions(LHS, RHS);
- return LHS->getType();
+ if (LHS.isInvalid() || RHS.isInvalid())
+ return QualType();
+ return LHS.get()->getType();
}
// -- The second and third operands have pointer type, or one has pointer
@@ -3170,7 +3529,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
Diag(QuestionLoc,
diag::ext_typecheck_cond_incompatible_operands_nonstandard)
<< LTy << RTy << Composite
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return Composite;
}
@@ -3181,12 +3540,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return Composite;
// Check if we are using a null with a non-pointer type.
- if (DiagnoseConditionalForNull(LHS, RHS, QuestionLoc))
+ if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc))
return QualType();
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
- << LHS->getType() << RHS->getType()
- << LHS->getSourceRange() << RHS->getSourceRange();
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
@@ -3224,16 +3583,16 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// the type of the other operand.
if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (T2->isMemberPointerType())
- ImpCastExprToType(E1, T2, CK_NullToMemberPointer);
+ E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).take();
else
- ImpCastExprToType(E1, T2, CK_NullToPointer);
+ E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).take();
return T2;
}
if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (T1->isMemberPointerType())
- ImpCastExprToType(E2, T1, CK_NullToMemberPointer);
+ E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).take();
else
- ImpCastExprToType(E2, T1, CK_NullToPointer);
+ E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).take();
return T1;
}
@@ -3763,7 +4122,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
- TypeResult T = ActOnTemplateIdType(TemplateId->Template,
+ TypeResult T = ActOnTemplateIdType(TemplateId->SS,
+ TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
@@ -3811,7 +4171,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
- TypeResult T = ActOnTemplateIdType(TemplateId->Template,
+ TypeResult T = ActOnTemplateIdType(TemplateId->SS,
+ TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
@@ -3834,24 +4195,25 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
Destructed, HasTrailingLParen);
}
-ExprResult Sema::BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,
+ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
CXXMethodDecl *Method) {
- if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0,
- FoundDecl, Method))
+ ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0,
+ FoundDecl, Method);
+ if (Exp.isInvalid())
return true;
MemberExpr *ME =
- new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method,
+ new (Context) MemberExpr(Exp.take(), /*IsArrow=*/false, Method,
SourceLocation(), Method->getType(),
VK_RValue, OK_Ordinary);
QualType ResultType = Method->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
- MarkDeclarationReferenced(Exp->getLocStart(), Method);
+ MarkDeclarationReferenced(Exp.get()->getLocStart(), Method);
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK,
- Exp->getLocEnd());
+ Exp.get()->getLocEnd());
return CE;
}
@@ -3869,46 +4231,62 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
/// Perform the conversions required for an expression used in a
/// context that ignores the result.
-void Sema::IgnoredValueConversions(Expr *&E) {
+ExprResult Sema::IgnoredValueConversions(Expr *E) {
// C99 6.3.2.1:
// [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the
// designated object (and is no longer an lvalue).
- if (E->isRValue()) return;
+ if (E->isRValue()) return Owned(E);
// We always want to do this on ObjC property references.
if (E->getObjectKind() == OK_ObjCProperty) {
- ConvertPropertyForRValue(E);
- if (E->isRValue()) return;
+ ExprResult Res = ConvertPropertyForRValue(E);
+ if (Res.isInvalid()) return Owned(E);
+ E = Res.take();
+ if (E->isRValue()) return Owned(E);
}
// Otherwise, this rule does not apply in C++, at least not for the moment.
- if (getLangOptions().CPlusPlus) return;
+ if (getLangOptions().CPlusPlus) return Owned(E);
// GCC seems to also exclude expressions of incomplete enum type.
if (const EnumType *T = E->getType()->getAs<EnumType>()) {
if (!T->getDecl()->isComplete()) {
// FIXME: stupid workaround for a codegen bug!
- ImpCastExprToType(E, Context.VoidTy, CK_ToVoid);
- return;
+ E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).take();
+ return Owned(E);
}
}
- DefaultFunctionArrayLvalueConversion(E);
+ ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
+ if (Res.isInvalid())
+ return Owned(E);
+ E = Res.take();
+
if (!E->getType()->isVoidType())
RequireCompleteType(E->getExprLoc(), E->getType(),
diag::err_incomplete_type);
+ return Owned(E);
}
-ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) {
- if (!FullExpr)
+ExprResult Sema::ActOnFinishFullExpr(Expr *FE) {
+ ExprResult FullExpr = Owned(FE);
+
+ if (!FullExpr.get())
+ return ExprError();
+
+ if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
+ return ExprError();
+
+ FullExpr = CheckPlaceholderExpr(FullExpr.take());
+ if (FullExpr.isInvalid())
return ExprError();
- if (DiagnoseUnexpandedParameterPack(FullExpr))
+ FullExpr = IgnoredValueConversions(FullExpr.take());
+ if (FullExpr.isInvalid())
return ExprError();
- IgnoredValueConversions(FullExpr);
- CheckImplicitConversions(FullExpr);
+ CheckImplicitConversions(FullExpr.get());
return MaybeCreateExprWithCleanups(FullExpr);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 4d03b068ca85..2a262f093922 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -62,7 +62,8 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// Create the aggregate string with the appropriate content and location
// information.
- S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), false,
+ S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(),
+ /*Wide=*/false, /*Pascal=*/false,
Context.getPointerType(Context.CharTy),
&StrLocs[0], StrLocs.size());
}
@@ -246,7 +247,10 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
if (Args[i]->isTypeDependent())
continue;
- DefaultArgumentPromotion(Args[i]);
+ ExprResult Result = DefaultArgumentPromotion(Args[i]);
+ if (Result.isInvalid())
+ return true;
+ Args[i] = Result.take();
}
unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
@@ -305,7 +309,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
if (Args[i]->isTypeDependent())
continue;
- IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
+ ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
+ IsError |= Arg.isInvalid();
+ Args[i] = Arg.take();
}
} else {
// Check for extra arguments to non-variadic methods.
@@ -318,12 +324,24 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
Args[NumArgs-1]->getLocEnd());
}
}
+ // diagnose nonnull arguments.
+ for (specific_attr_iterator<NonNullAttr>
+ i = Method->specific_attr_begin<NonNullAttr>(),
+ e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) {
+ CheckNonNullArguments(*i, Args, lbrac);
+ }
DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs);
return IsError;
}
bool Sema::isSelfExpr(Expr *RExpr) {
+ // 'self' is objc 'self' in an objc method only.
+ DeclContext *DC = CurContext;
+ while (isa<BlockDecl>(DC))
+ DC = DC->getParent();
+ if (DC && !isa<ObjCMethodDecl>(DC))
+ return false;
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr))
if (ICE->getCastKind() == CK_LValueToRValue)
RExpr = ICE->getSubExpr();
@@ -381,6 +399,23 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
return Method;
}
+/// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier
+/// list of a qualified objective pointer type.
+ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
+ const ObjCObjectPointerType *OPT,
+ bool Instance)
+{
+ ObjCMethodDecl *MD = 0;
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I) {
+ ObjCProtocolDecl *PROTO = (*I);
+ if ((MD = PROTO->lookupMethod(Sel, Instance))) {
+ return MD;
+ }
+ }
+ return 0;
+}
+
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
/// objective C interface. This is a property reference expression.
ExprResult Sema::
@@ -391,6 +426,13 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
bool Super) {
const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
ObjCInterfaceDecl *IFace = IFaceT->getDecl();
+
+ if (MemberName.getNameKind() != DeclarationName::Identifier) {
+ Diag(MemberLoc, diag::err_invalid_property_name)
+ << MemberName << QualType(OPT, 0);
+ return ExprError();
+ }
+
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
if (IFace->isForwardDecl()) {
@@ -405,6 +447,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
QualType ResTy = PD->getType();
+ ResTy = ResTy.getNonLValueExprType(Context);
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
@@ -448,6 +491,10 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
+
+ // May be founf in property's qualified list.
+ if (!Getter)
+ Getter = LookupMethodInQualifiedType(Sel, OPT, true);
// If this reference is in an @implementation, check for 'private' methods.
if (!Getter)
@@ -467,6 +514,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
SelectorTable::constructSetterName(PP.getIdentifierTable(),
PP.getSelectorTable(), Member);
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
+
+ // May be founf in property's qualified list.
+ if (!Setter)
+ Setter = LookupMethodInQualifiedType(SetterSel, OPT, true);
+
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
// methods.
@@ -475,7 +527,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Look through local category implementations associated with the class.
if (!Setter)
Setter = IFace->getCategoryInstanceMethod(SetterSel);
-
+
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
@@ -868,7 +920,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
return ExprError();
}
assert(Class && "We don't know which class we're messaging?");
-
+ (void)DiagnoseUseOfDecl(Class, Loc);
// Find the method we are messaging.
if (!Method) {
if (Class->isForwardDecl()) {
@@ -1007,7 +1059,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- DefaultFunctionArrayLvalueConversion(Receiver);
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(Receiver);
+ if (Result.isInvalid())
+ return ExprError();
+ Receiver = Result.take();
ReceiverType = Receiver->getType();
}
@@ -1026,39 +1081,53 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
} else if (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType()) {
// Handle messages to Class.
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
- // First check the public methods in the class interface.
- Method = ClassDecl->lookupClassMethod(Sel);
-
- if (!Method)
- Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ // We allow sending a message to a qualified Class ("Class<foo>"), which
+ // is ok as long as one of the protocols implements the selector (if not, warn).
+ if (const ObjCObjectPointerType *QClassTy
+ = ReceiverType->getAsObjCQualifiedClassType()) {
+ // Search protocols for class methods.
+ Method = LookupMethodInQualifiedType(Sel, QClassTy, false);
+ if (!Method) {
+ Method = LookupMethodInQualifiedType(Sel, QClassTy, true);
+ // warn if instance method found for a Class message.
+ if (Method) {
+ Diag(Loc, diag::warn_instance_method_on_class_found)
+ << Method->getSelector() << Sel;
+ Diag(Method->getLocation(), diag::note_method_declared_at);
+ }
+ }
+ } else {
+ if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
+ if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
+ // First check the public methods in the class interface.
+ Method = ClassDecl->lookupClassMethod(Sel);
- // FIXME: if we still haven't found a method, we need to look in
- // protocols (if we have qualifiers).
+ if (!Method)
+ Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ }
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
}
- if (Method && DiagnoseUseOfDecl(Method, Loc))
- return ExprError();
- }
- if (!Method) {
- // If not messaging 'self', look for any factory method named 'Sel'.
- if (!Receiver || !isSelfExpr(Receiver)) {
- Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc),
- true);
- if (!Method) {
- // If no class (factory) method was found, check if an _instance_
- // method of the same name exists in the root class only.
- Method = LookupInstanceMethodInGlobalPool(Sel,
+ if (!Method) {
+ // If not messaging 'self', look for any factory method named 'Sel'.
+ if (!Receiver || !isSelfExpr(Receiver)) {
+ Method = LookupFactoryMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc),
+ true);
+ if (!Method) {
+ // If no class (factory) method was found, check if an _instance_
+ // method of the same name exists in the root class only.
+ Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc),
- true);
- if (Method)
- if (const ObjCInterfaceDecl *ID =
- dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
- if (ID->getSuperClass())
- Diag(Loc, diag::warn_root_inst_method_not_found)
- << Sel << SourceRange(LBracLoc, RBracLoc);
- }
+ true);
+ if (Method)
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
+ if (ID->getSuperClass())
+ Diag(Loc, diag::warn_root_inst_method_not_found)
+ << Sel << SourceRange(LBracLoc, RBracLoc);
+ }
+ }
}
}
}
@@ -1070,15 +1139,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (const ObjCObjectPointerType *QIdTy
= ReceiverType->getAsObjCQualifiedIdType()) {
// Search protocols for instance methods.
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *PDecl = *I;
- if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
- break;
- // Since we aren't supporting "Class<foo>", look for a class method.
- if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
- break;
- }
+ Method = LookupMethodInQualifiedType(Sel, QIdTy, true);
+ if (!Method)
+ Method = LookupMethodInQualifiedType(Sel, QIdTy, false);
} else if (const ObjCObjectPointerType *OCIType
= ReceiverType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
@@ -1088,15 +1151,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// The idea is to add class info to MethodPool.
Method = ClassDecl->lookupInstanceMethod(Sel);
- if (!Method) {
+ if (!Method)
// Search protocol qualifiers.
- for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
- E = OCIType->qual_end(); QI != E; ++QI) {
- if ((Method = (*QI)->lookupInstanceMethod(Sel)))
- break;
- }
- }
- bool forwardClass = false;
+ Method = LookupMethodInQualifiedType(Sel, OCIType, true);
+
+ const ObjCInterfaceDecl *forwardClass = 0;
if (!Method) {
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
@@ -1108,7 +1167,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
- forwardClass = OCIType->getInterfaceDecl()->isForwardDecl();
+ if (OCIType->getInterfaceDecl()->isForwardDecl())
+ forwardClass = OCIType->getInterfaceDecl();
if (Method && !forwardClass)
Diag(Loc, diag::warn_maynot_respond)
<< OCIType->getInterfaceDecl()->getIdentifier() << Sel;
@@ -1125,37 +1185,42 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
<< ReceiverType
<< Receiver->getSourceRange();
if (ReceiverType->isPointerType())
- ImpCastExprToType(Receiver, Context.getObjCIdType(),
- CK_BitCast);
+ Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CK_BitCast).take();
else {
// TODO: specialized warning on null receivers?
bool IsNull = Receiver->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
- ImpCastExprToType(Receiver, Context.getObjCIdType(),
- IsNull ? CK_NullToPointer : CK_IntegralToPointer);
+ Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ IsNull ? CK_NullToPointer : CK_IntegralToPointer).take();
}
ReceiverType = Receiver->getType();
}
- else if (getLangOptions().CPlusPlus &&
- !PerformContextuallyConvertToObjCId(Receiver)) {
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) {
- Receiver = ICE->getSubExpr();
- ReceiverType = Receiver->getType();
+ else {
+ ExprResult ReceiverRes;
+ if (getLangOptions().CPlusPlus)
+ ReceiverRes = PerformContextuallyConvertToObjCId(Receiver);
+ if (ReceiverRes.isUsable()) {
+ Receiver = ReceiverRes.take();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) {
+ Receiver = ICE->getSubExpr();
+ ReceiverType = Receiver->getType();
+ }
+ return BuildInstanceMessage(Receiver,
+ ReceiverType,
+ SuperLoc,
+ Sel,
+ Method,
+ LBracLoc,
+ SelectorLoc,
+ RBracLoc,
+ move(ArgsIn));
+ } else {
+ // Reject other random receiver types (e.g. structs).
+ Diag(Loc, diag::err_bad_receiver_type)
+ << ReceiverType << Receiver->getSourceRange();
+ return ExprError();
}
- return BuildInstanceMessage(Receiver,
- ReceiverType,
- SuperLoc,
- Sel,
- Method,
- LBracLoc,
- SelectorLoc,
- RBracLoc,
- move(ArgsIn));
- } else {
- // Reject other random receiver types (e.g. structs).
- Diag(Loc, diag::err_bad_receiver_type)
- << ReceiverType << Receiver->getSourceRange();
- return ExprError();
}
}
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 5882da0eab46..ca3fd6dfcb45 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -92,13 +92,31 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
- // C99 6.7.8p14. We have an array of character type with known size. However,
+ // We have an array of character type with known size. However,
// the size may be smaller or larger than the string we are initializing.
// FIXME: Avoid truncation for 64-bit length strings.
- if (StrLength-1 > CAT->getSize().getZExtValue())
- S.Diag(Str->getSourceRange().getBegin(),
- diag::warn_initializer_string_for_char_array_too_long)
- << Str->getSourceRange();
+ if (S.getLangOptions().CPlusPlus) {
+ if (StringLiteral *SL = dyn_cast<StringLiteral>(Str)) {
+ // For Pascal strings it's OK to strip off the terminating null character,
+ // so the example below is valid:
+ //
+ // unsigned char a[2] = "\pa";
+ if (SL->isPascal())
+ StrLength--;
+ }
+
+ // [dcl.init.string]p2
+ if (StrLength > CAT->getSize().getZExtValue())
+ S.Diag(Str->getSourceRange().getBegin(),
+ diag::err_initializer_string_for_char_array_too_long)
+ << Str->getSourceRange();
+ } else {
+ // C99 6.7.8p14.
+ if (StrLength-1 > CAT->getSize().getZExtValue())
+ S.Diag(Str->getSourceRange().getBegin(),
+ diag::warn_initializer_string_for_char_array_too_long)
+ << Str->getSourceRange();
+ }
// Set the type to the actual size that we are initializing. If we have
// something like:
@@ -386,15 +404,29 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
if (hadError) {
// Do nothing
} else if (Init < NumInits) {
- ILE->setInit(Init, ElementInit.takeAs<Expr>());
- } else if (InitSeq.getKind()
+ // For arrays, just set the expression used for value-initialization
+ // of the "holes" in the array.
+ if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement)
+ ILE->setArrayFiller(ElementInit.takeAs<Expr>());
+ else
+ ILE->setInit(Init, ElementInit.takeAs<Expr>());
+ } else {
+ // For arrays, just set the expression used for value-initialization
+ // of the rest of elements and exit.
+ if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) {
+ ILE->setArrayFiller(ElementInit.takeAs<Expr>());
+ return;
+ }
+
+ if (InitSeq.getKind()
== InitializationSequence::ConstructorInitialization) {
- // Value-initialization requires a constructor call, so
- // extend the initializer list to include the constructor
- // call and make a note that we'll need to take another pass
- // through the initializer list.
- ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
- RequiresSecondPass = true;
+ // Value-initialization requires a constructor call, so
+ // extend the initializer list to include the constructor
+ // call and make a note that we'll need to take another pass
+ // through the initializer list.
+ ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
+ RequiresSecondPass = true;
+ }
}
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
@@ -713,15 +745,23 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// compatible structure or union type. In the latter case, the
// initial value of the object, including unnamed members, is
// that of the expression.
+ ExprResult ExprRes = SemaRef.Owned(expr);
if ((ElemType->isRecordType() || ElemType->isVectorType()) &&
- SemaRef.CheckSingleAssignmentConstraints(ElemType, expr)
+ SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes)
== Sema::Compatible) {
- SemaRef.DefaultFunctionArrayLvalueConversion(expr);
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ if (ExprRes.isInvalid())
+ hadError = true;
+ else {
+ ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.take());
+ if (ExprRes.isInvalid())
+ hadError = true;
+ }
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ ExprRes.takeAs<Expr>());
++Index;
return;
}
-
+ ExprRes.release();
// Fall through for subaggregate initialization
}
@@ -1755,11 +1795,15 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
unsigned NumInits = 0;
- if (!StructuredList)
+ bool GotNumInits = false;
+ if (!StructuredList) {
NumInits = IList->getNumInits();
- else if (Index < IList->getNumInits()) {
- if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index)))
+ GotNumInits = true;
+ } else if (Index < IList->getNumInits()) {
+ if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) {
NumInits = SubList->getNumInits();
+ GotNumInits = true;
+ }
}
if (const ArrayType *AType
@@ -1768,7 +1812,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
NumElements = CAType->getSize().getZExtValue();
// Simple heuristic so that we don't allocate a very large
// initializer with many empty entries at the end.
- if (NumInits && NumElements > NumInits)
+ if (GotNumInits && NumElements > NumInits)
NumElements = 0;
}
} else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>())
@@ -1936,6 +1980,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
Loc, GNUSyntax, Init.takeAs<Expr>());
if (getLangOptions().CPlusPlus)
+ Diag(DIE->getLocStart(), diag::ext_designated_init_cxx)
+ << DIE->getSourceRange();
+ else if (!getLangOptions().C99)
Diag(DIE->getLocStart(), diag::ext_designated_init)
<< DIE->getSourceRange();
@@ -1998,6 +2045,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_New:
case EK_Temporary:
case EK_Base:
+ case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_BlockElement:
@@ -2020,6 +2068,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
case EK_New:
case EK_Temporary:
case EK_Base:
+ case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_BlockElement:
@@ -2042,6 +2091,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_New:
case EK_Temporary:
case EK_Base:
+ case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_BlockElement:
@@ -2101,6 +2151,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_ReferenceInitDropsQualifiers:
case FK_ReferenceInitFailed:
case FK_ConversionFailed:
+ case FK_ConversionFromPropertyFailed:
case FK_TooManyInitsForScalar:
case FK_ReferenceBindingToInitList:
case FK_InitListBadDestinationType:
@@ -3126,8 +3177,14 @@ InitializationSequence::InitializationSequence(Sema &S,
}
for (unsigned I = 0; I != NumArgs; ++I)
- if (Args[I]->getObjectKind() == OK_ObjCProperty)
- S.ConvertPropertyForRValue(Args[I]);
+ if (Args[I]->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = S.ConvertPropertyForRValue(Args[I]);
+ if (Result.isInvalid()) {
+ SetFailed(FK_ConversionFromPropertyFailed);
+ return;
+ }
+ Args[I] = Result.take();
+ }
QualType SourceType;
Expr *Initializer = 0;
@@ -3289,6 +3346,7 @@ getAssignmentAction(const InitializedEntity &Entity) {
case InitializedEntity::EK_New:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
return Sema::AA_Initializing;
case InitializedEntity::EK_Parameter:
@@ -3325,6 +3383,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_New:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_BlockElement:
@@ -3346,6 +3405,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_Result:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_BlockElement:
return false;
@@ -3430,6 +3490,7 @@ static ExprResult CopyObject(Sema &S,
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_BlockElement:
Loc = CurInitExpr->getLocStart();
@@ -3686,14 +3747,15 @@ InitializationSequence::Perform(Sema &S,
case SK_ObjCObjectConversion:
case SK_ArrayInit: {
assert(Args.size() == 1);
- Expr *CurInitExpr = Args.get()[0];
- if (!CurInitExpr) return ExprError();
+ CurInit = Args.get()[0];
+ if (!CurInit.get()) return ExprError();
// Read from a property when initializing something with it.
- if (CurInitExpr->getObjectKind() == OK_ObjCProperty)
- S.ConvertPropertyForRValue(CurInitExpr);
-
- CurInit = ExprResult(CurInitExpr);
+ if (CurInit.get()->getObjectKind() == OK_ObjCProperty) {
+ CurInit = S.ConvertPropertyForRValue(CurInit.take());
+ if (CurInit.isInvalid())
+ return ExprError();
+ }
break;
}
@@ -3710,14 +3772,13 @@ InitializationSequence::Perform(Sema &S,
if (CurInit.isInvalid())
return ExprError();
- Expr *CurInitExpr = CurInit.get();
- QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType();
+ QualType SourceType = CurInit.get() ? CurInit.get()->getType() : QualType();
switch (Step->Kind) {
case SK_ResolveAddressOfOverloadedFunction:
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
- S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl);
+ S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl);
S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation());
CurInit = S.FixOverloadedFunctionReference(move(CurInit),
Step->Function.FoundDecl,
@@ -3735,8 +3796,8 @@ InitializationSequence::Perform(Sema &S,
// Casts to inaccessible base classes are allowed with C-style casts.
bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
if (S.CheckDerivedToBaseConversion(SourceType, Step->Type,
- CurInitExpr->getLocStart(),
- CurInitExpr->getSourceRange(),
+ CurInit.get()->getLocStart(),
+ CurInit.get()->getSourceRange(),
&BasePath, IgnoreBaseAccess))
return ExprError();
@@ -3745,7 +3806,7 @@ InitializationSequence::Perform(Sema &S,
if (const PointerType *Pointer = T->getAs<PointerType>())
T = Pointer->getPointeeType();
if (const RecordType *RecordTy = T->getAs<RecordType>())
- S.MarkVTableUsed(CurInitExpr->getLocStart(),
+ S.MarkVTableUsed(CurInit.get()->getLocStart(),
cast<CXXRecordDecl>(RecordTy->getDecl()));
}
@@ -3764,21 +3825,21 @@ InitializationSequence::Perform(Sema &S,
}
case SK_BindReference:
- if (FieldDecl *BitField = CurInitExpr->getBitField()) {
+ if (FieldDecl *BitField = CurInit.get()->getBitField()) {
// References cannot bind to bit fields (C++ [dcl.init.ref]p5).
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
<< Entity.getType().isVolatileQualified()
<< BitField->getDeclName()
- << CurInitExpr->getSourceRange();
+ << CurInit.get()->getSourceRange();
S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
return ExprError();
}
- if (CurInitExpr->refersToVectorElement()) {
+ if (CurInit.get()->refersToVectorElement()) {
// References cannot bind to vector elements.
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
<< Entity.getType().isVolatileQualified()
- << CurInitExpr->getSourceRange();
+ << CurInit.get()->getSourceRange();
PrintInitLocationNote(S, Entity);
return ExprError();
}
@@ -3786,7 +3847,7 @@ InitializationSequence::Perform(Sema &S,
// Reference binding does not have any corresponding ASTs.
// Check exception specifications
- if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
+ if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
break;
@@ -3795,7 +3856,7 @@ InitializationSequence::Perform(Sema &S,
// Reference binding does not have any corresponding ASTs.
// Check exception specifications
- if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
+ if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
break;
@@ -3817,13 +3878,14 @@ InitializationSequence::Perform(Sema &S,
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
ASTOwningVector<Expr*> ConstructorArgs(S);
- SourceLocation Loc = CurInitExpr->getLocStart();
+ SourceLocation Loc = CurInit.get()->getLocStart();
CurInit.release(); // Ownership transferred into MultiExprArg, below.
// Determine the arguments required to actually perform the constructor
// call.
+ Expr *Arg = CurInit.get();
if (S.CompleteConstructorCall(Constructor,
- MultiExprArg(&CurInitExpr, 1),
+ MultiExprArg(&Arg, 1),
Loc, ConstructorArgs))
return ExprError();
@@ -3851,23 +3913,22 @@ InitializationSequence::Perform(Sema &S,
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
IsLvalue = Conversion->getResultType()->isLValueReferenceType();
- S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
+ S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0,
FoundFn);
S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation());
// FIXME: Should we move this initialization into a separate
// derived-to-base conversion? I believe the answer is "no", because
// we don't want to turn off access control here for c-style casts.
- if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0,
- FoundFn, Conversion))
+ ExprResult CurInitExprRes =
+ S.PerformObjectArgumentInitialization(CurInit.take(), /*Qualifier=*/0,
+ FoundFn, Conversion);
+ if(CurInitExprRes.isInvalid())
return ExprError();
-
- // Do a little dance to make sure that CurInit has the proper
- // pointer.
- CurInit.release();
+ CurInit = move(CurInitExprRes);
// Build the actual call to the conversion function.
- CurInit = S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, Conversion);
+ CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion);
if (CurInit.isInvalid() || !CurInit.get())
return ExprError();
@@ -3881,23 +3942,21 @@ InitializationSequence::Perform(Sema &S,
if (RequiresCopy || shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
else if (CreatedObject && shouldDestroyTemporary(Entity)) {
- CurInitExpr = static_cast<Expr *>(CurInit.get());
- QualType T = CurInitExpr->getType();
+ QualType T = CurInit.get()->getType();
if (const RecordType *Record = T->getAs<RecordType>()) {
CXXDestructorDecl *Destructor
= S.LookupDestructor(cast<CXXRecordDecl>(Record->getDecl()));
- S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor,
+ S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor,
S.PDiag(diag::err_access_dtor_temp) << T);
- S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor);
- S.DiagnoseUseOfDecl(Destructor, CurInitExpr->getLocStart());
+ S.MarkDeclarationReferenced(CurInit.get()->getLocStart(), Destructor);
+ S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart());
}
}
- CurInitExpr = CurInit.takeAs<Expr>();
// FIXME: xvalues
CurInit = S.Owned(ImplicitCastExpr::Create(S.Context,
- CurInitExpr->getType(),
- CastKind, CurInitExpr, 0,
+ CurInit.get()->getType(),
+ CastKind, CurInit.get(), 0,
IsLvalue ? VK_LValue : VK_RValue));
if (RequiresCopy)
@@ -3917,25 +3976,23 @@ InitializationSequence::Perform(Sema &S,
(Step->Kind == SK_QualificationConversionXValue ?
VK_XValue :
VK_RValue);
- S.ImpCastExprToType(CurInitExpr, Step->Type, CK_NoOp, VK);
- CurInit.release();
- CurInit = S.Owned(CurInitExpr);
+ CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type, CK_NoOp, VK);
break;
}
case SK_ConversionSequence: {
- if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS,
- getAssignmentAction(Entity),
- Kind.isCStyleOrFunctionalCast()))
+ ExprResult CurInitExprRes =
+ S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
+ getAssignmentAction(Entity),
+ Kind.isCStyleOrFunctionalCast());
+ if (CurInitExprRes.isInvalid())
return ExprError();
-
- CurInit.release();
- CurInit = S.Owned(CurInitExpr);
+ CurInit = move(CurInitExprRes);
break;
}
case SK_ListInitialization: {
- InitListExpr *InitList = cast<InitListExpr>(CurInitExpr);
+ InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
QualType Ty = Step->Type;
if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty))
return ExprError();
@@ -4004,6 +4061,9 @@ InitializationSequence::Perform(Sema &S,
CXXConstructExpr::CK_VirtualBase :
CXXConstructExpr::CK_NonVirtualBase;
}
+ if (Entity.getKind() == InitializedEntity::EK_Delegating) {
+ ConstructKind = CXXConstructExpr::CK_Delegating;
+ }
// Only get the parenthesis range if it is a direct construction.
SourceRange parenRange =
@@ -4068,54 +4128,57 @@ InitializationSequence::Perform(Sema &S,
}
case SK_CAssignment: {
- QualType SourceType = CurInitExpr->getType();
+ QualType SourceType = CurInit.get()->getType();
+ ExprResult Result = move(CurInit);
Sema::AssignConvertType ConvTy =
- S.CheckSingleAssignmentConstraints(Step->Type, CurInitExpr);
+ S.CheckSingleAssignmentConstraints(Step->Type, Result);
+ if (Result.isInvalid())
+ return ExprError();
+ CurInit = move(Result);
// If this is a call, allow conversion to a transparent union.
+ ExprResult CurInitExprRes = move(CurInit);
if (ConvTy != Sema::Compatible &&
Entity.getKind() == InitializedEntity::EK_Parameter &&
- S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExpr)
+ S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes)
== Sema::Compatible)
ConvTy = Sema::Compatible;
+ if (CurInitExprRes.isInvalid())
+ return ExprError();
+ CurInit = move(CurInitExprRes);
bool Complained;
if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
Step->Type, SourceType,
- CurInitExpr,
+ CurInit.get(),
getAssignmentAction(Entity),
&Complained)) {
PrintInitLocationNote(S, Entity);
return ExprError();
} else if (Complained)
PrintInitLocationNote(S, Entity);
-
- CurInit.release();
- CurInit = S.Owned(CurInitExpr);
break;
}
case SK_StringInit: {
QualType Ty = Step->Type;
- CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty,
+ CheckStringInit(CurInit.get(), ResultType ? *ResultType : Ty,
S.Context.getAsArrayType(Ty), S);
break;
}
case SK_ObjCObjectConversion:
- S.ImpCastExprToType(CurInitExpr, Step->Type,
+ CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type,
CK_ObjCObjectLValueCast,
- S.CastCategory(CurInitExpr));
- CurInit.release();
- CurInit = S.Owned(CurInitExpr);
+ S.CastCategory(CurInit.get()));
break;
case SK_ArrayInit:
// Okay: we checked everything before creating this step. Note that
// this is a GNU extension.
S.Diag(Kind.getLocation(), diag::ext_array_init_copy)
- << Step->Type << CurInitExpr->getType()
- << CurInitExpr->getSourceRange();
+ << Step->Type << CurInit.get()->getType()
+ << CurInit.get()->getSourceRange();
// If the destination type is an incomplete array type, update the
// type accordingly.
@@ -4123,7 +4186,7 @@ InitializationSequence::Perform(Sema &S,
if (const IncompleteArrayType *IncompleteDest
= S.Context.getAsIncompleteArrayType(Step->Type)) {
if (const ConstantArrayType *ConstantSource
- = S.Context.getAsConstantArrayType(CurInitExpr->getType())) {
+ = S.Context.getAsConstantArrayType(CurInit.get()->getType())) {
*ResultType = S.Context.getConstantArrayType(
IncompleteDest->getElementType(),
ConstantSource->getSize(),
@@ -4283,6 +4346,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
}
+
+ case FK_ConversionFromPropertyFailed:
+ // No-op. This error has already been reported.
+ break;
+
case FK_TooManyInitsForScalar: {
SourceRange R;
@@ -4482,6 +4550,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
OS << "conversion failed";
break;
+ case FK_ConversionFromPropertyFailed:
+ OS << "conversion from property failed";
+ break;
+
case FK_TooManyInitsForScalar:
OS << "too many initializers for scalar";
break;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 3deb4034c538..309c7712d4cc 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -686,8 +686,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// FIXME: Calling convention!
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default);
- EPI.HasExceptionSpec = false;
- EPI.HasAnyExceptionSpec = false;
+ EPI.ExceptionSpecType = EST_None;
EPI.NumExceptions = 0;
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
@@ -1130,8 +1129,8 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
// If we didn't find a use of this identifier, and if the identifier
// corresponds to a compiler builtin, create the decl object for the builtin
// now, injecting it into translation unit scope, and return it.
- if (AllowBuiltinCreation)
- return LookupBuiltin(*this, R);
+ if (AllowBuiltinCreation && LookupBuiltin(*this, R))
+ return true;
// If we didn't find a use of this identifier, the ExternalSource
// may be able to handle the situation.
@@ -1964,10 +1963,13 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
case Type::Complex:
break;
- // These are ignored by ADL.
+ // If T is an Objective-C object or interface type, or a pointer to an
+ // object or interface type, the associated namespace is the global
+ // namespace.
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
+ Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl());
break;
}
@@ -2203,7 +2205,8 @@ void ADLResult::insert(NamedDecl *New) {
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- ADLResult &Result) {
+ ADLResult &Result,
+ bool StdNamespaceIsAssociated) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
@@ -2211,6 +2214,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
FindAssociatedClassesAndNamespaces(Args, NumArgs,
AssociatedNamespaces,
AssociatedClasses);
+ if (StdNamespaceIsAssociated && StdNamespace)
+ AssociatedNamespaces.insert(getStdNamespace());
QualType T1, T2;
if (Operator) {
@@ -2766,30 +2771,35 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
}
/// LookupOrCreateLabel - Do a name lookup of a label with the specified name.
-/// If isLocalLabel is true, then this is a definition of an __label__ label
-/// name, otherwise it is a normal label definition or use.
+/// If GnuLabelLoc is a valid source location, then this is a definition
+/// of an __label__ label name, otherwise it is a normal label definition
+/// or use.
LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
- bool isLocalLabel) {
+ SourceLocation GnuLabelLoc) {
// Do a lookup to see if we have a label with this name already.
NamedDecl *Res = 0;
-
- // Local label definitions always shadow existing labels.
- if (!isLocalLabel)
- Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration);
-
- // If we found a label, check to see if it is in the same context as us. When
- // in a Block, we don't want to reuse a label in an enclosing function.
+
+ if (GnuLabelLoc.isValid()) {
+ // Local label definitions always shadow existing labels.
+ Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc);
+ Scope *S = CurScope;
+ PushOnScopeChains(Res, S, true);
+ return cast<LabelDecl>(Res);
+ }
+
+ // Not a GNU local label.
+ Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration);
+ // If we found a label, check to see if it is in the same context as us.
+ // When in a Block, we don't want to reuse a label in an enclosing function.
if (Res && Res->getDeclContext() != CurContext)
Res = 0;
-
if (Res == 0) {
// If not forward referenced or defined already, create the backing decl.
Res = LabelDecl::Create(Context, CurContext, Loc, II);
- Scope *S = isLocalLabel ? CurScope : CurScope->getFnParent();
+ Scope *S = CurScope->getFnParent();
assert(S && "Not in a function?");
PushOnScopeChains(Res, S, true);
}
-
return cast<LabelDecl>(Res);
}
@@ -2853,8 +2863,6 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
}
void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) {
- using namespace std;
-
// Use a simple length-based heuristic to determine the minimum possible
// edit distance. If the minimum isn't good enough, bail out early.
unsigned MinED = abs((int)Name.size() - (int)Typo.size());
@@ -2863,7 +2871,8 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) {
// Compute an upper bound on the allowable edit distance, so that the
// edit-distance algorithm can short-circuit.
- unsigned UpperBound = min(unsigned((Typo.size() + 2) / 3), BestEditDistance);
+ unsigned UpperBound =
+ std::min(unsigned((Typo.size() + 2) / 3), BestEditDistance);
// Compute the edit distance between the typo and the name of this
// entity. If this edit distance is not worse than the best edit
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index b086ca751406..6c4469cef9ef 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -45,11 +45,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
!(Attributes & ObjCDeclSpec::DQ_PR_copy)));
TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
- QualType T = TSI->getType();
- if (T->isReferenceType()) {
- Diag(AtLoc, diag::error_reference_property);
- return 0;
- }
+
// Proceed with constructing the ObjCPropertDecls.
ObjCContainerDecl *ClassDecl =
cast<ObjCContainerDecl>(ClassCategory);
@@ -404,12 +400,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (!PropertyIvar)
PropertyIvar = PropertyId;
QualType PropType = Context.getCanonicalType(property->getType());
+ QualType PropertyIvarType = PropType;
+ if (PropType->isReferenceType())
+ PropertyIvarType = cast<ReferenceType>(PropType)->getPointeeType();
// Check that this is a previously declared 'ivar' in 'IDecl' interface
ObjCInterfaceDecl *ClassDeclared;
Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
- Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc,
- PropertyIvar, PropType, /*Dinfo=*/0,
+ Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
+ PropertyLoc, PropertyLoc, PropertyIvar,
+ PropertyIvarType, /*Dinfo=*/0,
ObjCIvarDecl::Private,
(Expr *)0, true);
ClassImpDecl->addDecl(Ivar);
@@ -432,19 +432,19 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
QualType IvarType = Context.getCanonicalType(Ivar->getType());
// Check that type of property and its ivar are type compatible.
- if (PropType != IvarType) {
+ if (PropertyIvarType != IvarType) {
bool compat = false;
- if (isa<ObjCObjectPointerType>(PropType)
+ if (isa<ObjCObjectPointerType>(PropertyIvarType)
&& isa<ObjCObjectPointerType>(IvarType))
compat =
Context.canAssignObjCInterfaces(
- PropType->getAs<ObjCObjectPointerType>(),
+ PropertyIvarType->getAs<ObjCObjectPointerType>(),
IvarType->getAs<ObjCObjectPointerType>());
else {
SourceLocation Loc = PropertyIvarLoc;
if (Loc.isInvalid())
Loc = PropertyLoc;
- compat = (CheckAssignmentConstraints(Loc, PropType, IvarType)
+ compat = (CheckAssignmentConstraints(Loc, PropertyIvarType, IvarType)
== Compatible);
}
if (!compat) {
@@ -459,7 +459,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// FIXME! Rules for properties are somewhat different that those
// for assignments. Use a new routine to consolidate all cases;
// specifically for property redeclarations as well as for ivars.
- QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType();
+ QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType();
if (lhsType != rhsType &&
lhsType->isArithmeticType()) {
@@ -538,7 +538,10 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
- Expr *rhs = new (Context) DeclRefExpr(Param, Param->getType(),
+ QualType T = Param->getType();
+ if (T->isReferenceType())
+ T = T->getAs<ReferenceType>()->getPointeeType();
+ Expr *rhs = new (Context) DeclRefExpr(Param, T,
VK_LValue, SourceLocation());
ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
BO_Assign, lhs, rhs);
@@ -682,7 +685,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
/// ComparePropertiesInBaseAndSuper - This routine compares property
/// declarations in base and its super class, if any, and issues
-/// diagnostics in a variety of inconsistant situations.
+/// diagnostics in a variety of inconsistent situations.
///
void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
@@ -1137,10 +1140,14 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
ObjCPropertyDecl *Property) {
// Should we just clone all attributes over?
- if (DeprecatedAttr *A = Property->getAttr<DeprecatedAttr>())
- PropertyMethod->addAttr(A->clone(S.Context));
- if (UnavailableAttr *A = Property->getAttr<UnavailableAttr>())
- PropertyMethod->addAttr(A->clone(S.Context));
+ for (Decl::attr_iterator A = Property->attr_begin(),
+ AEnd = Property->attr_end();
+ A != AEnd; ++A) {
+ if (isa<DeprecatedAttr>(*A) ||
+ isa<UnavailableAttr>(*A) ||
+ isa<AvailabilityAttr>(*A))
+ PropertyMethod->addAttr((*A)->clone(S.Context));
+ }
}
/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods
@@ -1235,7 +1242,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// Invent the arguments for the setter. We don't bother making a
// nice name for the argument.
- ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, Loc,
+ ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
+ Loc, Loc,
property->getIdentifier(),
property->getType(),
/*TInfo=*/0,
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 8d03285ee443..3f3ed0e1f902 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -36,18 +36,26 @@ using namespace sema;
/// A convenience routine for creating a decayed reference to a
/// function.
-static Expr *
+static ExprResult
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn,
SourceLocation Loc = SourceLocation()) {
- Expr *E = new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc);
- S.DefaultFunctionArrayConversion(E);
- return E;
+ ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc));
+ E = S.DefaultFunctionArrayConversion(E.take());
+ if (E.isInvalid())
+ return ExprError();
+ return move(E);
}
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle);
+
+static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
+ QualType &ToType,
+ bool InOverloadResolution,
+ StandardConversionSequence &SCS,
+ bool CStyle);
static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
@@ -128,7 +136,9 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
- ICR_Complex_Real_Conversion
+ ICR_Complex_Real_Conversion,
+ ICR_Conversion,
+ ICR_Conversion
};
return Rank[(int)Kind];
}
@@ -157,7 +167,9 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Derived-to-base conversion",
"Vector conversion",
"Vector splat",
- "Complex-real conversion"
+ "Complex-real conversion",
+ "Block Pointer conversion",
+ "Transparent Union Conversion"
};
return Name[Kind];
}
@@ -228,7 +240,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
if (First == ICK_Array_To_Pointer)
FromType = Context.getArrayDecayedType(FromType);
- if (Second == ICK_Pointer_Conversion && FromType->isPointerType())
+ if (Second == ICK_Pointer_Conversion && FromType->isAnyPointerType())
if (const PointerType* ToPtrType = ToType->getAs<PointerType>())
return ToPtrType->getPointeeType()->isVoidType();
@@ -876,20 +888,19 @@ bool Sema::TryImplicitConversion(InitializationSequence &Sequence,
}
/// PerformImplicitConversion - Perform an implicit conversion of the
-/// expression From to the type ToType. Returns true if there was an
-/// error, false otherwise. The expression From is replaced with the
+/// expression From to the type ToType. Returns the
/// converted expression. Flavor is the kind of conversion we're
/// performing, used in the error message. If @p AllowExplicit,
/// explicit user-defined conversions are permitted.
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ExprResult
+Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit) {
ImplicitConversionSequence ICS;
return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS);
}
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ExprResult
+Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
ImplicitConversionSequence& ICS) {
ICS = clang::TryImplicitConversion(*this, From, ToType,
@@ -1048,27 +1059,33 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// otherwise, only a boolean conversion is standard
if (!ToType->isBooleanType())
return false;
-
- }
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
- if (!Method->isStatic()) {
- const Type *ClassType
- = S.Context.getTypeDeclType(Method->getParent()).getTypePtr();
- FromType = S.Context.getMemberPointerType(FromType, ClassType);
- }
}
- // If the "from" expression takes the address of the overloaded
- // function, update the type of the resulting expression accordingly.
- if (FromType->getAs<FunctionType>())
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens()))
- if (UnOp->getOpcode() == UO_AddrOf)
- FromType = S.Context.getPointerType(FromType);
+ // Check if the "from" expression is taking the address of an overloaded
+ // function and recompute the FromType accordingly. Take advantage of the
+ // fact that non-static member functions *must* have such an address-of
+ // expression.
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn);
+ if (Method && !Method->isStatic()) {
+ assert(isa<UnaryOperator>(From->IgnoreParens()) &&
+ "Non-unary operator on non-static member address");
+ assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode()
+ == UO_AddrOf &&
+ "Non-address-of operator on non-static member address");
+ const Type *ClassType
+ = S.Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FromType = S.Context.getMemberPointerType(FromType, ClassType);
+ } else if (isa<UnaryOperator>(From->IgnoreParens())) {
+ assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode() ==
+ UO_AddrOf &&
+ "Non-address-of operator for overloaded function expression");
+ FromType = S.Context.getPointerType(FromType);
+ }
// Check that we've computed the proper type after overload resolution.
- assert(S.Context.hasSameType(FromType,
- S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
+ assert(S.Context.hasSameType(
+ FromType,
+ S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
} else {
return false;
}
@@ -1188,6 +1205,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Pointer conversions (C++ 4.10).
SCS.Second = ICK_Pointer_Conversion;
SCS.IncompatibleObjC = IncompatibleObjC;
+ FromType = FromType.getUnqualifiedType();
} else if (S.IsMemberPointerConversion(From, FromType, ToType,
InOverloadResolution, FromType)) {
// Pointer to member conversions (4.11).
@@ -1203,6 +1221,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
} else if (IsNoReturnConversion(S.Context, FromType, ToType, FromType)) {
// Treat a conversion that strips "noreturn" as an identity conversion.
SCS.Second = ICK_NoReturn_Adjustment;
+ } else if (IsTransparentUnionStandardConversion(S, From, ToType,
+ InOverloadResolution,
+ SCS, CStyle)) {
+ SCS.Second = ICK_TransparentUnionConversion;
+ FromType = ToType;
} else {
// No second conversion required.
SCS.Second = ICK_Identity;
@@ -1244,6 +1267,30 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
return true;
}
+
+static bool
+IsTransparentUnionStandardConversion(Sema &S, Expr* From,
+ QualType &ToType,
+ bool InOverloadResolution,
+ StandardConversionSequence &SCS,
+ bool CStyle) {
+
+ const RecordType *UT = ToType->getAsUnionType();
+ if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ return false;
+ // The field to initialize within the transparent union.
+ RecordDecl *UD = UT->getDecl();
+ // It's compatible if the expression matches any of the fields.
+ for (RecordDecl::field_iterator it = UD->field_begin(),
+ itend = UD->field_end();
+ it != itend; ++it) {
+ if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, CStyle)) {
+ ToType = it->getType();
+ return true;
+ }
+ }
+ return false;
+}
/// IsIntegralPromotion - Determines whether the conversion from the
/// expression From (whose potentially-adjusted type is FromType) to
@@ -1615,8 +1662,30 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
return true;
}
+ if (FromPointeeType->isVectorType() && ToPointeeType->isVectorType() &&
+ Context.areCompatibleVectorTypes(FromPointeeType, ToPointeeType)) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
return false;
}
+
+/// \brief Adopt the given qualifiers for the given type.
+static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){
+ Qualifiers TQs = T.getQualifiers();
+
+ // Check whether qualifiers already match.
+ if (TQs == Qs)
+ return T;
+
+ if (Qs.compatiblyIncludes(TQs))
+ return Context.getQualifiedType(T, Qs);
+
+ return Context.getQualifiedType(T.getUnqualifiedType(), Qs);
+}
/// isObjCPointerConversion - Determines whether this is an
/// Objective-C pointer conversion. Subroutine of IsPointerConversion,
@@ -1627,6 +1696,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
if (!getLangOptions().ObjC1)
return false;
+ // The set of qualifiers on the type we're converting from.
+ Qualifiers FromQualifiers = FromType.getQualifiers();
+
// First, we handle all conversions on ObjC object pointer types.
const ObjCObjectPointerType* ToObjCPtr =
ToType->getAs<ObjCObjectPointerType>();
@@ -1640,10 +1712,11 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
FromObjCPtr->getPointeeType()))
return false;
+ // Check for compatible
// Objective C++: We're able to convert between "id" or "Class" and a
// pointer to any interface (in both directions).
if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) {
- ConvertedType = ToType;
+ ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
return true;
}
// Conversions with Objective-C's id<...>.
@@ -1651,7 +1724,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ToObjCPtr->isObjCQualifiedIdType()) &&
Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType,
/*compare=*/false)) {
- ConvertedType = ToType;
+ ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
return true;
}
// Objective C++: We're able to convert from a pointer to an
@@ -1666,6 +1739,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
ToObjCPtr->getPointeeType(),
ToType, Context);
+ ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
@@ -1677,6 +1751,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
ToObjCPtr->getPointeeType(),
ToType, Context);
+ ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
}
@@ -1689,7 +1764,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// Objective C++: We're able to convert from a pointer to any object
// to a block pointer type.
if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) {
- ConvertedType = ToType;
+ ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
return true;
}
ToPointeeType = ToBlockPtr->getPointeeType();
@@ -1698,7 +1773,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) {
// Objective C++: We're able to convert from a block pointer type to a
// pointer to any object.
- ConvertedType = ToType;
+ ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
return true;
}
else
@@ -1721,6 +1796,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// We always complain about this conversion.
IncompatibleObjC = true;
ConvertedType = Context.getPointerType(ConvertedType);
+ ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
// Allow conversion of pointee being objective-c pointer to another one;
@@ -1730,6 +1806,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
IncompatibleObjC)) {
ConvertedType = Context.getPointerType(ConvertedType);
+ ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
}
@@ -1790,7 +1867,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
if (HasObjCConversion) {
// We had an Objective-C conversion. Allow this pointer
// conversion, but complain about it.
- ConvertedType = ToType;
+ ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers);
IncompatibleObjC = true;
return true;
}
@@ -1936,11 +2013,12 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
Kind = CK_BitCast;
- if (CXXBoolLiteralExpr* LitBool
- = dyn_cast<CXXBoolLiteralExpr>(From->IgnoreParens()))
- if (!IsCStyleOrFunctionalCast && LitBool->getValue() == false)
- Diag(LitBool->getExprLoc(), diag::warn_init_pointer_from_false)
- << ToType;
+ if (!IsCStyleOrFunctionalCast &&
+ Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy) &&
+ From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(From->getExprLoc(), From,
+ PDiag(diag::warn_impcast_bool_to_null_pointer)
+ << ToType << From->getSourceRange());
if (const PointerType *FromPtrType = FromType->getAs<PointerType>())
if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) {
@@ -2116,21 +2194,24 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
// unwrap.
UnwrappedAnyPointer = true;
+ Qualifiers FromQuals = FromType.getQualifiers();
+ Qualifiers ToQuals = ToType.getQualifiers();
+
// -- for every j > 0, if const is in cv 1,j then const is in cv
// 2,j, and similarly for volatile.
- if (!CStyle && !ToType.isAtLeastAsQualifiedAs(FromType))
+ if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
return false;
// -- if the cv 1,j and cv 2,j are different, then const is in
// every cv for 0 < k < j.
- if (!CStyle && FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
+ if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers()
&& !PreviousToQualsIncludeConst)
return false;
// Keep track of whether all prior cv-qualifiers in the "to" type
// include const.
PreviousToQualsIncludeConst
- = PreviousToQualsIncludeConst && ToType.isConstQualified();
+ = PreviousToQualsIncludeConst && ToQuals.hasConst();
}
// We are left with FromType and ToType being the pointee types
@@ -2175,7 +2256,11 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
S.IsDerivedFrom(From->getType(), ToType)))
ConstructorsOnly = true;
- if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag())) {
+ S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag());
+ // RequireCompleteType may have returned true due to some invalid decl
+ // during template instantiation, but ToType may be complete enough now
+ // to try to recover.
+ if (ToType->isIncompleteType()) {
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
@@ -2546,7 +2631,8 @@ CompareStandardConversionSequences(Sema &S,
if (ImplicitConversionSequence::CompareKind DerivedCK
= CompareDerivedToBaseConversions(S, SCS1, SCS2))
return DerivedCK;
- } else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid) {
+ } else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid &&
+ !S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType())) {
// Both conversion sequences are conversions to void
// pointers. Compare the source types to determine if there's an
// inheritance relationship in their sources.
@@ -2560,10 +2646,8 @@ CompareStandardConversionSequences(Sema &S,
if (SCS2.First == ICK_Array_To_Pointer)
FromType2 = S.Context.getArrayDecayedType(FromType2);
- QualType FromPointee1
- = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- QualType FromPointee2
- = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee1 = FromType1->getPointeeType().getUnqualifiedType();
+ QualType FromPointee2 = FromType2->getPointeeType().getUnqualifiedType();
if (S.IsDerivedFrom(FromPointee2, FromPointee1))
return ImplicitConversionSequence::Better;
@@ -2572,13 +2656,19 @@ CompareStandardConversionSequences(Sema &S,
// Objective-C++: If one interface is more specific than the
// other, it is the better one.
- const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>();
- const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>();
- if (FromIface1 && FromIface1) {
- if (S.Context.canAssignObjCInterfaces(FromIface2, FromIface1))
- return ImplicitConversionSequence::Better;
- else if (S.Context.canAssignObjCInterfaces(FromIface1, FromIface2))
- return ImplicitConversionSequence::Worse;
+ const ObjCObjectPointerType* FromObjCPtr1
+ = FromType1->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType* FromObjCPtr2
+ = FromType2->getAs<ObjCObjectPointerType>();
+ if (FromObjCPtr1 && FromObjCPtr2) {
+ bool AssignLeft = S.Context.canAssignObjCInterfaces(FromObjCPtr1,
+ FromObjCPtr2);
+ bool AssignRight = S.Context.canAssignObjCInterfaces(FromObjCPtr2,
+ FromObjCPtr1);
+ if (AssignLeft != AssignRight) {
+ return AssignLeft? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+ }
}
}
@@ -2981,7 +3071,12 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// overload resolution, cases for which cv1 is greater
// cv-qualification than cv2 are identified as
// reference-compatible with added qualification (see 13.3.3.2).
- if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
+ //
+ // Note that we also require equivalence of Objective-C GC and address-space
+ // qualifiers when performing these computations, so that e.g., an int in
+ // address space 1 is not reference-compatible with an int in address
+ // space 2.
+ if (T1Quals == T2Quals)
return Ref_Compatible;
else if (T1.isMoreQualifiedThan(T2))
return Ref_Compatible_With_Added_Qualification;
@@ -3480,8 +3575,8 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
/// PerformObjectArgumentInitialization - Perform initialization of
/// the implicit object parameter for the given Method with the given
/// expression.
-bool
-Sema::PerformObjectArgumentInitialization(Expr *&From,
+ExprResult
+Sema::PerformObjectArgumentInitialization(Expr *From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
CXXMethodDecl *Method) {
@@ -3517,7 +3612,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
<< From->getSourceRange();
Diag(Method->getLocation(), diag::note_previous_decl)
<< Method->getDeclName();
- return true;
+ return ExprError();
}
}
@@ -3526,13 +3621,18 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
<< ImplicitParamRecordType << FromRecordType << From->getSourceRange();
}
- if (ICS.Standard.Second == ICK_Derived_To_Base)
- return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method);
+ if (ICS.Standard.Second == ICK_Derived_To_Base) {
+ ExprResult FromRes =
+ PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method);
+ if (FromRes.isInvalid())
+ return ExprError();
+ From = FromRes.take();
+ }
if (!Context.hasSameType(From->getType(), DestType))
- ImpCastExprToType(From, DestType, CK_NoOp,
- From->getType()->isPointerType() ? VK_RValue : VK_LValue);
- return false;
+ From = ImpCastExprToType(From, DestType, CK_NoOp,
+ From->getType()->isPointerType() ? VK_RValue : VK_LValue).take();
+ return Owned(From);
}
/// TryContextuallyConvertToBool - Attempt to contextually convert the
@@ -3550,16 +3650,16 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) {
/// PerformContextuallyConvertToBool - Perform a contextual conversion
/// of the expression From to bool (C++0x [conv]p3).
-bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
+ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From);
if (!ICS.isBad())
return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
- return Diag(From->getSourceRange().getBegin(),
- diag::err_typecheck_bool_condition)
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_bool_condition)
<< From->getType() << From->getSourceRange();
- return true;
+ return ExprError();
}
/// TryContextuallyConvertToObjCId - Attempt to contextually convert the
@@ -3577,12 +3677,12 @@ TryContextuallyConvertToObjCId(Sema &S, Expr *From) {
/// PerformContextuallyConvertToObjCId - Perform a contextual conversion
/// of the expression From to 'id'.
-bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) {
+ExprResult Sema::PerformContextuallyConvertToObjCId(Expr *From) {
QualType Ty = Context.getObjCIdType();
ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(*this, From);
if (!ICS.isBad())
return PerformImplicitConversion(From, Ty, ICS, AA_Converting);
- return true;
+ return ExprError();
}
/// \brief Attempt to convert the given expression to an integral or
@@ -4061,7 +4161,7 @@ void
Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
Expr **Args, unsigned NumArgs,
@@ -4114,7 +4214,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
@@ -6090,9 +6190,10 @@ void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
bool Operator,
Expr **Args, unsigned NumArgs,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ bool StdNamespaceIsAssociated) {
ADLResult Fns;
// FIXME: This approach for uniquing ADL results (and removing
@@ -6103,7 +6204,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns);
+ ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns,
+ StdNamespaceIsAssociated);
// Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -6282,8 +6384,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Best is the best viable function.
if (Best->Function &&
- (Best->Function->isDeleted() ||
- Best->Function->getAttr<UnavailableAttr>()))
+ (Best->Function->isDeleted() || Best->Function->isUnavailable()))
return OR_Deleted;
return OR_Success;
@@ -6473,6 +6574,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
+ if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy
+ << FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr()
+ << (unsigned) isObjectArgument << I+1;
+ MaybeEmitInheritedConstructorNote(S, Fn);
+ return;
+ }
+
unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
assert(CVR && "unexpected qualifiers mismatch");
@@ -6735,7 +6847,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
- if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr<UnavailableAttr>())) {
+ if (Cand->Viable && (Fn->isDeleted() || Fn->isUnavailable())) {
std::string FnDesc;
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
@@ -7134,8 +7246,23 @@ public:
if (!TargetFunctionType->isFunctionType()) {
if (OvlExpr->hasExplicitTemplateArgs()) {
DeclAccessPair dap;
- if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
+ if (FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
OvlExpr, false, &dap) ) {
+
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
+ if (!Method->isStatic()) {
+ // If the target type is a non-function type and the function
+ // found is a non-static member function, pretend as if that was
+ // the target, it's the only possible type to end up with.
+ TargetTypeIsNonStaticMemberFunction = true;
+
+ // And skip adding the function if its not in the proper form.
+ // We'll diagnose this due to an empty set of functions.
+ if (!OvlExprInfo.HasFormOfMemberPointer)
+ return;
+ }
+ }
+
Matches.push_back(std::make_pair(dap,Fn));
}
}
@@ -7419,32 +7546,29 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetTyp
/// template, where that template-id refers to a single template whose template
/// arguments are either provided by the template-id or have defaults,
/// as described in C++0x [temp.arg.explicit]p3.
-FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From,
- bool Complain,
- DeclAccessPair* FoundResult) {
+FunctionDecl *
+Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
+ bool Complain,
+ DeclAccessPair *FoundResult) {
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
- if (From->getType() != Context.OverloadTy)
- return 0;
-
- OverloadExpr *OvlExpr = OverloadExpr::find(From).Expression;
// If we didn't actually find any template-ids, we're done.
- if (!OvlExpr->hasExplicitTemplateArgs())
+ if (!ovl->hasExplicitTemplateArgs())
return 0;
TemplateArgumentListInfo ExplicitTemplateArgs;
- OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
+ ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
FunctionDecl *Matched = 0;
- for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
- E = OvlExpr->decls_end(); I != E; ++I) {
+ for (UnresolvedSetIterator I = ovl->decls_begin(),
+ E = ovl->decls_end(); I != E; ++I) {
// C++0x [temp.arg.explicit]p3:
// [...] In contexts where deduction is done and fails, or in contexts
// where deduction is not done, if a template argument list is
@@ -7461,7 +7585,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From,
// function template specialization, which is added to the set of
// overloaded functions considered.
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
+ TemplateDeductionInfo Info(Context, ovl->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info)) {
@@ -7470,30 +7594,98 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From,
continue;
}
+ assert(Specialization && "no specialization and no error?");
+
// Multiple matches; we can't resolve to a single declaration.
if (Matched) {
- if (FoundResult)
- *FoundResult = DeclAccessPair();
-
if (Complain) {
- Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
- << OvlExpr->getName();
- NoteAllOverloadCandidates(OvlExpr);
+ Diag(ovl->getExprLoc(), diag::err_addr_ovl_ambiguous)
+ << ovl->getName();
+ NoteAllOverloadCandidates(ovl);
}
return 0;
- }
+ }
- if ((Matched = Specialization) && FoundResult)
- *FoundResult = I.getPair();
+ Matched = Specialization;
+ if (FoundResult) *FoundResult = I.getPair();
}
return Matched;
}
+
+
+
+// Resolve and fix an overloaded expression that
+// can be resolved because it identifies a single function
+// template specialization
+// Last three arguments should only be supplied if Complain = true
+ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
+ Expr *SrcExpr, bool doFunctionPointerConverion, bool complain,
+ const SourceRange& OpRangeForComplaining,
+ QualType DestTypeForComplaining,
+ unsigned DiagIDForComplaining) {
+ assert(SrcExpr->getType() == Context.OverloadTy);
+
+ OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr);
+
+ DeclAccessPair found;
+ ExprResult SingleFunctionExpression;
+ if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization(
+ ovl.Expression, /*complain*/ false, &found)) {
+ if (DiagnoseUseOfDecl(fn, SrcExpr->getSourceRange().getBegin()))
+ return ExprError();
+
+ // It is only correct to resolve to an instance method if we're
+ // resolving a form that's permitted to be a pointer to member.
+ // Otherwise we'll end up making a bound member expression, which
+ // is illegal in all the contexts we resolve like this.
+ if (!ovl.HasFormOfMemberPointer &&
+ isa<CXXMethodDecl>(fn) &&
+ cast<CXXMethodDecl>(fn)->isInstance()) {
+ if (complain) {
+ Diag(ovl.Expression->getExprLoc(),
+ diag::err_invalid_use_of_bound_member_func)
+ << ovl.Expression->getSourceRange();
+ // TODO: I believe we only end up here if there's a mix of
+ // static and non-static candidates (otherwise the expression
+ // would have 'bound member' type, not 'overload' type).
+ // Ideally we would note which candidate was chosen and why
+ // the static candidates were rejected.
+ }
+
+ return ExprError();
+ }
+
+ // Fix the expresion to refer to 'fn'.
+ SingleFunctionExpression =
+ Owned(FixOverloadedFunctionReference(SrcExpr, found, fn));
+
+ // If desired, do function-to-pointer decay.
+ if (doFunctionPointerConverion)
+ SingleFunctionExpression =
+ DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take());
+ }
+
+ if (!SingleFunctionExpression.isUsable()) {
+ if (complain) {
+ Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
+ << ovl.Expression->getName()
+ << DestTypeForComplaining
+ << OpRangeForComplaining
+ << ovl.Expression->getQualifierLoc().getSourceRange();
+ NoteAllOverloadCandidates(SrcExpr);
+ }
+ return ExprError();
+ }
+
+ return SingleFunctionExpression;
+}
+
/// \brief Add a single candidate to the overload set.
static void AddOverloadedCallCandidate(Sema &S,
DeclAccessPair FoundDecl,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
@@ -7559,7 +7751,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
// It would be nice to avoid this copy.
TemplateArgumentListInfo TABuffer;
- const TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
+ TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TABuffer);
ExplicitTemplateArgs = &TABuffer;
@@ -7576,7 +7768,8 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
Args, NumArgs,
ExplicitTemplateArgs,
CandidateSet,
- PartialOverloading);
+ PartialOverloading,
+ ULE->isStdAssociatedNamespace());
}
/// Attempts to recover from a call where no functions were found.
@@ -7590,9 +7783,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
SourceLocation RParenLoc) {
CXXScopeSpec SS;
- if (ULE->getQualifier())
- SS.MakeTrivial(SemaRef.Context,
- ULE->getQualifier(), ULE->getQualifierRange());
+ SS.Adopt(ULE->getQualifierLoc());
TemplateArgumentListInfo TABuffer;
const TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
@@ -7657,7 +7848,9 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
// We don't perform ADL in C.
assert(getLangOptions().CPlusPlus && "ADL enabled in C");
- }
+ } else
+ assert(!ULE->isStdAssociatedNamespace() &&
+ "std is associated namespace but not doing ADL");
#endif
OverloadCandidateSet CandidateSet(Fn->getExprLoc());
@@ -7704,8 +7897,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call)
<< Best->Function->isDeleted()
<< ULE->getName()
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
+ << getDeletedOrUnavailableSuffix(Best->Function)
<< Fn->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
}
@@ -7749,8 +7941,12 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// TODO: provide better source location info.
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
- if (Input->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForRValue(Input);
+ if (Input->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(Input);
+ if (Result.isInvalid())
+ return ExprError();
+ Input = Result.take();
+ }
Expr *Args[2] = { Input, 0 };
unsigned NumArgs = 1;
@@ -7776,11 +7972,11 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, NamingClass,
- 0, SourceRange(), OpNameInfo,
+ NestedNameSpecifierLoc(), OpNameInfo,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
- &Args[0], NumArgs,
+ &Args[0], NumArgs,
Context.DependentTy,
VK_RValue,
OpLoc));
@@ -7821,9 +8017,12 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
- if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0,
- Best->FoundDecl, Method))
+ ExprResult InputRes =
+ PerformObjectArgumentInitialization(Input, /*Qualifier=*/0,
+ Best->FoundDecl, Method);
+ if (InputRes.isInvalid())
return ExprError();
+ Input = InputRes.take();
} else {
// Convert the arguments.
ExprResult InputInit
@@ -7845,11 +8044,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl);
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl);
+ if (FnExpr.isInvalid())
+ return ExprError();
Args[0] = Input;
CallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
Args, NumArgs, ResultTy, VK, OpLoc);
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
@@ -7861,39 +8062,40 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing))
- return ExprError();
-
- break;
- }
- }
-
- case OR_No_Viable_Function:
- // No viable function; fall through to handling this as a
- // built-in operator, which will produce an error message for us.
+ ExprResult InputRes =
+ PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], AA_Passing);
+ if (InputRes.isInvalid())
+ return ExprError();
+ Input = InputRes.take();
break;
+ }
+ }
- case OR_Ambiguous:
- Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary)
- << UnaryOperator::getOpcodeStr(Opc)
- << Input->getType()
- << Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
- Args, NumArgs,
- UnaryOperator::getOpcodeStr(Opc), OpLoc);
- return ExprError();
+ case OR_No_Viable_Function:
+ // No viable function; fall through to handling this as a
+ // built-in operator, which will produce an error message for us.
+ break;
- case OR_Deleted:
- Diag(OpLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted()
+ case OR_Ambiguous:
+ Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary)
<< UnaryOperator::getOpcodeStr(Opc)
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
+ << Input->getType()
<< Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
- return ExprError();
- }
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
+ Args, NumArgs,
+ UnaryOperator::getOpcodeStr(Opc), OpLoc);
+ return ExprError();
+
+ case OR_Deleted:
+ Diag(OpLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << UnaryOperator::getOpcodeStr(Opc)
+ << getDeletedOrUnavailableSuffix(Best->Function)
+ << Input->getSourceRange();
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ return ExprError();
+ }
// Either we found no viable overloaded operator or we matched a
// built-in operator. In either case, fall through to trying to
@@ -7956,8 +8158,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// TODO: provide better source location info in DNLoc component.
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, NamingClass, 0, SourceRange(),
- OpNameInfo, /*ADL*/ true, IsOverloaded(Fns),
+ = UnresolvedLookupExpr::Create(Context, NamingClass,
+ NestedNameSpecifierLoc(), OpNameInfo,
+ /*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
Args, 2,
@@ -7967,8 +8170,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
}
// Always do property rvalue conversions on the RHS.
- if (Args[1]->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForRValue(Args[1]);
+ if (Args[1]->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(Args[1]);
+ if (Result.isInvalid())
+ return ExprError();
+ Args[1] = Result.take();
+ }
// The LHS is more complicated.
if (Args[0]->getObjectKind() == OK_ObjCProperty) {
@@ -7996,7 +8203,10 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
- ConvertPropertyForRValue(Args[0]);
+ ExprResult Result = ConvertPropertyForRValue(Args[0]);
+ if (Result.isInvalid())
+ return ExprError();
+ Args[0] = Result.take();
}
// If this is the assignment operator, we only perform overload resolution
@@ -8057,10 +8267,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Arg1.isInvalid())
return ExprError();
- if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
- Best->FoundDecl, Method))
+ ExprResult Arg0 =
+ PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
+ Best->FoundDecl, Method);
+ if (Arg0.isInvalid())
return ExprError();
-
+ Args[0] = Arg0.takeAs<Expr>();
Args[1] = RHS = Arg1.takeAs<Expr>();
} else {
// Convert the arguments.
@@ -8090,10 +8302,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc);
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc);
+ if (FnExpr.isInvalid())
+ return ExprError();
CXXOperatorCallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
Args, 2, ResultTy, VK, OpLoc);
if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
@@ -8105,12 +8319,19 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing) ||
- PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], AA_Passing))
+ ExprResult ArgsRes0 =
+ PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], AA_Passing);
+ if (ArgsRes0.isInvalid())
return ExprError();
+ Args[0] = ArgsRes0.take();
+ ExprResult ArgsRes1 =
+ PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
+ Best->Conversions[1], AA_Passing);
+ if (ArgsRes1.isInvalid())
+ return ExprError();
+ Args[1] = ArgsRes1.take();
break;
}
}
@@ -8158,8 +8379,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
+ << getDeletedOrUnavailableSuffix(Best->Function)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2);
return ExprError();
@@ -8187,7 +8407,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
OpNameInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, NamingClass,
- 0, SourceRange(), OpNameInfo,
+ NestedNameSpecifierLoc(), OpNameInfo,
/*ADL*/ true, /*Overloaded*/ false,
UnresolvedSetIterator(),
UnresolvedSetIterator());
@@ -8200,10 +8420,18 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
RLoc));
}
- if (Args[0]->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForRValue(Args[0]);
- if (Args[1]->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForRValue(Args[1]);
+ if (Args[0]->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(Args[0]);
+ if (Result.isInvalid())
+ return ExprError();
+ Args[0] = Result.take();
+ }
+ if (Args[1]->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(Args[1]);
+ if (Result.isInvalid())
+ return ExprError();
+ Args[1] = Result.take();
+ }
// Build an empty overload set.
OverloadCandidateSet CandidateSet(LLoc);
@@ -8234,9 +8462,12 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
- if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
- Best->FoundDecl, Method))
+ ExprResult Arg0 =
+ PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
+ Best->FoundDecl, Method);
+ if (Arg0.isInvalid())
return ExprError();
+ Args[0] = Arg0.take();
// Convert the arguments.
ExprResult InputInit
@@ -8256,11 +8487,13 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc);
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc);
+ if (FnExpr.isInvalid())
+ return ExprError();
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
- FnExpr, Args, 2,
+ FnExpr.take(), Args, 2,
ResultTy, VK, RLoc);
if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall,
@@ -8272,11 +8505,19 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing) ||
- PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], AA_Passing))
+ ExprResult ArgsRes0 =
+ PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], AA_Passing);
+ if (ArgsRes0.isInvalid())
return ExprError();
+ Args[0] = ArgsRes0.take();
+
+ ExprResult ArgsRes1 =
+ PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
+ Best->Conversions[1], AA_Passing);
+ if (ArgsRes1.isInvalid())
+ return ExprError();
+ Args[1] = ArgsRes1.take();
break;
}
@@ -8308,8 +8549,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
case OR_Deleted:
Diag(LLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted() << "[]"
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
+ << getDeletedOrUnavailableSuffix(Best->Function)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2,
"[]", LLoc);
@@ -8325,16 +8565,66 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
/// function (and includes the object parameter), Args/NumArgs are the
/// arguments to the function call (not including the object
/// parameter). The caller needs to validate that the member
-/// expression refers to a member function or an overloaded member
-/// function.
+/// expression refers to a non-static member function or an overloaded
+/// member function.
ExprResult
Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation RParenLoc) {
+ assert(MemExprE->getType() == Context.BoundMemberTy ||
+ MemExprE->getType() == Context.OverloadTy);
+
// Dig out the member expression. This holds both the object
// argument and the member function we're referring to.
Expr *NakedMemExpr = MemExprE->IgnoreParens();
+ // Determine whether this is a call to a pointer-to-member function.
+ if (BinaryOperator *op = dyn_cast<BinaryOperator>(NakedMemExpr)) {
+ assert(op->getType() == Context.BoundMemberTy);
+ assert(op->getOpcode() == BO_PtrMemD || op->getOpcode() == BO_PtrMemI);
+
+ QualType fnType =
+ op->getRHS()->getType()->castAs<MemberPointerType>()->getPointeeType();
+
+ const FunctionProtoType *proto = fnType->castAs<FunctionProtoType>();
+ QualType resultType = proto->getCallResultType(Context);
+ ExprValueKind valueKind = Expr::getValueKindForType(proto->getResultType());
+
+ // Check that the object type isn't more qualified than the
+ // member function we're calling.
+ Qualifiers funcQuals = Qualifiers::fromCVRMask(proto->getTypeQuals());
+
+ QualType objectType = op->getLHS()->getType();
+ if (op->getOpcode() == BO_PtrMemI)
+ objectType = objectType->castAs<PointerType>()->getPointeeType();
+ Qualifiers objectQuals = objectType.getQualifiers();
+
+ Qualifiers difference = objectQuals - funcQuals;
+ difference.removeObjCGCAttr();
+ difference.removeAddressSpace();
+ if (difference) {
+ std::string qualsString = difference.getAsString();
+ Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals)
+ << fnType.getUnqualifiedType()
+ << qualsString
+ << (qualsString.find(' ') == std::string::npos ? 1 : 2);
+ }
+
+ CXXMemberCallExpr *call
+ = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs,
+ resultType, valueKind, RParenLoc);
+
+ if (CheckCallReturnType(proto->getResultType(),
+ op->getRHS()->getSourceRange().getBegin(),
+ call, 0))
+ return ExprError();
+
+ if (ConvertArgumentsForCall(call, op, 0, proto, Args, NumArgs, RParenLoc))
+ return ExprError();
+
+ return MaybeBindToTemporary(call);
+ }
+
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public);
@@ -8427,8 +8717,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
<< DeclName
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
+ << getDeletedOrUnavailableSuffix(Best->Function)
<< MemExprE->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
@@ -8464,12 +8753,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Convert the object argument (for a non-static member function call).
// We only need to do this if there was actually an overload; otherwise
// it was done at lookup.
- Expr *ObjectArg = MemExpr->getBase();
- if (!Method->isStatic() &&
- PerformObjectArgumentInitialization(ObjectArg, Qualifier,
- FoundDecl, Method))
- return ExprError();
- MemExpr->setBase(ObjectArg);
+ if (!Method->isStatic()) {
+ ExprResult ObjectArg =
+ PerformObjectArgumentInitialization(MemExpr->getBase(), Qualifier,
+ FoundDecl, Method);
+ if (ObjectArg.isInvalid())
+ return ExprError();
+ MemExpr->setBase(ObjectArg.take());
+ }
// Convert the rest of the arguments
const FunctionProtoType *Proto =
@@ -8489,15 +8780,19 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
/// overloaded function call operator (@c operator()) or performing a
/// user-defined conversion on the object argument.
ExprResult
-Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
+Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc) {
- if (Object->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForRValue(Object);
+ ExprResult Object = Owned(Obj);
+ if (Object.get()->getObjectKind() == OK_ObjCProperty) {
+ Object = ConvertPropertyForRValue(Object.take());
+ if (Object.isInvalid())
+ return ExprError();
+ }
- assert(Object->getType()->isRecordType() && "Requires object type argument");
- const RecordType *Record = Object->getType()->getAs<RecordType>();
+ assert(Object.get()->getType()->isRecordType() && "Requires object type argument");
+ const RecordType *Record = Object.get()->getType()->getAs<RecordType>();
// C++ [over.call.object]p1:
// If the primary-expression E in the function call syntax
@@ -8509,9 +8804,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
OverloadCandidateSet CandidateSet(LParenLoc);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
- if (RequireCompleteType(LParenLoc, Object->getType(),
+ if (RequireCompleteType(LParenLoc, Object.get()->getType(),
PDiag(diag::err_incomplete_object_call)
- << Object->getSourceRange()))
+ << Object.get()->getSourceRange()))
return true;
LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
@@ -8520,8 +8815,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
- AddMethodCandidate(Oper.getPair(), Object->getType(),
- Object->Classify(Context), Args, NumArgs, CandidateSet,
+ AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
+ Object.get()->Classify(Context), Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/ false);
}
@@ -8566,12 +8861,12 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
- Object, Args, NumArgs, CandidateSet);
+ Object.get(), Args, NumArgs, CandidateSet);
}
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
- switch (CandidateSet.BestViableFunction(*this, Object->getLocStart(),
+ switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(),
Best)) {
case OR_Success:
// Overload resolution succeeded; we'll build the appropriate call
@@ -8580,31 +8875,30 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
case OR_No_Viable_Function:
if (CandidateSet.empty())
- Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_oper)
- << Object->getType() << /*call*/ 1
- << Object->getSourceRange();
+ Diag(Object.get()->getSourceRange().getBegin(), diag::err_ovl_no_oper)
+ << Object.get()->getType() << /*call*/ 1
+ << Object.get()->getSourceRange();
else
- Diag(Object->getSourceRange().getBegin(),
+ Diag(Object.get()->getSourceRange().getBegin(),
diag::err_ovl_no_viable_object_call)
- << Object->getType() << Object->getSourceRange();
+ << Object.get()->getType() << Object.get()->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
break;
case OR_Ambiguous:
- Diag(Object->getSourceRange().getBegin(),
+ Diag(Object.get()->getSourceRange().getBegin(),
diag::err_ovl_ambiguous_object_call)
- << Object->getType() << Object->getSourceRange();
+ << Object.get()->getType() << Object.get()->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
break;
case OR_Deleted:
- Diag(Object->getSourceRange().getBegin(),
+ Diag(Object.get()->getSourceRange().getBegin(),
diag::err_ovl_deleted_object_call)
<< Best->Function->isDeleted()
- << Object->getType()
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
- << Object->getSourceRange();
+ << Object.get()->getType()
+ << getDeletedOrUnavailableSuffix(Best->Function)
+ << Object.get()->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
break;
}
@@ -8619,7 +8913,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
- CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
+ CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We selected one of the surrogate functions that converts the
@@ -8628,7 +8922,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Create an implicit member expr to refer to the conversion operator.
// and then call it.
- ExprResult Call = BuildCXXMemberCallExpr(Object, Best->FoundDecl, Conv);
+ ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl, Conv);
if (Call.isInvalid())
return ExprError();
@@ -8637,7 +8931,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
}
MarkDeclarationReferenced(LParenLoc, Best->Function);
- CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
+ CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We found an overloaded operator(). Build a CXXOperatorCallExpr
@@ -8660,11 +8954,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
} else {
MethodArgs = new Expr*[NumArgs + 1];
}
- MethodArgs[0] = Object;
+ MethodArgs[0] = Object.get();
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
MethodArgs[ArgIdx + 1] = Args[ArgIdx];
- Expr *NewFn = CreateFunctionRefExpr(*this, Method);
+ ExprResult NewFn = CreateFunctionRefExpr(*this, Method);
+ if (NewFn.isInvalid())
+ return true;
// Once we've built TheCall, all of the expressions are properly
// owned.
@@ -8673,7 +8969,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
+ new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn.take(),
MethodArgs, NumArgs + 1,
ResultTy, VK, RParenLoc);
delete [] MethodArgs;
@@ -8692,10 +8988,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
bool IsError = false;
// Initialize the implicit object parameter.
- IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0,
- Best->FoundDecl, Method);
- TheCall->setArg(0, Object);
-
+ ExprResult ObjRes =
+ PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/0,
+ Best->FoundDecl, Method);
+ if (ObjRes.isInvalid())
+ IsError = true;
+ else
+ Object = move(ObjRes);
+ TheCall->setArg(0, Object.take());
// Check the argument types.
for (unsigned i = 0; i != NumArgsToCheck; i++) {
@@ -8731,9 +9031,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (Proto->isVariadic()) {
// Promote the arguments (C99 6.5.2.2p7).
for (unsigned i = NumArgsInProto; i != NumArgs; i++) {
- Expr *Arg = Args[i];
- IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod, 0);
- TheCall->setArg(i + 1, Arg);
+ ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
+ IsError |= Arg.isInvalid();
+ TheCall->setArg(i + 1, Arg.take());
}
}
@@ -8753,8 +9053,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
assert(Base->getType()->isRecordType() &&
"left-hand side must have class type");
- if (Base->getObjectKind() == OK_ObjCProperty)
- ConvertPropertyForRValue(Base);
+ if (Base->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = ConvertPropertyForRValue(Base);
+ if (Result.isInvalid())
+ return ExprError();
+ Base = Result.take();
+ }
SourceLocation Loc = Base->getExprLoc();
@@ -8811,8 +9115,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< "->"
- << Best->Function->getMessageUnavailableAttr(
- !Best->Function->isDeleted())
+ << getDeletedOrUnavailableSuffix(Best->Function)
<< Base->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1);
return ExprError();
@@ -8824,24 +9127,30 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
- if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0,
- Best->FoundDecl, Method))
+ ExprResult BaseResult =
+ PerformObjectArgumentInitialization(Base, /*Qualifier=*/0,
+ Best->FoundDecl, Method);
+ if (BaseResult.isInvalid())
return ExprError();
+ Base = BaseResult.take();
// Build the operator call.
- Expr *FnExpr = CreateFunctionRefExpr(*this, Method);
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, Method);
+ if (FnExpr.isInvalid())
+ return ExprError();
QualType ResultTy = Method->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr,
+ new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.take(),
&Base, 1, ResultTy, VK, OpLoc);
if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall,
Method))
return ExprError();
- return Owned(TheCall);
+
+ return MaybeBindToTemporary(TheCall);
}
/// FixOverloadedFunctionReference - E is an expression that refers to
@@ -8930,12 +9239,12 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
}
return DeclRefExpr::Create(Context,
- ULE->getQualifier(),
- ULE->getQualifierRange(),
+ ULE->getQualifierLoc(),
Fn,
ULE->getNameLoc(),
Fn->getType(),
VK_LValue,
+ Found.getDecl(),
TemplateArgs);
}
@@ -8954,17 +9263,17 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (MemExpr->isImplicitAccess()) {
if (cast<CXXMethodDecl>(Fn)->isStatic()) {
return DeclRefExpr::Create(Context,
- MemExpr->getQualifier(),
- MemExpr->getQualifierRange(),
+ MemExpr->getQualifierLoc(),
Fn,
MemExpr->getMemberLoc(),
Fn->getType(),
VK_LValue,
+ Found.getDecl(),
TemplateArgs);
} else {
SourceLocation Loc = MemExpr->getMemberLoc();
if (MemExpr->getQualifier())
- Loc = MemExpr->getQualifierRange().getBegin();
+ Loc = MemExpr->getQualifierLoc().getBeginLoc();
Base = new (Context) CXXThisExpr(Loc,
MemExpr->getBaseType(),
/*isImplicit=*/true);
@@ -8972,18 +9281,24 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
} else
Base = MemExpr->getBase();
+ ExprValueKind valueKind;
+ QualType type;
+ if (cast<CXXMethodDecl>(Fn)->isStatic()) {
+ valueKind = VK_LValue;
+ type = Fn->getType();
+ } else {
+ valueKind = VK_RValue;
+ type = Context.BoundMemberTy;
+ }
+
return MemberExpr::Create(Context, Base,
MemExpr->isArrow(),
- MemExpr->getQualifier(),
- MemExpr->getQualifierRange(),
+ MemExpr->getQualifierLoc(),
Fn,
Found,
MemExpr->getMemberNameInfo(),
TemplateArgs,
- Fn->getType(),
- cast<CXXMethodDecl>(Fn)->isStatic()
- ? VK_LValue : VK_RValue,
- OK_Ordinary);
+ type, valueKind, OK_Ordinary);
}
llvm_unreachable("Invalid reference to overloaded function");
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 89957e60deca..65cea7a69d61 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -45,8 +46,9 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) {
}
-StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, bool LeadingEmptyMacro) {
- return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacro));
+StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
+ SourceLocation LeadingEmptyMacroLoc) {
+ return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacroLoc));
}
StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc,
@@ -76,12 +78,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (!E)
return;
- if (E->isBoundMemberFunction(Context)) {
- Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func)
- << E->getSourceRange();
- return;
- }
-
SourceLocation Loc;
SourceRange R1, R2;
if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
@@ -245,11 +241,10 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
}
// Otherwise, things are good. Fill in the declaration and return it.
- TheDecl->setLocation(IdentLoc);
-
LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt);
TheDecl->setStmt(LS);
- TheDecl->setLocation(IdentLoc);
+ if (!TheDecl->isGnuLocal())
+ TheDecl->setLocation(IdentLoc);
return Owned(LS);
}
@@ -470,7 +465,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
GetTypeBeforeIntegralPromotion(CondExpr);
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
- UsualUnaryConversions(CondExpr);
+ ExprResult CondResult = UsualUnaryConversions(CondExpr);
+ if (CondResult.isInvalid())
+ return StmtError();
+ CondExpr = CondResult.take();
QualType CondType = CondExpr->getType();
SS->setCond(CondExpr);
@@ -556,7 +554,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If the LHS is not the same type as the condition, insert an implicit
// cast.
- ImpCastExprToType(Lo, CondType, CK_IntegralCast);
+ Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
CS->setLHS(Lo);
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
@@ -635,7 +633,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If the LHS is not the same type as the condition, insert an implicit
// cast.
- ImpCastExprToType(Hi, CondType, CK_IntegralCast);
+ Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
CR->setRHS(Hi);
// If the low value is bigger than the high value, the case is empty.
@@ -869,11 +867,13 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
Expr *Cond, SourceLocation CondRParen) {
assert(Cond && "ActOnDoStmt(): missing expression");
- if (CheckBooleanCondition(Cond, DoLoc))
+ ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc);
+ if (CondResult.isInvalid() || CondResult.isInvalid())
return StmtError();
+ Cond = CondResult.take();
CheckImplicitConversions(Cond, DoLoc);
- ExprResult CondResult = MaybeCreateExprWithCleanups(Cond);
+ CondResult = MaybeCreateExprWithCleanups(Cond);
if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.take();
@@ -974,7 +974,10 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
<< FirstType << First->getSourceRange();
}
if (Second && !Second->isTypeDependent()) {
- DefaultFunctionArrayLvalueConversion(Second);
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(Second);
+ if (Result.isInvalid())
+ return StmtError();
+ Second = Result.take();
QualType SecondType = Second->getType();
if (!SecondType->isObjCObjectPointerType())
Diag(ForLoc, diag::err_collection_expr_type)
@@ -992,7 +995,8 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]);
if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) {
if (!IDecl->isForwardDecl() &&
- !IDecl->lookupInstanceMethod(CSelector)) {
+ !IDecl->lookupInstanceMethod(CSelector) &&
+ !LookupMethodInQualifiedType(CSelector, OPT, true)) {
// Must further look into private implementation methods.
if (!LookupPrivateInstanceMethod(CSelector, IDecl))
Diag(ForLoc, diag::warn_collection_expr_type)
@@ -1005,6 +1009,389 @@ 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,
+ SourceLocation Loc, int diag) {
+ // Deduce the type for the iterator variable now rather than leaving it to
+ // AddInitializerToDecl, so we can produce a more suitable diagnostic.
+ TypeSourceInfo *InitTSI = 0;
+ if (Init->getType()->isVoidType() ||
+ !SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
+ SemaRef.Diag(Loc, diag) << Init->getType();
+ if (!InitTSI) {
+ Decl->setInvalidDecl();
+ return true;
+ }
+ Decl->setTypeSourceInfo(InitTSI);
+ Decl->setType(InitTSI->getType());
+
+ SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false,
+ /*TypeMayContainAuto=*/false);
+ SemaRef.FinalizeDeclaration(Decl);
+ SemaRef.CurContext->addHiddenDecl(Decl);
+ return false;
+}
+
+/// 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,
+/// nor from the diagnostics produced when analysing the implicit expressions
+/// required in a for-range statement.
+void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
+ BeginEndFunction BEF) {
+ CallExpr *CE = dyn_cast<CallExpr>(E);
+ if (!CE)
+ return;
+ FunctionDecl *D = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
+ if (!D)
+ return;
+ SourceLocation Loc = D->getLocation();
+
+ std::string Description;
+ bool IsTemplate = false;
+ if (FunctionTemplateDecl *FunTmpl = D->getPrimaryTemplate()) {
+ Description = SemaRef.getTemplateArgumentBindingsText(
+ FunTmpl->getTemplateParameters(), *D->getTemplateSpecializationArgs());
+ IsTemplate = true;
+ }
+
+ SemaRef.Diag(Loc, diag::note_for_range_begin_end)
+ << 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(),
+ /*Qualifier=*/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);
+ 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;
+}
+
+}
+
+/// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement.
+///
+/// C++0x [stmt.ranged]:
+/// A range-based for statement is equivalent to
+///
+/// {
+/// auto && __range = range-init;
+/// for ( auto __begin = begin-expr,
+/// __end = end-expr;
+/// __begin != __end;
+/// ++__begin ) {
+/// for-range-declaration = *__begin;
+/// statement
+/// }
+/// }
+///
+/// The body of the loop is not available yet, since it cannot be analysed until
+/// we have determined the type of the for-range-declaration.
+StmtResult
+Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
+ Stmt *First, SourceLocation ColonLoc, Expr *Range,
+ SourceLocation RParenLoc) {
+ if (!First || !Range)
+ return StmtError();
+
+ DeclStmt *DS = dyn_cast<DeclStmt>(First);
+ assert(DS && "first part of for range not a decl stmt");
+
+ if (!DS->isSingleDecl()) {
+ Diag(DS->getStartLoc(), diag::err_type_defined_in_for_range);
+ return StmtError();
+ }
+ if (DS->getSingleDecl()->isInvalidDecl())
+ return StmtError();
+
+ if (DiagnoseUnexpandedParameterPack(Range, UPPC_Expression))
+ return StmtError();
+
+ // Build auto && __range = range-init
+ SourceLocation RangeLoc = Range->getLocStart();
+ VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
+ Context.getAutoRRefDeductType(),
+ "__range");
+ if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
+ diag::err_for_range_deduction_failure))
+ return StmtError();
+
+ // Claim the type doesn't contain auto: we've already done the checking.
+ DeclGroupPtrTy RangeGroup =
+ BuildDeclaratorGroup((Decl**)&RangeVar, 1, /*TypeMayContainAuto=*/false);
+ StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
+ if (RangeDecl.isInvalid())
+ return StmtError();
+
+ return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
+ /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
+ RParenLoc);
+}
+
+/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement.
+StmtResult
+Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
+ Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
+ Expr *Inc, Stmt *LoopVarDecl,
+ SourceLocation RParenLoc) {
+ Scope *S = getCurScope();
+
+ DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl);
+ VarDecl *RangeVar = cast<VarDecl>(RangeDS->getSingleDecl());
+ QualType RangeVarType = RangeVar->getType();
+
+ DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl);
+ VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl());
+
+ StmtResult BeginEndDecl = BeginEnd;
+ ExprResult NotEqExpr = Cond, IncrExpr = Inc;
+
+ if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) {
+ SourceLocation RangeLoc = RangeVar->getLocation();
+
+ ExprResult RangeRef = BuildDeclRefExpr(RangeVar,
+ RangeVarType.getNonReferenceType(),
+ VK_LValue, ColonLoc);
+ if (RangeRef.isInvalid())
+ return StmtError();
+
+ QualType AutoType = Context.getAutoDeductType();
+ Expr *Range = RangeVar->getInit();
+ if (!Range)
+ return StmtError();
+ QualType RangeType = Range->getType();
+
+ if (RequireCompleteType(RangeLoc, RangeType,
+ PDiag(diag::err_for_range_incomplete_type)))
+ return StmtError();
+
+ // Build auto __begin = begin-expr, __end = end-expr.
+ VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
+ "__begin");
+ VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
+ "__end");
+
+ // Build begin-expr and end-expr and attach to __begin and __end variables.
+ ExprResult BeginExpr, EndExpr;
+ if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) {
+ // - if _RangeT is an array type, begin-expr and end-expr are __range and
+ // __range + __bound, respectively, where __bound is the array bound. If
+ // _RangeT is an array of unknown size or an array of incomplete type,
+ // the program is ill-formed;
+
+ // begin-expr is __range.
+ BeginExpr = RangeRef;
+ if (FinishForRangeVarDecl(*this, BeginVar, RangeRef.get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ return StmtError();
+ }
+
+ // Find the array bound.
+ ExprResult BoundExpr;
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
+ BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(),
+ Context.IntTy, RangeLoc));
+ else if (const VariableArrayType *VAT =
+ dyn_cast<VariableArrayType>(UnqAT))
+ BoundExpr = VAT->getSizeExpr();
+ else {
+ // Can't be a DependentSizedArrayType or an IncompleteArrayType since
+ // UnqAT is not incomplete and Range is not type-dependent.
+ assert(0 && "Unexpected array type in for-range");
+ return StmtError();
+ }
+
+ // end-expr is __range + __bound.
+ EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, RangeRef.get(),
+ BoundExpr.get());
+ if (EndExpr.isInvalid())
+ return StmtError();
+ if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ 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.
+ }
+
+ BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar,
+ BEF_begin, BeginNameInfo,
+ BeginMemberLookup, RangeRef.get());
+ if (BeginExpr.isInvalid())
+ return StmtError();
+
+ EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar,
+ BEF_end, EndNameInfo,
+ EndMemberLookup, RangeRef.get());
+ if (EndExpr.isInvalid())
+ return StmtError();
+ }
+
+ // C++0x [decl.spec.auto]p6: 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)
+ << BeginType << EndType;
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ }
+
+ Decl *BeginEndDecls[] = { BeginVar, EndVar };
+ // Claim the type doesn't contain auto: we've already done the checking.
+ DeclGroupPtrTy BeginEndGroup =
+ BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false);
+ BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
+
+ ExprResult BeginRef = BuildDeclRefExpr(BeginVar,
+ BeginType.getNonReferenceType(),
+ VK_LValue, ColonLoc);
+ ExprResult EndRef = BuildDeclRefExpr(EndVar, EndType.getNonReferenceType(),
+ VK_LValue, ColonLoc);
+
+ // Build and check __begin != __end expression.
+ NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal,
+ BeginRef.get(), EndRef.get());
+ NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get());
+ NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
+ if (NotEqExpr.isInvalid()) {
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ if (!Context.hasSameType(BeginType, EndType))
+ NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ return StmtError();
+ }
+
+ // Build and check ++__begin expression.
+ IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
+ IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
+ if (IncrExpr.isInvalid()) {
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ return StmtError();
+ }
+
+ // Build and check *__begin expression.
+ ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
+ if (DerefExpr.isInvalid()) {
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ return StmtError();
+ }
+
+ // Attach *__begin as initializer for VD.
+ if (!LoopVar->isInvalidDecl()) {
+ AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false,
+ /*TypeMayContainAuto=*/true);
+ if (LoopVar->isInvalidDecl())
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ }
+ }
+
+ return Owned(new (Context) CXXForRangeStmt(RangeDS,
+ cast_or_null<DeclStmt>(BeginEndDecl.get()),
+ NotEqExpr.take(), IncrExpr.take(),
+ LoopVarDS, /*Body=*/0, ForLoc,
+ ColonLoc, RParenLoc));
+}
+
+/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.
+/// This is a separate step from ActOnCXXForRangeStmt because analysis of the
+/// body cannot be performed until after the type of the range variable is
+/// determined.
+StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) {
+ if (!S || !B)
+ return StmtError();
+
+ cast<CXXForRangeStmt>(S)->setBody(B);
+ return S;
+}
+
StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc,
LabelDecl *TheDecl) {
@@ -1020,8 +1407,12 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
if (!E->isTypeDependent()) {
QualType ETy = E->getType();
QualType DestTy = Context.getPointerType(Context.VoidTy.withConst());
+ ExprResult ExprRes = Owned(E);
AssignConvertType ConvTy =
- CheckSingleAssignmentConstraints(DestTy, E);
+ CheckSingleAssignmentConstraints(DestTy, ExprRes);
+ if (ExprRes.isInvalid())
+ return StmtError();
+ E = ExprRes.take();
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
return StmtError();
}
@@ -1188,7 +1579,10 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (RetValExp) {
// Don't call UsualUnaryConversions(), since we don't want to do
// integer promotions here.
- DefaultFunctionArrayLvalueConversion(RetValExp);
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
+ if (Result.isInvalid())
+ return StmtError();
+ RetValExp = Result.take();
CurBlock->ReturnType = RetValExp->getType();
if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
// We have to remove a 'const' added to copied-in variable which was
@@ -1290,8 +1684,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (RetValExp->getType()->isVoidType())
D = diag::ext_return_has_void_expr;
else {
- IgnoredValueConversions(RetValExp);
- ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid);
+ ExprResult Result = Owned(RetValExp);
+ Result = IgnoredValueConversions(Result.take());
+ if (Result.isInvalid())
+ return StmtError();
+ RetValExp = Result.take();
+ RetValExp = ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid).take();
}
// return (some void expression); is legal in C++.
@@ -1498,8 +1896,11 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
}
- DefaultFunctionArrayLvalueConversion(Exprs[i]);
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
+ if (Result.isInvalid())
+ return StmtError();
+ Exprs[i] = Result.take();
InputConstraintInfos.push_back(Info);
}
@@ -1614,7 +2015,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (InputDomain == AD_Int && OutputDomain == AD_Int &&
!isOperandMentioned(InputOpNo, Pieces) &&
InputExpr->isEvaluatable(Context)) {
- ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast);
+ InputExpr = ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast).take();
Exprs[InputOpNo] = InputExpr;
NS->setInputExpr(i, InputExpr);
continue;
@@ -1663,8 +2064,11 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
Expr *Throw) {
if (Throw) {
- DefaultLvalueConversion(Throw);
+ ExprResult Result = DefaultLvalueConversion(Throw);
+ if (Result.isInvalid())
+ return StmtError();
+ Throw = Result.take();
QualType ThrowType = Throw->getType();
// Make sure the expression type is an ObjC pointer or "void *".
if (!ThrowType->isDependentType() &&
@@ -1703,8 +2107,11 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
Stmt *SyncBody) {
getCurFunction()->setHasBranchProtectedScope();
- DefaultLvalueConversion(SyncExpr);
+ ExprResult Result = DefaultLvalueConversion(SyncExpr);
+ if (Result.isInvalid())
+ return StmtError();
+ SyncExpr = Result.take();
// Make sure the expression type is an ObjC pointer or "void *".
if (!SyncExpr->getType()->isDependentType() &&
!SyncExpr->getType()->isObjCObjectPointerType()) {
@@ -1766,7 +2173,7 @@ StmtResult
Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
MultiStmtArg RawHandlers) {
// Don't report an error if 'try' is used in system headers.
- if (!getLangOptions().Exceptions &&
+ if (!getLangOptions().CXXExceptions &&
!getSourceManager().isInSystemHeader(TryLoc))
Diag(TryLoc, diag::err_exceptions_disabled) << "try";
@@ -1824,3 +2231,36 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock,
Handlers, NumHandlers));
}
+
+StmtResult
+Sema::ActOnSEHTryBlock(bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler) {
+ assert(TryBlock && Handler);
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return Owned(SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler));
+}
+
+StmtResult
+Sema::ActOnSEHExceptBlock(SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block) {
+ assert(FilterExpr && Block);
+
+ if(!FilterExpr->getType()->isIntegerType()) {
+ return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType());
+ }
+
+ return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block));
+}
+
+StmtResult
+Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
+ Stmt *Block) {
+ assert(Block);
+ return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
+}
+
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f02dd2582402..ef0912485b66 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -76,13 +76,13 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
return 0;
}
-static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) {
+void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
// The set of class templates we've already seen.
llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
LookupResult::Filter filter = R.makeFilter();
while (filter.hasNext()) {
NamedDecl *Orig = filter.next();
- NamedDecl *Repl = isAcceptableTemplateName(C, Orig);
+ NamedDecl *Repl = isAcceptableTemplateName(Context, Orig);
if (!Repl)
filter.erase();
else if (Repl != Orig) {
@@ -114,6 +114,14 @@ static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) {
filter.done();
}
+bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R) {
+ for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)
+ if (isAcceptableTemplateName(Context, *I))
+ return true;
+
+ return false;
+}
+
TemplateNameKind Sema::isTemplateName(Scope *S,
CXXScopeSpec &SS,
bool hasTemplateKeyword,
@@ -289,7 +297,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
DeclarationName Name = Found.getLookupName();
if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx,
false, CTC_CXXCasts)) {
- FilterAcceptableTemplateNames(Context, Found);
+ FilterAcceptableTemplateNames(Found);
if (!Found.empty()) {
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
@@ -311,7 +319,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
}
- FilterAcceptableTemplateNames(Context, Found);
+ FilterAcceptableTemplateNames(Found);
if (Found.empty()) {
if (isDependent)
MemberOfUnknownSpecialization = true;
@@ -327,7 +335,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
LookupOrdinaryName);
LookupName(FoundOuter, S);
- FilterAcceptableTemplateNames(Context, FoundOuter);
+ FilterAcceptableTemplateNames(FoundOuter);
if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
@@ -368,9 +376,6 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
-
DeclContext *DC = getFunctionLevelDeclContext();
if (!isAddressOfOperand &&
@@ -386,7 +391,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
/*This*/ 0, ThisType,
/*IsArrow*/ true,
/*Op*/ SourceLocation(),
- Qualifier, SS.getRange(),
+ SS.getWithLocInContext(Context),
FirstQualifierInScope,
NameInfo,
TemplateArgs));
@@ -472,7 +477,8 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
else
TArg = Template;
return TemplateArgumentLoc(TArg,
- Arg.getScopeSpec().getRange(),
+ Arg.getScopeSpec().getWithLocInContext(
+ SemaRef.Context),
Arg.getLocation(),
Arg.getEllipsisLoc());
}
@@ -497,7 +503,7 @@ void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn,
/// (otherwise, "class" was used), and KeyLoc is the location of the
/// "class" or "typename" keyword. ParamName is the name of the
/// parameter (NULL indicates an unnamed template parameter) and
-/// ParamName is the location of the parameter name (if any).
+/// ParamNameLoc is the location of the parameter name (if any).
/// If the type parameter has a default argument, it will be added
/// later via ActOnTypeParameterDefault.
Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
@@ -527,8 +533,9 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
TemplateTypeParmDecl *Param
= TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
- Loc, Depth, Position, ParamName, Typename,
- Ellipsis);
+ KeyLoc, Loc, Depth, Position, ParamName,
+ Typename, Ellipsis);
+ Param->setAccess(AS_public);
if (Invalid)
Param->setInvalidDecl();
@@ -651,9 +658,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
bool IsParameterPack = D.hasEllipsis();
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ D.getSourceRange().getBegin(),
D.getIdentifierLoc(),
Depth, Position, ParamName, T,
IsParameterPack, TInfo);
+ Param->setAccess(AS_public);
+
if (Invalid)
Param->setInvalidDecl();
@@ -678,10 +688,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
return Param;
TemplateArgument Converted;
- if (CheckTemplateArgument(Param, Param->getType(), Default, Converted)) {
+ ExprResult DefaultRes = CheckTemplateArgument(Param, Param->getType(), Default, Converted);
+ if (DefaultRes.isInvalid()) {
Param->setInvalidDecl();
return Param;
}
+ Default = DefaultRes.take();
Param->setDefaultArgument(Default, false);
}
@@ -707,13 +719,13 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
// Construct the parameter object.
bool IsParameterPack = EllipsisLoc.isValid();
- // FIXME: Pack-ness is dropped
TemplateTemplateParmDecl *Param =
TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
NameLoc.isInvalid()? TmpLoc : NameLoc,
Depth, Position, IsParameterPack,
Name, Params);
-
+ Param->setAccess(AS_public);
+
// If the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
if (Name) {
@@ -791,7 +803,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
- AccessSpecifier AS) {
+ AccessSpecifier AS,
+ unsigned NumOuterTemplateParamLists,
+ TemplateParameterList** OuterTemplateParamLists) {
assert(TemplateParams && TemplateParams->size() > 0 &&
"No template parameters");
assert(TUK != TUK_Reference && "Can only declare or define class templates");
@@ -961,11 +975,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
CXXRecordDecl *NewClass =
- CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
+ CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
PrevClassTemplate?
PrevClassTemplate->getTemplatedDecl() : 0,
/*DelayTypeCreation=*/true);
SetNestedNameSpecifier(NewClass, SS);
+ if (NumOuterTemplateParamLists > 0)
+ NewClass->setTemplateParameterListsInfo(Context,
+ NumOuterTemplateParamLists,
+ OuterTemplateParamLists);
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
@@ -1089,7 +1107,8 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
/// \brief Check for unexpanded parameter packs within the template parameters
/// of a template template parameter, recursively.
-bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateTemplateParmDecl *TTP){
+static bool DiagnoseUnexpandedParameterPacks(Sema &S,
+ TemplateTemplateParmDecl *TTP) {
TemplateParameterList *Params = TTP->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
NamedDecl *P = Params->getParam(I);
@@ -1448,9 +1467,9 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
///
/// \returns the template parameter list, if any, that corresponds to the
/// name that is preceded by the scope specifier @p SS. This template
-/// parameter list may be have template parameters (if we're declaring a
+/// parameter list may have template parameters (if we're declaring a
/// template) or may have no template parameters (if we're declaring a
-/// template specialization), or may be NULL (if we were's declaring isn't
+/// template specialization), or may be NULL (if what we're declaring isn't
/// itself a template).
TemplateParameterList *
Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
@@ -1631,14 +1650,42 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
return ParamLists[NumParamLists - 1];
}
+void Sema::NoteAllFoundTemplates(TemplateName Name) {
+ if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+ Diag(Template->getLocation(), diag::note_template_declared_here)
+ << (isa<FunctionTemplateDecl>(Template)? 0
+ : isa<ClassTemplateDecl>(Template)? 1
+ : 2)
+ << Template->getDeclName();
+ return;
+ }
+
+ if (OverloadedTemplateStorage *OST = Name.getAsOverloadedTemplate()) {
+ for (OverloadedTemplateStorage::iterator I = OST->begin(),
+ IEnd = OST->end();
+ I != IEnd; ++I)
+ Diag((*I)->getLocation(), diag::note_template_declared_here)
+ << 0 << (*I)->getDeclName();
+
+ return;
+ }
+}
+
+
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
- const TemplateArgumentListInfo &TemplateArgs) {
+ TemplateArgumentListInfo &TemplateArgs) {
TemplateDecl *Template = Name.getAsTemplateDecl();
- if (!Template) {
- // The template name does not resolve to a template, so we just
- // build a dependent template-id type.
- return Context.getTemplateSpecializationType(Name, TemplateArgs);
+ if (!Template || isa<FunctionTemplateDecl>(Template)) {
+ // We might have a substituted template template parameter pack. If so,
+ // build a template specialization type for it.
+ if (Name.getAsSubstTemplateTemplateParmPack())
+ return Context.getTemplateSpecializationType(Name, TemplateArgs);
+
+ Diag(TemplateLoc, diag::err_template_id_not_a_type)
+ << Name;
+ NoteAllFoundTemplates(Name);
+ return QualType();
}
// Check that the template argument list is well-formed for this
@@ -1727,6 +1774,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getTemplatedDecl()->getTagKind(),
ClassTemplate->getDeclContext(),
ClassTemplate->getLocation(),
+ ClassTemplate->getLocation(),
ClassTemplate,
Converted.data(),
Converted.size(), 0);
@@ -1746,77 +1794,148 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
}
TypeResult
-Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
+Sema::ActOnTemplateIdType(CXXScopeSpec &SS,
+ TemplateTy TemplateD, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc) {
+ if (SS.isInvalid())
+ return true;
+
TemplateName Template = TemplateD.getAsVal<TemplateName>();
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
+ QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ TemplateArgs);
+
+ // Build type-source information.
+ TypeLocBuilder TLB;
+ DependentTemplateSpecializationTypeLoc SpecTL
+ = TLB.push<DependentTemplateSpecializationTypeLoc>(T);
+ SpecTL.setKeywordLoc(SourceLocation());
+ SpecTL.setNameLoc(TemplateLoc);
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I)
+ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
+ return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
+ }
+
QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
TemplateArgsIn.release();
if (Result.isNull())
return true;
- TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Result);
- TemplateSpecializationTypeLoc TL
- = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc());
- TL.setTemplateNameLoc(TemplateLoc);
- TL.setLAngleLoc(LAngleLoc);
- TL.setRAngleLoc(RAngleLoc);
- for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
-
- return CreateParsedType(Result, DI);
+ // Build type-source information.
+ TypeLocBuilder TLB;
+ TemplateSpecializationTypeLoc SpecTL
+ = TLB.push<TemplateSpecializationTypeLoc>(Result);
+ SpecTL.setTemplateNameLoc(TemplateLoc);
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
+ SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
+
+ if (SS.isNotEmpty()) {
+ // Create an elaborated-type-specifier containing the nested-name-specifier.
+ Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result);
+ ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result);
+ ElabTL.setKeywordLoc(SourceLocation());
+ ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ }
+
+ return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
-TypeResult Sema::ActOnTagTemplateIdType(CXXScopeSpec &SS,
- TypeResult TypeResult,
- TagUseKind TUK,
+TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
TypeSpecifierType TagSpec,
- SourceLocation TagLoc) {
- if (TypeResult.isInvalid())
- return ::TypeResult();
-
- TypeSourceInfo *DI;
- QualType Type = GetTypeFromParser(TypeResult.get(), &DI);
-
- // Verify the tag specifier.
+ SourceLocation TagLoc,
+ CXXScopeSpec &SS,
+ TemplateTy TemplateD,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation RAngleLoc) {
+ TemplateName Template = TemplateD.getAsVal<TemplateName>();
+
+ // Translate the parser's template argument list in our AST format.
+ TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
+ translateTemplateArguments(TemplateArgsIn, TemplateArgs);
+
+ // Determine the tag kind
TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ ElaboratedTypeKeyword Keyword
+ = TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
- if (const RecordType *RT = Type->getAs<RecordType>()) {
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
+ QualType T = Context.getDependentTemplateSpecializationType(Keyword,
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ TemplateArgs);
+
+ // Build type-source information.
+ TypeLocBuilder TLB;
+ DependentTemplateSpecializationTypeLoc SpecTL
+ = TLB.push<DependentTemplateSpecializationTypeLoc>(T);
+ SpecTL.setKeywordLoc(TagLoc);
+ SpecTL.setNameLoc(TemplateLoc);
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I)
+ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
+ return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
+ }
+
+ QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
+ if (Result.isNull())
+ return TypeResult();
+
+ // Check the tag kind
+ if (const RecordType *RT = Result->getAs<RecordType>()) {
RecordDecl *D = RT->getDecl();
-
+
IdentifierInfo *Id = D->getIdentifier();
assert(Id && "templated class must have an identifier");
-
+
if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
Diag(TagLoc, diag::err_use_with_wrong_tag)
- << Type
+ << Result
<< FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName());
Diag(D->getLocation(), diag::note_previous_use);
}
}
-
- ElaboratedTypeKeyword Keyword
- = TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
- QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type);
-
- TypeSourceInfo *ElabDI = Context.CreateTypeSourceInfo(ElabType);
- ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(ElabDI->getTypeLoc());
- TL.setKeywordLoc(TagLoc);
- TL.setQualifierRange(SS.getRange());
- TL.getNamedTypeLoc().initializeFullCopy(DI->getTypeLoc());
- return CreateParsedType(ElabType, ElabDI);
+
+ // Provide source-location information for the template specialization.
+ TypeLocBuilder TLB;
+ TemplateSpecializationTypeLoc SpecTL
+ = TLB.push<TemplateSpecializationTypeLoc>(Result);
+ SpecTL.setTemplateNameLoc(TemplateLoc);
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
+ SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
+
+ // Construct an elaborated type containing the nested-name-specifier (if any)
+ // and keyword.
+ Result = Context.getElaboratedType(Keyword, SS.getScopeRep(), Result);
+ ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result);
+ ElabTL.setKeywordLoc(TagLoc);
+ ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- bool RequiresADL,
+ LookupResult &R,
+ bool RequiresADL,
const TemplateArgumentListInfo &TemplateArgs) {
// FIXME: Can we do any checking at this point? I guess we could check the
// template arguments that we have against the template name, if the template
@@ -1832,19 +1951,12 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
assert(!R.empty() && "empty lookup results when building templateid");
assert(!R.isAmbiguous() && "ambiguous lookup when building templateid");
- NestedNameSpecifier *Qualifier = 0;
- SourceRange QualifierRange;
- if (SS.isSet()) {
- Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
- QualifierRange = SS.getRange();
- }
-
// We don't want lookup warnings at this point.
R.suppressDiagnostics();
UnresolvedLookupExpr *ULE
= UnresolvedLookupExpr::Create(Context, R.getNamingClass(),
- Qualifier, QualifierRange,
+ SS.getWithLocInContext(Context),
R.getLookupNameInfo(),
RequiresADL, TemplateArgs,
R.begin(), R.end());
@@ -1935,7 +2047,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
isa<CXXRecordDecl>(LookupCtx) &&
- cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) {
+ (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() ||
+ cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases())) {
// This is a dependent template. Handle it below.
} else if (TNK == TNK_Non_template) {
Diag(Name.getSourceRange().getBegin(),
@@ -2043,7 +2156,6 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
///
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
-///
/// \returns the substituted template argument, or NULL if an error occurred.
static TypeSourceInfo *
SubstDefaultTemplateArgument(Sema &SemaRef,
@@ -2140,6 +2252,9 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
///
+/// \param QualifierLoc Will be set to the nested-name-specifier (with
+/// source-location information) that precedes the template name.
+///
/// \returns the substituted template argument, or NULL if an error occurred.
static TemplateName
SubstDefaultTemplateArgument(Sema &SemaRef,
@@ -2147,7 +2262,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
TemplateTemplateParmDecl *Param,
- llvm::SmallVectorImpl<TemplateArgument> &Converted) {
+ llvm::SmallVectorImpl<TemplateArgument> &Converted,
+ NestedNameSpecifierLoc &QualifierLoc) {
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
@@ -2159,7 +2275,16 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
Converted.size(),
SourceRange(TemplateLoc, RAngleLoc));
- return SemaRef.SubstTemplateName(
+ // Substitute into the nested-name-specifier first,
+ QualifierLoc = Param->getDefaultArgument().getTemplateQualifierLoc();
+ if (QualifierLoc) {
+ QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
+ AllTemplateArgs);
+ if (!QualifierLoc)
+ return TemplateName();
+ }
+
+ return SemaRef.SubstTemplateName(QualifierLoc,
Param->getDefaultArgument().getArgument().getAsTemplate(),
Param->getDefaultArgument().getTemplateNameLoc(),
AllTemplateArgs);
@@ -2195,10 +2320,10 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();
ExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NonTypeParm,
- Converted);
+ TemplateLoc,
+ RAngleLoc,
+ NonTypeParm,
+ Converted);
if (Arg.isInvalid())
return TemplateArgumentLoc();
@@ -2211,16 +2336,19 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
if (!TempTempParm->hasDefaultArgument())
return TemplateArgumentLoc();
+
+ NestedNameSpecifierLoc QualifierLoc;
TemplateName TName = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
TempTempParm,
- Converted);
+ Converted,
+ QualifierLoc);
if (TName.isNull())
return TemplateArgumentLoc();
return TemplateArgumentLoc(TemplateArgument(TName),
- TempTempParm->getDefaultArgument().getTemplateQualifierRange(),
+ TempTempParm->getDefaultArgument().getTemplateQualifierLoc(),
TempTempParm->getDefaultArgument().getTemplateNameLoc());
}
@@ -2300,9 +2428,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
case TemplateArgument::Expression: {
- Expr *E = Arg.getArgument().getAsExpr();
TemplateArgument Result;
- if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK))
+ ExprResult Res =
+ CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(),
+ Result, CTAK);
+ if (Res.isInvalid())
return true;
Converted.push_back(Result);
@@ -2331,28 +2461,23 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
DeclarationNameInfo NameInfo(DTN->getIdentifier(),
Arg.getTemplateNameLoc());
- // FIXME: TemplateArgumentLoc should store a NestedNameSpecifierLoc
- // for the template name.
CXXScopeSpec SS;
- SS.MakeTrivial(Context, DTN->getQualifier(),
- Arg.getTemplateQualifierRange());
- Expr *E = DependentScopeDeclRefExpr::Create(Context,
+ SS.Adopt(Arg.getTemplateQualifierLoc());
+ ExprResult E = Owned(DependentScopeDeclRefExpr::Create(Context,
SS.getWithLocInContext(Context),
- NameInfo);
+ NameInfo));
// If we parsed the template argument as a pack expansion, create a
// pack expansion expression.
if (Arg.getArgument().getKind() == TemplateArgument::TemplateExpansion){
- ExprResult Expansion = ActOnPackExpansion(E,
- Arg.getTemplateEllipsisLoc());
- if (Expansion.isInvalid())
+ E = ActOnPackExpansion(E.take(), Arg.getTemplateEllipsisLoc());
+ if (E.isInvalid())
return true;
-
- E = Expansion.get();
}
TemplateArgument Result;
- if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
+ E = CheckTemplateArgument(NTTP, NTTPType, E.take(), Result);
+ if (E.isInvalid())
return true;
Converted.push_back(Result);
@@ -2461,7 +2586,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
- const TemplateArgumentListInfo &TemplateArgs,
+ TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
llvm::SmallVectorImpl<TemplateArgument> &Converted) {
TemplateParameterList *Params = Template->getTemplateParameters();
@@ -2499,6 +2624,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// a template-id shall match the type and form specified for the
// corresponding parameter declared by the template in its
// template-parameter-list.
+ bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
llvm::SmallVector<TemplateArgument, 2> ArgumentPack;
TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
@@ -2604,17 +2730,18 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
break;
}
+ NestedNameSpecifierLoc QualifierLoc;
TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
TempParm,
- Converted);
+ Converted,
+ QualifierLoc);
if (Name.isNull())
return true;
- Arg = TemplateArgumentLoc(TemplateArgument(Name),
- TempParm->getDefaultArgument().getTemplateQualifierRange(),
- TempParm->getDefaultArgument().getTemplateNameLoc());
+ Arg = TemplateArgumentLoc(TemplateArgument(Name), QualifierLoc,
+ TempParm->getDefaultArgument().getTemplateNameLoc());
}
// Introduce an instantiation record that describes where we are using
@@ -2628,6 +2755,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
RAngleLoc, 0, Converted))
return true;
+ // Core issue 150 (assumed resolution): if this is a template template
+ // parameter, keep track of the default template arguments from the
+ // template definition.
+ if (isTemplateTemplateParameter)
+ TemplateArgs.addArgument(Arg);
+
// Move to the next template parameter and argument.
++Param;
++ArgIdx;
@@ -2853,7 +2986,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
return true;
}
- if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl()) {
+ if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) {
S.Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR;
S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here);
return true;
@@ -2961,13 +3094,25 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
SourceLocation AddrOpLoc;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
if (UnOp->getOpcode() == UO_AddrOf) {
+ // Support &__uuidof(class_with_uuid) as a non-type template argument.
+ // Very common in Microsoft COM headers.
+ if (S.getLangOptions().Microsoft &&
+ isa<CXXUuidofExpr>(UnOp->getSubExpr())) {
+ Converted = TemplateArgument(ArgIn);
+ return false;
+ }
+
DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
AddressTaken = true;
AddrOpLoc = UnOp->getOperatorLoc();
}
- } else
+ } else {
+ if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) {
+ Converted = TemplateArgument(ArgIn);
+ return false;
+ }
DRE = dyn_cast<DeclRefExpr>(Arg);
-
+ }
if (!DRE) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
@@ -3266,15 +3411,14 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
/// non-type template parameter.
///
/// This routine implements the semantics of C++ [temp.arg.nontype].
-/// It returns true if an error occurred, and false otherwise. \p
+/// If an error occurred, it returns ExprError(); otherwise, it
+/// returns the converted template argument. \p
/// InstantiatedParamType is the type of the non-type template
/// parameter after it has been instantiated.
-///
-/// If no error was detected, Converted receives the converted template argument.
-bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgument &Converted,
- CheckTemplateArgumentKind CTAK) {
+ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ QualType InstantiatedParamType, Expr *Arg,
+ TemplateArgument &Converted,
+ CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
// If either the parameter has a dependent type or the argument is
@@ -3282,7 +3426,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
- return false;
+ return Owned(Arg);
}
// C++ [temp.arg.nontype]p5:
@@ -3312,12 +3456,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
diag::err_template_arg_not_integral_or_enumeral)
<< ArgType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ return ExprError();
} else if (!Arg->isValueDependent() &&
!Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) {
Diag(NonConstantLoc, diag::err_template_arg_not_ice)
<< ArgType << Arg->getSourceRange();
- return true;
+ return ExprError();
}
// From here on out, all we care about are the unqualified forms
@@ -3340,21 +3484,21 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
<< ArgType << ParamType;
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ return ExprError();
} else if (ParamType->isBooleanType()) {
// This is an integral-to-boolean conversion.
- ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean);
+ Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean).take();
} else if (IsIntegralPromotion(Arg, ArgType, ParamType) ||
!ParamType->isEnumeralType()) {
// This is an integral promotion or conversion.
- ImpCastExprToType(Arg, ParamType, CK_IntegralCast);
+ Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralCast).take();
} else {
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ return ExprError();
}
QualType IntegerType = Context.getCanonicalType(ParamType);
@@ -3404,13 +3548,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// The argument is value-dependent. Create a new
// TemplateArgument with the converted expression.
Converted = TemplateArgument(Arg);
- return false;
+ return Owned(Arg);
}
Converted = TemplateArgument(Value,
ParamType->isEnumeralType() ? ParamType
: IntegerType);
- return false;
+ return Owned(Arg);
}
DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction
@@ -3422,7 +3566,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (ArgType->isNullPtrType() &&
(ParamType->isPointerType() || ParamType->isMemberPointerType())) {
Converted = TemplateArgument((NamedDecl *)0);
- return false;
+ return Owned(Arg);
}
// Handle pointer-to-function, reference-to-function, and
@@ -3454,22 +3598,25 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
true,
FoundResult)) {
if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
- return true;
+ return ExprError();
Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
ArgType = Arg->getType();
} else
- return true;
+ return ExprError();
}
- if (!ParamType->isMemberPointerType())
- return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted);
+ if (!ParamType->isMemberPointerType()) {
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted))
+ return ExprError();
+ return Owned(Arg);
+ }
if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(),
false)) {
- ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg));
+ Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
} else if (!Context.hasSameUnqualifiedType(ArgType,
ParamType.getNonReferenceType())) {
// We can't perform this conversion.
@@ -3477,10 +3624,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ return ExprError();
}
- return CheckTemplateArgumentPointerToMember(Arg, Converted);
+ if (CheckTemplateArgumentPointerToMember(Arg, Converted))
+ return ExprError();
+ return Owned(Arg);
}
if (ParamType->isPointerType()) {
@@ -3491,9 +3640,11 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamType->getPointeeType()->isIncompleteOrObjectType() &&
"Only object pointers allowed here");
- return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted);
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted))
+ return ExprError();
+ return Owned(Arg);
}
if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
@@ -3512,17 +3663,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
true,
FoundResult)) {
if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
- return true;
+ return ExprError();
Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
ArgType = Arg->getType();
} else
- return true;
+ return ExprError();
}
- return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted);
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted))
+ return ExprError();
+ return Owned(Arg);
}
// -- For a non-type template-parameter of type pointer to data
@@ -3532,17 +3685,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
// Types match exactly: nothing more to do here.
} else if (IsQualificationConversion(ArgType, ParamType, false)) {
- ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg));
+ Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
} else {
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ return ExprError();
}
- return CheckTemplateArgumentPointerToMember(Arg, Converted);
+ if (CheckTemplateArgumentPointerToMember(Arg, Converted))
+ return ExprError();
+ return Owned(Arg);
}
/// \brief Check a template argument against its corresponding
@@ -3636,11 +3791,8 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
// the element type on the parameter could be more qualified than the
// element type in the expression we constructed.
if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
- ParamType.getUnqualifiedType(), false)) {
- Expr *RefE = RefExpr.takeAs<Expr>();
- ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CK_NoOp);
- RefExpr = Owned(RefE);
- }
+ ParamType.getUnqualifiedType(), false))
+ RefExpr = ImpCastExprToType(RefExpr.take(), ParamType.getUnqualifiedType(), CK_NoOp);
assert(!RefExpr.isInvalid() &&
Context.hasSameType(((Expr*) RefExpr.get())->getType(),
@@ -3659,12 +3811,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
if (T->isFunctionType() || T->isArrayType()) {
// Decay functions and arrays.
- Expr *RefE = (Expr *)RefExpr.get();
- DefaultFunctionArrayConversion(RefE);
- if (RefE != RefExpr.get()) {
- RefExpr.release();
- RefExpr = Owned(RefE);
- }
+ RefExpr = DefaultFunctionArrayConversion(RefExpr.take());
+ if (RefExpr.isInvalid())
+ return ExprError();
return move(RefExpr);
}
@@ -3703,18 +3852,18 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
if (T->isCharType() || T->isWideCharType())
return Owned(new (Context) CharacterLiteral(
Arg.getAsIntegral()->getZExtValue(),
- T->isWideCharType(),
- T,
- Loc));
+ T->isWideCharType(), T, Loc));
if (T->isBooleanType())
return Owned(new (Context) CXXBoolLiteralExpr(
Arg.getAsIntegral()->getBoolValue(),
- T,
- Loc));
+ T, Loc));
+ // If this is an enum type that we're instantiating, we need to use an integer
+ // type the same size as the enumerator. We don't want to build an
+ // IntegerLiteral with enum type.
QualType BT;
if (const EnumType *ET = T->getAs<EnumType>())
- BT = ET->getDecl()->getPromotionType();
+ BT = ET->getDecl()->getIntegerType();
else
BT = T;
@@ -3722,10 +3871,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
if (T->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
- E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast,
- E, 0,
- Context.getTrivialTypeSourceInfo(T, Loc),
- Loc, Loc);
+ E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast, E, 0,
+ Context.getTrivialTypeSourceInfo(T, Loc),
+ Loc, Loc);
}
return Owned(E);
@@ -4245,7 +4393,7 @@ static NamedDecl *getPreviousDecl(NamedDecl *ND) {
return FD->getPreviousDeclaration();
if (TagDecl *TD = dyn_cast<TagDecl>(ND))
return TD->getPreviousDeclaration();
- if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND))
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
return TD->getPreviousDeclaration();
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
return FTD->getPreviousDeclaration();
@@ -4268,6 +4416,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
MultiTemplateParamsArg TemplateParameterLists) {
assert(TUK != TUK_Reference && "References are not specializations");
+ // 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();
+
// Find the class template we're specializing
TemplateName Name = TemplateD.getAsVal<TemplateName>();
ClassTemplateDecl *ClassTemplate
@@ -4298,10 +4451,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (Invalid)
return true;
- unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size();
- if (TemplateParams)
- --NumMatchedTemplateParamLists;
-
if (TemplateParams && TemplateParams->size() > 0) {
isPartialSpecialization = true;
@@ -4443,10 +4592,15 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Since the only prior class template specialization with these
// arguments was referenced but not declared, or we're only
// referencing this specialization as a friend, reuse that
- // declaration node as our own, updating its source location to
- // reflect our new declaration.
+ // declaration node as our own, updating its source location and
+ // the list of outer template parameters to reflect our new declaration.
Specialization = PrevDecl;
Specialization->setLocation(TemplateNameLoc);
+ if (TemplateParameterLists.size() > 0) {
+ Specialization->setTemplateParameterListsInfo(Context,
+ TemplateParameterLists.size(),
+ (TemplateParameterList**) TemplateParameterLists.release());
+ }
PrevDecl = 0;
CanonType = Context.getTypeDeclType(Specialization);
} else if (isPartialSpecialization) {
@@ -4471,7 +4625,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateNameLoc,
Attr,
TemplateParams,
- AS_none);
+ AS_none,
+ TemplateParameterLists.size() - 1,
+ (TemplateParameterList**) TemplateParameterLists.release());
}
// Create a new class template partial specialization declaration node.
@@ -4482,7 +4638,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
ClassTemplatePartialSpecializationDecl *Partial
= ClassTemplatePartialSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
- TemplateNameLoc,
+ KWLoc, TemplateNameLoc,
TemplateParams,
ClassTemplate,
Converted.data(),
@@ -4492,9 +4648,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
PrevPartial,
SequenceNumber);
SetNestedNameSpecifier(Partial, SS);
- if (NumMatchedTemplateParamLists > 0 && SS.isSet()) {
+ if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(Context,
- NumMatchedTemplateParamLists,
+ TemplateParameterLists.size() - 1,
(TemplateParameterList**) TemplateParameterLists.release());
}
@@ -4545,15 +4701,15 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Specialization
= ClassTemplateSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
- TemplateNameLoc,
+ KWLoc, TemplateNameLoc,
ClassTemplate,
Converted.data(),
Converted.size(),
PrevDecl);
SetNestedNameSpecifier(Specialization, SS);
- if (NumMatchedTemplateParamLists > 0 && SS.isSet()) {
+ if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
- NumMatchedTemplateParamLists,
+ TemplateParameterLists.size(),
(TemplateParameterList**) TemplateParameterLists.release());
}
@@ -4623,8 +4779,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateArgs, CanonType);
if (TUK != TUK_Friend) {
Specialization->setTypeAsWritten(WrittenTy);
- if (TemplateParams)
- Specialization->setTemplateKeywordLoc(TemplateParams->getTemplateLoc());
+ Specialization->setTemplateKeywordLoc(TemplateKWLoc);
}
TemplateArgsIn.release();
@@ -4927,7 +5082,7 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
/// this function specialization.
bool
Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
// The set of function template specializations that could match this
// explicit function template specialization.
@@ -4983,7 +5138,17 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
- Specialization->setLocation(FD->getLocation());
+
+ FunctionTemplateSpecializationInfo *SpecInfo
+ = Specialization->getTemplateSpecializationInfo();
+ assert(SpecInfo && "Function template specialization info missing?");
+ {
+ // Note: do not overwrite location info if previous template
+ // specialization kind was explicit.
+ TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
+ if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation)
+ Specialization->setLocation(FD->getLocation());
+ }
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
@@ -5006,10 +5171,6 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// before the first use of that specialization that would cause an implicit
// instantiation to take place, in every translation unit in which such a
// use occurs; no diagnostic is required.
- FunctionTemplateSpecializationInfo *SpecInfo
- = Specialization->getTemplateSpecializationInfo();
- assert(SpecInfo && "Function template specialization info missing?");
-
bool HasNoEffect = false;
if (!isFriend &&
CheckSpecializationInstantiationRedecl(FD->getLocation(),
@@ -5402,7 +5563,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization
= ClassTemplateSpecializationDecl::Create(Context, Kind,
ClassTemplate->getDeclContext(),
- TemplateNameLoc,
+ KWLoc, TemplateNameLoc,
ClassTemplate,
Converted.data(),
Converted.size(),
@@ -5883,26 +6044,34 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
return true;
}
+ // Create the resulting type.
ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
- return ParsedType::make(Context.getDependentNameType(Kwd, NNS, Name));
+ QualType Result = Context.getDependentNameType(Kwd, NNS, Name);
+
+ // Create type-source location information for this type.
+ TypeLocBuilder TLB;
+ DependentNameTypeLoc TL = TLB.push<DependentNameTypeLoc>(Result);
+ TL.setKeywordLoc(TagLoc);
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ TL.setNameLoc(NameLoc);
+ return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
TypeResult
Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
const CXXScopeSpec &SS, const IdentifierInfo &II,
SourceLocation IdLoc) {
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- if (!NNS)
+ if (SS.isInvalid())
return true;
-
+
if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() &&
!getLangOptions().CPlusPlus0x)
Diag(TypenameLoc, diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
- QualType T = CheckTypenameType(ETK_Typename, NNS, II,
- TypenameLoc, SS.getRange(), IdLoc);
+ NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
+ QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None,
+ TypenameLoc, QualifierLoc, II, IdLoc);
if (T.isNull())
return true;
@@ -5910,12 +6079,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
if (isa<DependentNameType>(T)) {
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
TL.setKeywordLoc(TypenameLoc);
- TL.setQualifierRange(SS.getRange());
+ TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(IdLoc);
} else {
ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
TL.setKeywordLoc(TypenameLoc);
- TL.setQualifierRange(SS.getRange());
+ TL.setQualifierLoc(QualifierLoc);
cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(IdLoc);
}
@@ -5923,91 +6092,94 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
}
TypeResult
-Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS, SourceLocation TemplateLoc,
- ParsedType Ty) {
+Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc,
+ TemplateTy TemplateIn,
+ SourceLocation TemplateNameLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation RAngleLoc) {
if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() &&
!getLangOptions().CPlusPlus0x)
Diag(TypenameLoc, diag::ext_typename_outside_of_template)
- << FixItHint::CreateRemoval(TypenameLoc);
-
- TypeSourceInfo *InnerTSI = 0;
- QualType T = GetTypeFromParser(Ty, &InnerTSI);
-
- assert(isa<TemplateSpecializationType>(T) &&
- "Expected a template specialization type");
-
- if (computeDeclContext(SS, false)) {
- // If we can compute a declaration context, then the "typename"
- // keyword was superfluous. Just build an ElaboratedType to keep
- // track of the nested-name-specifier.
-
- // Push the inner type, preserving its source locations if possible.
+ << FixItHint::CreateRemoval(TypenameLoc);
+
+ // Translate the parser's template argument list in our AST format.
+ TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
+ translateTemplateArguments(TemplateArgsIn, TemplateArgs);
+
+ TemplateName Template = TemplateIn.get();
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
+ // Construct a dependent template specialization type.
+ assert(DTN && "dependent template has non-dependent name?");
+ assert(DTN->getQualifier()
+ == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
+ QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename,
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ TemplateArgs);
+
+ // Create source-location information for this type.
TypeLocBuilder Builder;
- if (InnerTSI)
- Builder.pushFullCopy(InnerTSI->getTypeLoc());
- else
- Builder.push<TemplateSpecializationTypeLoc>(T).initialize(Context,
- TemplateLoc);
-
- /* Note: NNS already embedded in template specialization type T. */
- T = Context.getElaboratedType(ETK_Typename, /*NNS=*/0, T);
- ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T);
- TL.setKeywordLoc(TypenameLoc);
- TL.setQualifierRange(SS.getRange());
-
- TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T);
- return CreateParsedType(T, TSI);
- }
-
- // TODO: it's really silly that we make a template specialization
- // type earlier only to drop it again here.
- const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
- DependentTemplateName *DTN =
- TST->getTemplateName().getAsDependentTemplateName();
- assert(DTN && "dependent template has non-dependent name?");
- assert(DTN->getQualifier()
- == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
- T = Context.getDependentTemplateSpecializationType(ETK_Typename,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TST->getNumArgs(),
- TST->getArgs());
- TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
- DependentTemplateSpecializationTypeLoc TL =
- cast<DependentTemplateSpecializationTypeLoc>(TSI->getTypeLoc());
- if (InnerTSI) {
- TemplateSpecializationTypeLoc TSTL =
- cast<TemplateSpecializationTypeLoc>(InnerTSI->getTypeLoc());
- TL.setLAngleLoc(TSTL.getLAngleLoc());
- TL.setRAngleLoc(TSTL.getRAngleLoc());
- for (unsigned I = 0, E = TST->getNumArgs(); I != E; ++I)
- TL.setArgLocInfo(I, TSTL.getArgLocInfo(I));
- } else {
- // FIXME: Poor source-location information here.
- TL.initializeLocal(Context, TemplateLoc);
+ DependentTemplateSpecializationTypeLoc SpecTL
+ = Builder.push<DependentTemplateSpecializationTypeLoc>(T);
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ SpecTL.setKeywordLoc(TypenameLoc);
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ SpecTL.setNameLoc(TemplateNameLoc);
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
+ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
+
+ QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
+ if (T.isNull())
+ return true;
+
+ // Provide source-location information for the template specialization
+ // type.
+ TypeLocBuilder Builder;
+ TemplateSpecializationTypeLoc SpecTL
+ = Builder.push<TemplateSpecializationTypeLoc>(T);
+
+ // FIXME: No place to set the location of the 'template' keyword!
+ SpecTL.setLAngleLoc(LAngleLoc);
+ SpecTL.setRAngleLoc(RAngleLoc);
+ SpecTL.setTemplateNameLoc(TemplateNameLoc);
+ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+ SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
+
+ T = Context.getElaboratedType(ETK_Typename, SS.getScopeRep(), T);
+ ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T);
TL.setKeywordLoc(TypenameLoc);
- TL.setQualifierRange(SS.getRange());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+
+ TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T);
return CreateParsedType(T, TSI);
}
+
/// \brief Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType
-Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS, const IdentifierInfo &II,
- SourceLocation KeywordLoc, SourceRange NNSRange,
+Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ SourceLocation KeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ const IdentifierInfo &II,
SourceLocation IILoc) {
CXXScopeSpec SS;
- SS.MakeTrivial(Context, NNS, NNSRange);
+ SS.Adopt(QualifierLoc);
DeclContext *Ctx = computeDeclContext(SS);
if (!Ctx) {
// If the nested-name-specifier is dependent and couldn't be
// resolved to a type, build a typename type.
- assert(NNS->isDependent());
- return Context.getDependentNameType(Keyword, NNS, &II);
+ assert(QualifierLoc.getNestedNameSpecifier()->isDependent());
+ return Context.getDependentNameType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ &II);
}
// If the nested-name-specifier refers to the current instantiation,
@@ -6032,7 +6204,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
case LookupResult::FoundUnresolvedValue: {
// We found a using declaration that is a value. Most likely, the using
// declaration itself is meant to have the 'typename' keyword.
- SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(),
+ SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(),
IILoc);
Diag(IILoc, diag::err_typename_refers_to_using_value_decl)
<< Name << Ctx << FullRange;
@@ -6048,13 +6220,16 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
- return Context.getDependentNameType(Keyword, NNS, &II);
+ return Context.getDependentNameType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
// We found a type. Build an ElaboratedType, since the
// typename-specifier was just sugar.
- return Context.getElaboratedType(ETK_Typename, NNS,
+ return Context.getElaboratedType(ETK_Typename,
+ QualifierLoc.getNestedNameSpecifier(),
Context.getTypeDeclType(Type));
}
@@ -6077,7 +6252,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// If we get here, it's because name lookup did not find a
// type. Emit an appropriate diagnostic and return an error.
- SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(),
+ SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(),
IILoc);
Diag(IILoc, DiagID) << FullRange << Name << Ctx;
if (Referenced)
@@ -6225,3 +6400,24 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
Out << ']';
return Out.str();
}
+
+void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag) {
+ if (!FD)
+ return;
+ FD->setLateTemplateParsed(Flag);
+}
+
+bool Sema::IsInsideALocalClassWithinATemplateFunction() {
+ DeclContext *DC = CurContext;
+
+ while (DC) {
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) {
+ const FunctionDecl *FD = RD->isLocalClass();
+ return (FD && FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate);
+ } else if (DC->isTranslationUnit() || DC->isNamespace())
+ return false;
+
+ DC = DC->getParent();
+ }
+ return false;
+}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 139fafb346f9..235af049cf84 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -800,6 +800,32 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_Success;
}
+/// \brief Determine whether the parameter has qualifiers that are either
+/// inconsistent with or a superset of the argument's qualifiers.
+static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
+ QualType ArgType) {
+ Qualifiers ParamQs = ParamType.getQualifiers();
+ Qualifiers ArgQs = ArgType.getQualifiers();
+
+ if (ParamQs == ArgQs)
+ return false;
+
+ // Mismatched (but not missing) Objective-C GC attributes.
+ if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() &&
+ ParamQs.hasObjCGCAttr())
+ return true;
+
+ // Mismatched (but not missing) address spaces.
+ if (ParamQs.getAddressSpace() != ArgQs.getAddressSpace() &&
+ ParamQs.hasAddressSpace())
+ return true;
+
+ // CVR qualifier superset.
+ return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) &&
+ ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers())
+ == ParamQs.getCVRQualifiers());
+}
+
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@@ -875,9 +901,12 @@ DeduceTemplateArguments(Sema &S,
Comparison.ParamIsRvalueRef = ParamRef->getAs<RValueReferenceType>();
Comparison.ArgIsRvalueRef = ArgRef->getAs<RValueReferenceType>();
Comparison.Qualifiers = NeitherMoreQualified;
- if (Param.isMoreQualifiedThan(Arg))
+
+ Qualifiers ParamQuals = Param.getQualifiers();
+ Qualifiers ArgQuals = Arg.getQualifiers();
+ if (ParamQuals.isStrictSupersetOf(ArgQuals))
Comparison.Qualifiers = ParamMoreQualified;
- else if (Arg.isMoreQualifiedThan(Param))
+ else if (ArgQuals.isStrictSupersetOf(ParamQuals))
Comparison.Qualifiers = ArgMoreQualified;
RefParamComparisons->push_back(Comparison);
}
@@ -949,7 +978,6 @@ DeduceTemplateArguments(Sema &S,
// If the argument type is an array type, move the qualifiers up to the
// top level, so they can be matched with the qualifiers on the parameter.
- // FIXME: address spaces, ObjC GC qualifiers
if (isa<ArrayType>(Arg)) {
Qualifiers Quals;
Arg = S.Context.getUnqualifiedArrayType(Arg, Quals);
@@ -961,7 +989,8 @@ DeduceTemplateArguments(Sema &S,
// The argument type can not be less qualified than the parameter
// type.
- if (Param.isMoreQualifiedThan(Arg) && !(TDF & TDF_IgnoreQualifiers)) {
+ if (!(TDF & TDF_IgnoreQualifiers) &&
+ hasInconsistentOrSupersetQualifiersOf(Param, Arg)) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = TemplateArgument(Param);
Info.SecondArg = TemplateArgument(Arg);
@@ -972,8 +1001,18 @@ DeduceTemplateArguments(Sema &S,
assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function");
QualType DeducedType = Arg;
- // local manipulation is okay because it's canonical
- DeducedType.removeLocalCVRQualifiers(Param.getCVRQualifiers());
+ // Remove any qualifiers on the parameter from the deduced type.
+ // We checked the qualifiers for consistency above.
+ Qualifiers DeducedQs = DeducedType.getQualifiers();
+ Qualifiers ParamQs = Param.getQualifiers();
+ DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers());
+ if (ParamQs.hasObjCGCAttr())
+ DeducedQs.removeObjCGCAttr();
+ if (ParamQs.hasAddressSpace())
+ DeducedQs.removeAddressSpace();
+ DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(),
+ DeducedQs);
+
if (RecanonicalizeArg)
DeducedType = S.Context.getCanonicalType(DeducedType);
@@ -1006,7 +1045,7 @@ DeduceTemplateArguments(Sema &S,
// Check the cv-qualifiers on the parameter and argument types.
if (!(TDF & TDF_IgnoreQualifiers)) {
if (TDF & TDF_ParamWithReferenceType) {
- if (Param.isMoreQualifiedThan(Arg))
+ if (hasInconsistentOrSupersetQualifiersOf(Param, Arg))
return Sema::TDK_NonDeducedMismatch;
} else if (!IsPossiblyOpaquelyQualifiedType(Param)) {
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
@@ -1728,11 +1767,24 @@ getTrivialTemplateArgumentLoc(Sema &S,
return TemplateArgumentLoc(TemplateArgument(E), E);
}
- case TemplateArgument::Template:
- return TemplateArgumentLoc(Arg, SourceRange(), Loc);
-
- case TemplateArgument::TemplateExpansion:
- return TemplateArgumentLoc(Arg, SourceRange(), Loc, Loc);
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion: {
+ NestedNameSpecifierLocBuilder Builder;
+ TemplateName Template = Arg.getAsTemplate();
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
+ Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc);
+ else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc);
+
+ if (Arg.getKind() == TemplateArgument::Template)
+ return TemplateArgumentLoc(Arg,
+ Builder.getWithLocInContext(S.Context),
+ Loc);
+
+
+ return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.Context),
+ Loc, Loc);
+ }
case TemplateArgument::Expression:
return TemplateArgumentLoc(Arg, Arg.getAsExpr());
@@ -1996,7 +2048,7 @@ static bool isSimpleTemplateIdType(QualType T) {
Sema::TemplateDeductionResult
Sema::SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo &ExplicitTemplateArgs,
+ TemplateArgumentListInfo &ExplicitTemplateArgs,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
@@ -2442,8 +2494,8 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
// C++0x [temp.deduct.call]p3:
// If P is a cv-qualified type, the top level cv-qualifiers of P's type
// are ignored for type deduction.
- if (ParamType.getCVRQualifiers())
- ParamType = ParamType.getLocalUnqualifiedType();
+ if (ParamType.hasQualifiers())
+ ParamType = ParamType.getUnqualifiedType();
const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>();
if (ParamRefType) {
QualType PointeeType = ParamRefType->getPointeeType();
@@ -2499,8 +2551,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
else {
// - If A is a cv-qualified type, the top level cv-qualifiers of A's
// type are ignored for type deduction.
- if (ArgType.getCVRQualifiers())
- ArgType = ArgType.getUnqualifiedType();
+ ArgType = ArgType.getUnqualifiedType();
}
}
@@ -2563,7 +2614,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
@@ -2761,7 +2812,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
@@ -2832,18 +2883,18 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType P = Context.getCanonicalType(FromType);
QualType A = Context.getCanonicalType(ToType);
- // C++0x [temp.deduct.conv]p3:
+ // C++0x [temp.deduct.conv]p2:
// If P is a reference type, the type referred to by P is used for
// type deduction.
if (const ReferenceType *PRef = P->getAs<ReferenceType>())
P = PRef->getPointeeType();
- // C++0x [temp.deduct.conv]p3:
- // If A is a reference type, the type referred to by A is used
+ // C++0x [temp.deduct.conv]p4:
+ // [...] If A is a reference type, the type referred to by A is used
// for type deduction.
if (const ReferenceType *ARef = A->getAs<ReferenceType>())
- A = ARef->getPointeeType();
- // C++ [temp.deduct.conv]p2:
+ A = ARef->getPointeeType().getUnqualifiedType();
+ // C++ [temp.deduct.conv]p3:
//
// If A is not a reference type:
else {
@@ -2864,9 +2915,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
else
P = P.getUnqualifiedType();
- // C++0x [temp.deduct.conv]p3:
+ // C++0x [temp.deduct.conv]p4:
// If A is a cv-qualified type, the top level cv-qualifiers of A's
- // type are ignored for type deduction.
+ // type are ignored for type deduction. If A is a reference type, the type
+ // referred to by A is used for type deduction.
A = A.getUnqualifiedType();
}
@@ -2941,7 +2993,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
@@ -2989,11 +3041,14 @@ namespace {
///
/// \param Result if type deduction was successful, this will be set to the
/// deduced type. This may still contain undeduced autos if the type is
-/// dependent.
+/// dependent. This will be set to null if deduction succeeded, but auto
+/// substitution failed; the appropriate diagnostic will already have been
+/// produced in that case.
///
/// \returns true if deduction succeeded, false if it failed.
bool
-Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) {
+Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
+ TypeSourceInfo *&Result) {
if (Init->isTypeDependent()) {
Result = Type;
return true;
@@ -3004,14 +3059,18 @@ Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) {
LocalInstantiationScope InstScope(*this);
// Build template<class TemplParam> void Func(FuncParam);
- QualType TemplArg = Context.getTemplateTypeParmType(0, 0, false);
- TemplateTypeParmDecl TemplParam(0, Loc, 0, false, TemplArg, false);
- NamedDecl *TemplParamPtr = &TemplParam;
+ TemplateTypeParmDecl *TemplParam =
+ TemplateTypeParmDecl::Create(Context, 0, SourceLocation(), Loc, 0, 0, 0,
+ false, false);
+ QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
+ NamedDecl *TemplParamPtr = TemplParam;
FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr,
Loc);
- QualType FuncParam =
+ TypeSourceInfo *FuncParamInfo =
SubstituteAutoTransform(*this, TemplArg).TransformType(Type);
+ assert(FuncParamInfo && "substituting template parameter for 'auto' failed");
+ QualType FuncParam = FuncParamInfo->getType();
// Deduce type of TemplParam in Func(Init)
llvm::SmallVector<DeducedTemplateArgument, 1> Deduced;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index ae0ac9cbe35c..92ba095cd6c8 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -95,6 +95,12 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
assert(Function->getPrimaryTemplate() && "No function template?");
if (Function->getPrimaryTemplate()->isMemberSpecialization())
break;
+ } else if (FunctionTemplateDecl *FunTmpl
+ = Function->getDescribedFunctionTemplate()) {
+ // Add the "injected" template arguments.
+ std::pair<const TemplateArgument *, unsigned>
+ Injected = FunTmpl->getInjectedTemplateArgs();
+ Result.addOuterTemplateArguments(Injected.first, Injected.second);
}
// If this is a friend declaration and it declares an entity at
@@ -718,8 +724,9 @@ namespace {
/// as an instantiated local.
VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
TypeSourceInfo *Declarator,
- IdentifierInfo *Name,
- SourceLocation Loc);
+ SourceLocation StartLoc,
+ SourceLocation NameLoc,
+ IdentifierInfo *Name);
/// \brief Rebuild the Objective-C exception declaration and register the
/// declaration as an instantiated local.
@@ -730,9 +737,12 @@ namespace {
/// elaborated type.
QualType RebuildElaboratedType(SourceLocation KeywordLoc,
ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS, QualType T);
+ NestedNameSpecifierLoc QualifierLoc,
+ QualType T);
- TemplateName TransformTemplateName(TemplateName Name,
+ TemplateName TransformTemplateName(CXXScopeSpec &SS,
+ TemplateName Name,
+ SourceLocation NameLoc,
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = 0);
@@ -747,6 +757,7 @@ namespace {
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL);
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
+ int indexAdjustment,
llvm::Optional<unsigned> NumExpansions);
/// \brief Transforms a template type parameter type by performing
@@ -871,10 +882,11 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
VarDecl *
TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl,
TypeSourceInfo *Declarator,
- IdentifierInfo *Name,
- SourceLocation Loc) {
+ SourceLocation StartLoc,
+ SourceLocation NameLoc,
+ IdentifierInfo *Name) {
VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, Declarator,
- Name, Loc);
+ StartLoc, NameLoc, Name);
if (Var)
getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
return Var;
@@ -892,7 +904,7 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
QualType
TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
+ NestedNameSpecifierLoc QualifierLoc,
QualType T) {
if (const TagType *TT = T->getAs<TagType>()) {
TagDecl* TD = TT->getDecl();
@@ -918,10 +930,13 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(KeywordLoc,
Keyword,
- NNS, T);
+ QualifierLoc,
+ T);
}
-TemplateName TemplateInstantiator::TransformTemplateName(TemplateName Name,
+TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
+ TemplateName Name,
+ SourceLocation NameLoc,
QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
if (TemplateTemplateParmDecl *TTP
@@ -955,24 +970,31 @@ TemplateName TemplateInstantiator::TransformTemplateName(TemplateName Name,
TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
+
+ // We don't ever want to substitute for a qualified template name, since
+ // the qualifier is handled separately. So, look through the qualified
+ // template name to its underlying declaration.
+ if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Template = TemplateName(QTN->getTemplateDecl());
+
return Template;
}
}
if (SubstTemplateTemplateParmPackStorage *SubstPack
- = Name.getAsSubstTemplateTemplateParmPack()) {
+ = Name.getAsSubstTemplateTemplateParmPack()) {
if (getSema().ArgumentPackSubstitutionIndex == -1)
return Name;
-
+
const TemplateArgument &ArgPack = SubstPack->getArgumentPack();
assert(getSema().ArgumentPackSubstitutionIndex < (int)ArgPack.pack_size() &&
"Pack substitution index out-of-range");
return ArgPack.pack_begin()[getSema().ArgumentPackSubstitutionIndex]
- .getAsTemplate();
+ .getAsTemplate();
}
- return inherited::TransformTemplateName(Name, ObjectType,
- FirstQualifierInScope);
+ return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
+ FirstQualifierInScope);
}
ExprResult
@@ -1153,8 +1175,9 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
ParmVarDecl *
TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
+ int indexAdjustment,
llvm::Optional<unsigned> NumExpansions) {
- return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs,
+ return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
NumExpansions);
}
@@ -1217,12 +1240,17 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
// the template parameter list of a member template inside the
// template we are instantiating). Create a new template type
// parameter with the template "level" reduced by one.
+ TemplateTypeParmDecl *NewTTPDecl = 0;
+ if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
+ NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
+ TransformDecl(TL.getNameLoc(), OldTTPDecl));
+
QualType Result
= getSema().Context.getTemplateTypeParmType(T->getDepth()
- TemplateArgs.getNumLevels(),
T->getIndex(),
T->isParameterPack(),
- T->getName());
+ NewTTPDecl);
TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
@@ -1396,6 +1424,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
+ int indexAdjustment,
llvm::Optional<unsigned> NumExpansions) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
@@ -1432,9 +1461,10 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
}
ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
- NewDI, NewDI->getType(),
- OldParm->getIdentifier(),
+ OldParm->getInnerLocStart(),
OldParm->getLocation(),
+ OldParm->getIdentifier(),
+ NewDI->getType(), NewDI,
OldParm->getStorageClass(),
OldParm->getStorageClassAsWritten());
if (!NewParm)
@@ -1465,6 +1495,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
// FIXME: OldParm may come from a FunctionProtoType, in which case CurContext
// can be anything, is this right ?
NewParm->setDeclContext(CurContext);
+
+ NewParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
+ OldParm->getFunctionScopeIndex() + indexAdjustment);
return NewParm;
}
@@ -1508,6 +1541,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
}
SourceLocation EllipsisLoc;
+ TypeSourceInfo *BaseTypeLoc;
if (Base->isPackExpansion()) {
// This is a pack expansion. See whether we should expand it now, or
// wait until later.
@@ -1558,13 +1592,18 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
// The resulting base specifier will (still) be a pack expansion.
EllipsisLoc = Base->getEllipsisLoc();
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1);
+ BaseTypeLoc = SubstType(Base->getTypeSourceInfo(),
+ TemplateArgs,
+ Base->getSourceRange().getBegin(),
+ DeclarationName());
+ } else {
+ BaseTypeLoc = SubstType(Base->getTypeSourceInfo(),
+ TemplateArgs,
+ Base->getSourceRange().getBegin(),
+ DeclarationName());
}
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1);
- TypeSourceInfo *BaseTypeLoc = SubstType(Base->getTypeSourceInfo(),
- TemplateArgs,
- Base->getSourceRange().getBegin(),
- DeclarationName());
if (!BaseTypeLoc) {
Invalid = true;
continue;
@@ -1622,9 +1661,18 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
- if (!PatternDef) {
- if (!Complain) {
+ if (!PatternDef || PatternDef->isBeingDefined()) {
+ if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
// Say nothing
+ } else if (PatternDef) {
+ assert(PatternDef->isBeingDefined());
+ Diag(PointOfInstantiation,
+ diag::err_template_instantiate_within_definition)
+ << (TSK != TSK_ImplicitInstantiation)
+ << Context.getTypeDeclType(Instantiation);
+ // Not much point in noting the template declaration here, since
+ // we're lexically inside it.
+ Instantiation->setInvalidDecl();
} else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
Diag(PointOfInstantiation,
diag::err_implicit_instantiate_member_undefined)
@@ -2130,16 +2178,6 @@ bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
return Instantiator.TransformExprs(Exprs, NumExprs, IsCall, Outputs);
}
-/// \brief Do template substitution on a nested-name-specifier.
-NestedNameSpecifier *
-Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
- SourceRange Range,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
- TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(),
- DeclarationName());
- return Instantiator.TransformNestedNameSpecifier(NNS, Range);
-}
-
NestedNameSpecifierLoc
Sema::SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
const MultiLevelTemplateArgumentList &TemplateArgs) {
@@ -2161,11 +2199,14 @@ Sema::SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
}
TemplateName
-Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc,
+Sema::SubstTemplateName(NestedNameSpecifierLoc QualifierLoc,
+ TemplateName Name, SourceLocation Loc,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
DeclarationName());
- return Instantiator.TransformTemplateName(Name);
+ CXXScopeSpec SS;
+ SS.Adopt(QualifierLoc);
+ return Instantiator.TransformTemplateName(SS, Name, Loc);
}
bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs,
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3a40b6fd77a7..6e11ef5bbc5f 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -128,7 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
return Inst;
}
-Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
+Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
+ bool IsTypeAlias) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isDependentType() ||
@@ -144,9 +145,13 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
}
// Create the new typedef
- TypedefDecl *Typedef
- = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getIdentifier(), DI);
+ TypedefNameDecl *Typedef;
+ if (IsTypeAlias)
+ Typedef = TypeAliasDecl::Create(SemaRef.Context, Owner, D->getLocStart(),
+ D->getLocation(), D->getIdentifier(), DI);
+ else
+ Typedef = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocStart(),
+ D->getLocation(), D->getIdentifier(), DI);
if (Invalid)
Typedef->setInvalidDecl();
@@ -154,17 +159,20 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
// tag decl, re-establish that relationship for the new typedef.
if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) {
TagDecl *oldTag = oldTagType->getDecl();
- if (oldTag->getTypedefForAnonDecl() == D) {
+ if (oldTag->getTypedefNameForAnonDecl() == D) {
TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl();
- assert(!newTag->getIdentifier() && !newTag->getTypedefForAnonDecl());
- newTag->setTypedefForAnonDecl(Typedef);
+ assert(!newTag->getIdentifier() && !newTag->getTypedefNameForAnonDecl());
+ newTag->setTypedefNameForAnonDecl(Typedef);
}
}
- if (TypedefDecl *Prev = D->getPreviousDeclaration()) {
+ if (TypedefNameDecl *Prev = D->getPreviousDeclaration()) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
- Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
+ if (!InstPrev)
+ return 0;
+
+ Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev));
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
@@ -175,6 +183,14 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
return Typedef;
}
+Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
+ return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false);
+}
+
+Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true);
+}
+
/// \brief Instantiate an initializer, breaking it into separate
/// initialization arguments.
///
@@ -261,12 +277,14 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Build the instantiated declaration
VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
+ D->getInnerLocStart(),
D->getLocation(), D->getIdentifier(),
DI->getType(), DI,
D->getStorageClass(),
D->getStorageClassAsWritten());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
+ Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
@@ -280,8 +298,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setAccess(D->getAccess());
- if (!D->isStaticDataMember())
+ if (!D->isStaticDataMember()) {
Var->setUsed(D->isUsed(false));
+ Var->setReferenced(D->isReferenced());
+ }
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
@@ -346,7 +366,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
}
SemaRef.PopExpressionEvaluationContext();
- } else if (!Var->isStaticDataMember() || Var->isOutOfLine())
+ } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
+ !Var->isCXXForRangeDecl())
SemaRef.ActOnUninitializedDecl(Var, false);
// Diagnose unused local variables.
@@ -448,9 +469,14 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
int i = 0;
for (IndirectFieldDecl::chain_iterator PI =
D->chain_begin(), PE = D->chain_end();
- PI != PE; ++PI)
- NamedChain[i++] = (SemaRef.FindInstantiatedDecl(D->getLocation(),
- *PI, TemplateArgs));
+ PI != PE; ++PI) {
+ NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI,
+ TemplateArgs);
+ if (!Next)
+ return 0;
+
+ NamedChain[i++] = Next;
+ }
QualType T = cast<FieldDecl>(NamedChain[i-1])->getType();
IndirectFieldDecl* IndirectField
@@ -469,10 +495,18 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
// Handle friend type expressions by simply substituting template
// parameters into the pattern type and checking the result.
if (TypeSourceInfo *Ty = D->getFriendType()) {
- TypeSourceInfo *InstTy =
- SemaRef.SubstType(Ty, TemplateArgs,
- D->getLocation(), DeclarationName());
- if (!InstTy)
+ TypeSourceInfo *InstTy;
+ // If this is an unsupported friend, don't bother substituting template
+ // arguments into it. The actual type referred to won't be used by any
+ // parts of Clang, and may not be valid for instantiating. Just use the
+ // same info for the instantiated friend.
+ if (D->isUnsupportedFriend()) {
+ InstTy = Ty;
+ } else {
+ InstTy = SemaRef.SubstType(Ty, TemplateArgs,
+ D->getLocation(), DeclarationName());
+ }
+ if (!InstTy)
return 0;
FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy);
@@ -519,13 +553,13 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
D->getMessage();
return SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
InstantiatedAssertExpr.get(),
- Message.get());
+ Message.get(),
+ D->getRParenLoc());
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
- EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
+ EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, D->getLocStart(),
D->getLocation(), D->getIdentifier(),
- D->getTagKeywordLoc(),
/*PrevDecl=*/0, D->isScoped(),
D->isScopedUsingClassTag(), D->isFixed());
if (D->isFixed()) {
@@ -750,8 +784,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
CXXRecordDecl *RecordInst
= CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC,
- Pattern->getLocation(), Pattern->getIdentifier(),
- Pattern->getTagKeywordLoc(), PrevDecl,
+ Pattern->getLocStart(), Pattern->getLocation(),
+ Pattern->getIdentifier(), PrevDecl,
/*DelayTypeCreation=*/true);
if (QualifierLoc)
@@ -892,8 +926,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *Record
= CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
- D->getLocation(), D->getIdentifier(),
- D->getTagKeywordLoc(), PrevDecl);
+ D->getLocStart(), D->getLocation(),
+ D->getIdentifier(), PrevDecl);
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Record))
@@ -991,8 +1025,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
FunctionDecl *Function =
- FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
- D->getDeclName(), T, TInfo,
+ FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
+ D->getLocation(), D->getDeclName(), T, TInfo,
D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype());
@@ -1288,30 +1322,33 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = 0;
+ SourceLocation StartLoc = D->getInnerLocStart();
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
- NameInfo, T, TInfo,
+ StartLoc, NameInfo, T, TInfo,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
false);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
- NameInfo, T, TInfo,
+ StartLoc, NameInfo, T, TInfo,
Destructor->isInlineSpecified(),
false);
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(SemaRef.Context, Record,
- NameInfo, T, TInfo,
+ StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(),
- Conversion->isExplicit());
+ Conversion->isExplicit(),
+ Conversion->getLocEnd());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record,
- NameInfo, T, TInfo,
+ StartLoc, NameInfo, T, TInfo,
D->isStatic(),
D->getStorageClassAsWritten(),
- D->isInlineSpecified());
+ D->isInlineSpecified(),
+ D->getLocEnd());
}
if (QualifierLoc)
@@ -1431,23 +1468,24 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- return SemaRef.SubstParmVarDecl(D, TemplateArgs, llvm::Optional<unsigned>());
+ return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0,
+ llvm::Optional<unsigned>());
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
TemplateTypeParmDecl *D) {
// TODO: don't always clone when decls are refcounted.
- const Type* T = D->getTypeForDecl();
- assert(T->isTemplateTypeParmType());
- const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>();
+ assert(D->getTypeForDecl()->isTemplateTypeParmType());
TemplateTypeParmDecl *Inst =
- TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- TTPT->getDepth() - TemplateArgs.getNumLevels(),
- TTPT->getIndex(), D->getIdentifier(),
+ TemplateTypeParmDecl::Create(SemaRef.Context, Owner,
+ D->getLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumLevels(),
+ D->getIndex(), D->getIdentifier(),
D->wasDeclaredWithTypename(),
D->isParameterPack());
-
+ Inst->setAccess(AS_public);
+
if (D->hasDefaultArgument())
Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
@@ -1567,7 +1605,6 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
return 0;
// Check that this type is acceptable for a non-type template parameter.
- bool Invalid = false;
T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(),
D->getLocation());
if (T.isNull()) {
@@ -1579,7 +1616,8 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
NonTypeTemplateParmDecl *Param;
if (IsExpandedParameterPack)
Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getLocation(),
+ D->getInnerLocStart(),
+ D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
D->getPosition(),
D->getIdentifier(), T,
@@ -1589,12 +1627,14 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
ExpandedParameterPackTypesAsWritten.data());
else
Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
+ D->getInnerLocStart(),
D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
D->getPosition(),
D->getIdentifier(), T,
D->isParameterPack(), DI);
+ Param->setAccess(AS_public);
if (Invalid)
Param->setInvalidDecl();
@@ -1628,6 +1668,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
D->getPosition(), D->isParameterPack(),
D->getIdentifier(), InstParams);
Param->setDefaultArgument(D->getDefaultArgument(), false);
+ Param->setAccess(AS_public);
// Introduce this template parameter's instantiation into the instantiation
// scope.
@@ -1719,9 +1760,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
I != E; ++I) {
UsingShadowDecl *Shadow = *I;
NamedDecl *InstTarget =
- cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getLocation(),
- Shadow->getTargetDecl(),
- TemplateArgs));
+ cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
+ Shadow->getLocation(),
+ Shadow->getTargetDecl(),
+ TemplateArgs));
+ if (!InstTarget)
+ return 0;
if (CheckRedeclaration &&
SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev))
@@ -1936,7 +1980,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
= ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context,
PartialSpec->getTagKind(),
Owner,
- PartialSpec->getLocation(),
+ PartialSpec->getLocStart(),
+ PartialSpec->getLocation(),
InstParams,
ClassTemplate,
Converted.data(),
@@ -2063,8 +2108,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
const FunctionProtoType *Proto = Tmpl->getType()->getAs<FunctionProtoType>();
assert(Proto && "Function template without prototype?");
- if (Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec() ||
- Proto->getNoReturnAttr()) {
+ if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
// The function has an exception specification or a "noreturn"
// attribute. Substitute into each of the exception types.
llvm::SmallVector<QualType, 4> Exceptions;
@@ -2078,7 +2122,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Unexpanded);
assert(!Unexpanded.empty() &&
"Pack expansion without parameter packs?");
-
+
bool Expand = false;
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions
@@ -2092,7 +2136,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
RetainExpansion,
NumExpansions))
break;
-
+
if (!Expand) {
// We can't expand this pack expansion into separate arguments yet;
// just substitute into the pattern and create a new pack expansion
@@ -2108,7 +2152,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Exceptions.push_back(T);
continue;
}
-
+
// Substitute into the pack expansion pattern for each template
bool Invalid = false;
for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
@@ -2121,13 +2165,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Invalid = true;
break;
}
-
+
Exceptions.push_back(T);
}
-
+
if (Invalid)
break;
-
+
continue;
}
@@ -2140,14 +2184,20 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Exceptions.push_back(T);
}
+ Expr *NoexceptExpr = 0;
+ if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
+ ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
+ if (E.isUsable())
+ NoexceptExpr = E.take();
+ }
// Rebuild the function type
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
- EPI.HasExceptionSpec = Proto->hasExceptionSpec();
- EPI.HasAnyExceptionSpec = Proto->hasAnyExceptionSpec();
+ EPI.ExceptionSpecType = Proto->getExceptionSpecType();
EPI.NumExceptions = Exceptions.size();
EPI.Exceptions = Exceptions.data();
+ EPI.NoexceptExpr = NoexceptExpr;
EPI.ExtInfo = Proto->getExtInfo();
const FunctionProtoType *NewProto
@@ -2218,6 +2268,21 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (PatternDecl)
Pattern = PatternDecl->getBody(PatternDecl);
+ // Postpone late parsed template instantiations.
+ if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) {
+ PendingInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
+ return;
+ }
+
+ // Call the LateTemplateParser callback if there a need to late parse
+ // a templated function definition.
+ if (!Pattern && PatternDecl && PatternDecl->isLateTemplateParsed() &&
+ LateTemplateParser) {
+ LateTemplateParser(OpaqueParser, PatternDecl);
+ Pattern = PatternDecl->getBody(PatternDecl);
+ }
+
if (!Pattern) {
if (DefinitionRequired) {
if (Function->getPrimaryTemplate())
@@ -2573,10 +2638,15 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
New->getParent(),
EllipsisLoc);
} else if (Init->isMemberInitializer()) {
- FieldDecl *Member = cast<FieldDecl>(FindInstantiatedDecl(
+ FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
Init->getMember(),
TemplateArgs));
+ if (!Member) {
+ AnyErrors = true;
+ New->setInvalidDecl();
+ continue;
+ }
NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
NewArgs.size(),
@@ -2585,10 +2655,16 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
Init->getRParenLoc());
} else if (Init->isIndirectMemberInitializer()) {
IndirectFieldDecl *IndirectMember =
- cast<IndirectFieldDecl>(FindInstantiatedDecl(
+ cast_or_null<IndirectFieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
Init->getIndirectMember(), TemplateArgs));
+ if (!IndirectMember) {
+ AnyErrors = true;
+ New->setInvalidDecl();
+ continue;
+ }
+
NewInit = BuildMemberInitializer(IndirectMember, (Expr **)NewArgs.data(),
NewArgs.size(),
Init->getSourceLocation(),
@@ -2917,7 +2993,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// FIXME: Can we use the CurrentInstantiationScope to avoid this
// extra instantiation in the common case?
- T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
+ T = SubstType(T, TemplateArgs, Loc, DeclarationName());
assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
if (!T->isDependentType()) {
@@ -2974,11 +3050,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// If our context used to be dependent, we may need to instantiate
// it before performing lookup into that context.
+ bool IsBeingInstantiated = false;
if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
if (!Spec->isDependentContext()) {
QualType T = Context.getTypeDeclType(Spec);
const RecordType *Tag = T->getAs<RecordType>();
assert(Tag && "type of non-dependent record is not a RecordType");
+ if (Tag->isBeingDefined())
+ IsBeingInstantiated = true;
if (!Tag->isBeingDefined() &&
RequireCompleteType(Loc, T, diag::err_incomplete_type))
return 0;
@@ -3005,11 +3084,29 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
ParentDC->decls_end());
}
- // UsingShadowDecls can instantiate to nothing because of using hiding.
- assert((Result || isa<UsingShadowDecl>(D) || D->isInvalidDecl() ||
- cast<Decl>(ParentDC)->isInvalidDecl())
- && "Unable to find instantiation of declaration!");
-
+ if (!Result) {
+ if (isa<UsingShadowDecl>(D)) {
+ // UsingShadowDecls can instantiate to nothing because of using hiding.
+ } else if (Diags.hasErrorOccurred()) {
+ // We've already complained about something, so most likely this
+ // declaration failed to instantiate. There's no point in complaining
+ // further, since this is normal in invalid code.
+ } else if (IsBeingInstantiated) {
+ // The class in which this member exists is currently being
+ // instantiated, and we haven't gotten around to instantiating this
+ // member yet. This can happen when the code uses forward declarations
+ // of member classes, and introduces ordering dependencies via
+ // template instantiation.
+ Diag(Loc, diag::err_member_not_yet_instantiated)
+ << D->getDeclName()
+ << Context.getTypeDeclType(cast<CXXRecordDecl>(ParentDC));
+ Diag(D->getLocation(), diag::note_non_instantiated_member_here);
+ } else {
+ // We should have found something, but didn't.
+ llvm_unreachable("Unable to find instantiation of declaration!");
+ }
+ }
+
D = Result;
}
@@ -3018,7 +3115,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
-void Sema::PerformPendingInstantiations(bool LocalOnly) {
+///
+/// \returns true if anything was instantiated.
+bool Sema::PerformPendingInstantiations(bool LocalOnly) {
+ bool InstantiatedAnything = false;
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingInstantiations.empty())) {
PendingImplicitInstantiation Inst;
@@ -3039,6 +3139,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired);
+ InstantiatedAnything = true;
continue;
}
@@ -3075,7 +3176,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
DefinitionRequired);
+ InstantiatedAnything = true;
}
+
+ return InstantiatedAnything;
}
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 0da801c7e343..096d353bccc3 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -167,7 +167,7 @@ DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc,
IdentifierInfo *Name = 0;
if (const TemplateTypeParmType *TTP
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
- Name = TTP->getName();
+ Name = TTP->getIdentifier();
else
Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
@@ -483,7 +483,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
- Name = TTP->getName();
+ Name = TTP->getIdentifier();
} else {
NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
if (isa<ParmVarDecl>(ND))
@@ -649,6 +649,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_struct:
case TST_class:
case TST_auto:
+ case TST_unknown_anytype:
case TST_error:
break;
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ba80076003c9..00ac1d63dbe7 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
+#include "clang/Basic/OpenCL.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
@@ -22,6 +23,7 @@
#include "clang/AST/Expr.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
@@ -70,6 +72,40 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
return false;
}
+/// diagnoseBadTypeAttribute - Diagnoses a type attribute which
+/// doesn't apply to the given type.
+static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
+ QualType type) {
+ bool useInstantiationLoc = false;
+
+ unsigned diagID = 0;
+ switch (attr.getKind()) {
+ case AttributeList::AT_objc_gc:
+ diagID = diag::warn_pointer_attribute_wrong_type;
+ useInstantiationLoc = true;
+ break;
+
+ default:
+ // Assume everything else was a function attribute.
+ diagID = diag::warn_function_attribute_wrong_type;
+ break;
+ }
+
+ SourceLocation loc = attr.getLoc();
+ llvm::StringRef name = attr.getName()->getName();
+
+ // The GC attributes are usually written with macros; special-case them.
+ if (useInstantiationLoc && loc.isMacroID() && attr.getParameterName()) {
+ if (attr.getParameterName()->isStr("strong")) {
+ if (S.findMacroSpelling(loc, "__strong")) name = "__strong";
+ } else if (attr.getParameterName()->isStr("weak")) {
+ if (S.findMacroSpelling(loc, "__weak")) name = "__weak";
+ }
+ }
+
+ S.Diag(loc, diagID) << name << type;
+}
+
// objc_gc applies to Objective-C pointers or, otherwise, to the
// smallest available pointer type (i.e. 'void*' in 'void**').
#define OBJC_POINTER_TYPE_ATTRS_CASELIST \
@@ -83,7 +119,8 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
case AttributeList::AT_stdcall: \
case AttributeList::AT_thiscall: \
case AttributeList::AT_pascal: \
- case AttributeList::AT_regparm
+ case AttributeList::AT_regparm: \
+ case AttributeList::AT_pcs \
namespace {
/// An object which stores processing state for the entire
@@ -102,6 +139,9 @@ namespace {
/// Whether there are non-trivial modifications to the decl spec.
bool trivial;
+ /// Whether we saved the attributes in the decl spec.
+ bool hasSavedAttrs;
+
/// The original set of attributes on the DeclSpec.
llvm::SmallVector<AttributeList*, 2> savedAttrs;
@@ -113,7 +153,7 @@ namespace {
TypeProcessingState(Sema &sema, Declarator &declarator)
: sema(sema), declarator(declarator),
chunkIndex(declarator.getNumTypeObjects()),
- trivial(true) {}
+ trivial(true), hasSavedAttrs(false) {}
Sema &getSema() const {
return sema;
@@ -142,13 +182,14 @@ namespace {
/// Save the current set of attributes on the DeclSpec.
void saveDeclSpecAttrs() {
// Don't try to save them multiple times.
- if (!savedAttrs.empty()) return;
+ if (hasSavedAttrs) return;
DeclSpec &spec = getMutableDeclSpec();
for (AttributeList *attr = spec.getAttributes().getList(); attr;
attr = attr->getNext())
savedAttrs.push_back(attr);
trivial &= savedAttrs.empty();
+ hasSavedAttrs = true;
}
/// Record that we had nowhere to put the given type attribute.
@@ -162,11 +203,8 @@ namespace {
void diagnoseIgnoredTypeAttrs(QualType type) const {
for (llvm::SmallVectorImpl<AttributeList*>::const_iterator
i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end();
- i != e; ++i) {
- AttributeList &attr = **i;
- getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type)
- << attr.getName() << type;
- }
+ i != e; ++i)
+ diagnoseBadTypeAttribute(getSema(), **i, type);
}
~TypeProcessingState() {
@@ -181,7 +219,13 @@ namespace {
}
void restoreDeclSpecAttrs() {
- assert(!savedAttrs.empty());
+ assert(hasSavedAttrs);
+
+ if (savedAttrs.empty()) {
+ getMutableDeclSpec().getAttributes().set(0);
+ return;
+ }
+
getMutableDeclSpec().getAttributes().set(savedAttrs[0]);
for (unsigned i = 0, e = savedAttrs.size() - 1; i != e; ++i)
savedAttrs[i]->setNext(savedAttrs[i+1]);
@@ -287,9 +331,8 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state,
}
}
error:
-
- state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type)
- << attr.getName() << type;
+
+ diagnoseBadTypeAttribute(state.getSema(), attr, type);
}
/// Distribute an objc_gc type attribute that was written on the
@@ -328,8 +371,15 @@ distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state,
// That might actually be the decl spec if we weren't blocked by
// anything in the declarator.
if (considerDeclSpec) {
- if (handleObjCPointerTypeAttr(state, attr, declSpecType))
+ if (handleObjCPointerTypeAttr(state, attr, declSpecType)) {
+ // Splice the attribute into the decl spec. Prevents the
+ // attribute from being applied multiple times and gives
+ // the source-location-filler something to work with.
+ state.saveDeclSpecAttrs();
+ moveAttrFromListToList(attr, declarator.getAttrListRef(),
+ declarator.getMutableDeclSpec().getAttributes().getListRef());
return;
+ }
}
// Otherwise, if we found an appropriate chunk, splice the attribute
@@ -374,8 +424,7 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state,
}
}
- state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type)
- << attr.getName() << type;
+ diagnoseBadTypeAttribute(state.getSema(), attr, type);
}
/// Try to distribute a function type attribute to the innermost
@@ -505,13 +554,12 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
// ...and *prepend* it to the declarator.
declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
- ParsedAttributes(),
/*proto*/ true,
/*variadic*/ false, SourceLocation(),
/*args*/ 0, 0,
/*type quals*/ 0,
/*ref-qualifier*/true, SourceLocation(),
- /*EH*/ false, SourceLocation(), false, 0, 0, 0,
+ /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0,
/*parens*/ loc, loc,
declarator));
@@ -698,7 +746,7 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
}
// If the type is deprecated or unavailable, diagnose it.
- S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc());
+ S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeNameLoc());
assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!");
@@ -706,12 +754,11 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
// TypeQuals handled by caller.
Result = Context.getTypeDeclType(D);
- // In C++, make an ElaboratedType.
- if (S.getLangOptions().CPlusPlus) {
- ElaboratedTypeKeyword Keyword
- = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType());
- Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result);
- }
+ // In both C and C++, make an ElaboratedType.
+ ElaboratedTypeKeyword Keyword
+ = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType());
+ Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result);
+
if (D->isInvalidDecl())
declarator.setInvalidType(true);
break;
@@ -795,6 +842,10 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
break;
}
+ case DeclSpec::TST_unknown_anytype:
+ Result = Context.UnknownAnyTy;
+ break;
+
case DeclSpec::TST_error:
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -1108,8 +1159,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
// Do lvalue-to-rvalue conversions on the array size expression.
- if (ArraySize && !ArraySize->isRValue())
- DefaultLvalueConversion(ArraySize);
+ if (ArraySize && !ArraySize->isRValue()) {
+ ExprResult Result = DefaultLvalueConversion(ArraySize);
+ if (Result.isInvalid())
+ return QualType();
+
+ ArraySize = Result.take();
+ }
// C99 6.7.5.2p1: The size expression shall have integer type.
// TODO: in theory, if we were insane, we could allow contextual
@@ -1464,19 +1520,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
TypeProcessingState state(*this, D);
+ // In C++0x, deallocation functions (normal and array operator delete)
+ // are implicitly noexcept.
+ bool ImplicitlyNoexcept = false;
+
switch (D.getName().getKind()) {
- case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
+ if (getLangOptions().CPlusPlus0x) {
+ OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
+ if (OO == OO_Delete || OO == OO_Array_Delete)
+ ImplicitlyNoexcept = true;
+ }
+ // Intentional fall-through.
+ case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
T = ConvertDeclSpecToType(*this, state);
if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
- // Owned is embedded if it was defined here, or if it is the
- // very first (i.e., canonical) declaration of this tag type.
- Owned->setEmbeddedInDeclarator(Owned->isDefinition() ||
- Owned->isCanonicalDecl());
+ // Owned declaration is embedded in declarator.
+ Owned->setEmbeddedInDeclarator(true);
if (OwnedDecl) *OwnedDecl = Owned;
}
break;
@@ -1512,6 +1576,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::KNRTypeListContext:
assert(0 && "K&R type lists aren't allowed in C++");
break;
+ case Declarator::ObjCPrototypeContext:
case Declarator::PrototypeContext:
Error = 0; // Function prototype
break;
@@ -1535,9 +1600,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::TemplateTypeArgContext:
Error = 7; // Template type argument
break;
+ case Declarator::AliasDeclContext:
+ Error = 9; // Type alias
+ break;
case Declarator::TypeNameContext:
if (!AutoAllowedInTypeName)
- Error = 10; // Generic
+ Error = 11; // Generic
break;
case Declarator::FileContext:
case Declarator::BlockContext:
@@ -1551,7 +1619,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// In Objective-C it is an error to use 'auto' on a function declarator.
if (D.isFunctionDeclarator())
- Error = 9;
+ Error = 10;
// C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator
// contains a trailing return type. That is only legal at the outermost
@@ -1588,6 +1656,11 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getIdentifier())
Name = D.getIdentifier();
+ // Does this declaration declare a typedef-name?
+ bool IsTypedefName =
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef ||
+ D.getContext() == Declarator::AliasDeclContext;
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -1660,8 +1733,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
ASM = ArrayType::Static;
else
ASM = ArrayType::Normal;
- if (ASM == ArrayType::Star &&
- D.getContext() != Declarator::PrototypeContext) {
+ if (ASM == ArrayType::Star && !D.isPrototypeContext()) {
// FIXME: This check isn't quite right: it allows star in prototypes
// for function definitions, and disallows some edge cases detailed
// in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html
@@ -1728,7 +1800,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// cv-qualifiers on return types are pointless except when the type is a
// class type in C++.
- if (T->isPointerType() && T.getCVRQualifiers() &&
+ if (isa<PointerType>(T) && T.getLocalCVRQualifiers() &&
+ (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) &&
(!getLangOptions().CPlusPlus || !T->isDependentType())) {
assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?");
DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
@@ -1764,9 +1837,9 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Exception specs are not allowed in typedefs. Complain, but add it
// anyway.
- if (FTI.hasExceptionSpec &&
- D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- Diag(FTI.getThrowLoc(), diag::err_exception_spec_in_typedef);
+ if (IsTypedefName && FTI.getExceptionSpecType())
+ Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
+ << (D.getContext() == Declarator::AliasDeclContext);
if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
@@ -1845,9 +1918,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
} else if (!FTI.hasPrototype) {
if (ArgTy->isPromotableIntegerType()) {
ArgTy = Context.getPromotedIntegerType(ArgTy);
+ Param->setKNRPromoted(true);
} else if (const BuiltinType* BTy = ArgTy->getAs<BuiltinType>()) {
- if (BTy->getKind() == BuiltinType::Float)
+ if (BTy->getKind() == BuiltinType::Float) {
ArgTy = Context.DoubleTy;
+ Param->setKNRPromoted(true);
+ }
}
}
@@ -1855,9 +1931,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
llvm::SmallVector<QualType, 4> Exceptions;
- if (FTI.hasExceptionSpec) {
- EPI.HasExceptionSpec = FTI.hasExceptionSpec;
- EPI.HasAnyExceptionSpec = FTI.hasAnyExceptionSpec;
+ EPI.ExceptionSpecType = FTI.getExceptionSpecType();
+ if (FTI.getExceptionSpecType() == EST_Dynamic) {
Exceptions.reserve(FTI.NumExceptions);
for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) {
// FIXME: Preserve type source info.
@@ -1869,6 +1944,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
EPI.NumExceptions = Exceptions.size();
EPI.Exceptions = Exceptions.data();
+ } else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) {
+ // If an error occurred, there's no expression here.
+ if (Expr *NoexceptExpr = FTI.NoexceptExpr) {
+ assert((NoexceptExpr->isTypeDependent() ||
+ NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
+ Context.BoolTy) &&
+ "Parser should have made sure that the expression is boolean");
+ SourceLocation ErrLoc;
+ llvm::APSInt Dummy;
+ if (!NoexceptExpr->isValueDependent() &&
+ !NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc,
+ /*evaluated*/false))
+ Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
+ << NoexceptExpr->getSourceRange();
+ else
+ EPI.NoexceptExpr = NoexceptExpr;
+ }
+ } else 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);
@@ -1903,11 +1999,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
ClsType = QualType(NNS->getAsType(), 0);
- // Note: if NNS is dependent, then its prefix (if any) is already
- // included in ClsType; this does not hold if the NNS is
- // nondependent: in this case (if there is indeed a prefix)
- // ClsType needs to be wrapped into an elaborated type.
- if (NNSPrefix && !NNS->isDependent())
+ // Note: if the NNS has a prefix and ClsType is a nondependent
+ // TemplateSpecializationType, then the NNS prefix is NOT included
+ // in ClsType; hence we wrap ClsType into an ElaboratedType.
+ // NOTE: in particular, no wrap occurs if ClsType already is an
+ // Elaborated, DependentName, or DependentTemplateSpecialization.
+ if (NNSPrefix && isa<TemplateSpecializationType>(NNS->getAsType()))
ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType);
break;
}
@@ -1968,8 +2065,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// declaration.
if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) &&
!(D.getContext() == Declarator::TemplateTypeArgContext &&
- !D.isFunctionDeclarator()) &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ !D.isFunctionDeclarator()) && !IsTypedefName &&
(FreeFunction ||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
if (D.getContext() == Declarator::TemplateTypeArgContext) {
@@ -2053,8 +2149,10 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Diagnose any ignored type attributes.
if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T);
- // If there's a constexpr specifier, treat it as a top-level const.
- if (D.getDeclSpec().isConstexprSpecified()) {
+ // C++0x [dcl.constexpr]p9:
+ // A constexpr specifier used in an object declaration declares the object
+ // as const.
+ if (D.getDeclSpec().isConstexprSpecified() && T->isObjectType()) {
T.addConst();
}
@@ -2103,7 +2201,9 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::FileContext:
case Declarator::KNRTypeListContext:
+ case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
+ case Declarator::AliasDeclContext:
case Declarator::MemberContext:
case Declarator::BlockContext:
case Declarator::ForContext:
@@ -2126,6 +2226,62 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
return GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo);
}
+/// Map an AttributedType::Kind to an AttributeList::Kind.
+static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
+ switch (kind) {
+ case AttributedType::attr_address_space:
+ return AttributeList::AT_address_space;
+ case AttributedType::attr_regparm:
+ return AttributeList::AT_regparm;
+ case AttributedType::attr_vector_size:
+ return AttributeList::AT_vector_size;
+ case AttributedType::attr_neon_vector_type:
+ return AttributeList::AT_neon_vector_type;
+ case AttributedType::attr_neon_polyvector_type:
+ return AttributeList::AT_neon_polyvector_type;
+ case AttributedType::attr_objc_gc:
+ return AttributeList::AT_objc_gc;
+ case AttributedType::attr_noreturn:
+ return AttributeList::AT_noreturn;
+ case AttributedType::attr_cdecl:
+ return AttributeList::AT_cdecl;
+ case AttributedType::attr_fastcall:
+ return AttributeList::AT_fastcall;
+ case AttributedType::attr_stdcall:
+ return AttributeList::AT_stdcall;
+ case AttributedType::attr_thiscall:
+ return AttributeList::AT_thiscall;
+ case AttributedType::attr_pascal:
+ return AttributeList::AT_pascal;
+ case AttributedType::attr_pcs:
+ return AttributeList::AT_pcs;
+ }
+ llvm_unreachable("unexpected attribute kind!");
+ return AttributeList::Kind();
+}
+
+static void fillAttributedTypeLoc(AttributedTypeLoc TL,
+ const AttributeList *attrs) {
+ AttributedType::Kind kind = TL.getAttrKind();
+
+ assert(attrs && "no type attributes in the expected location!");
+ AttributeList::Kind parsedKind = getAttrListKind(kind);
+ while (attrs->getKind() != parsedKind) {
+ attrs = attrs->getNext();
+ assert(attrs && "no matching attribute in expected location!");
+ }
+
+ TL.setAttrNameLoc(attrs->getLoc());
+ if (TL.hasAttrExprOperand())
+ TL.setAttrExprOperand(attrs->getArg(0));
+ else if (TL.hasAttrEnumOperand())
+ TL.setAttrEnumOperandLoc(attrs->getParameterLoc());
+
+ // FIXME: preserve this information to here.
+ if (TL.hasAttrOperand())
+ TL.setAttrOperandParensRange(SourceRange());
+}
+
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
ASTContext &Context;
@@ -2135,6 +2291,10 @@ namespace {
TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS)
: Context(Context), DS(DS) {}
+ void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ fillAttributedTypeLoc(TL, DS.getAttributes().getList());
+ Visit(TL.getModifiedLoc());
+ }
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
Visit(TL.getUnqualifiedLoc());
}
@@ -2179,7 +2339,7 @@ namespace {
// If we got no declarator info from previous Sema routines,
// just fill with the typespec loc.
if (!TInfo) {
- TL.initialize(Context, DS.getTypeSpecTypeLoc());
+ TL.initialize(Context, DS.getTypeSpecTypeNameLoc());
return;
}
@@ -2237,7 +2397,7 @@ namespace {
? DS.getTypeSpecTypeLoc()
: SourceLocation());
const CXXScopeSpec& SS = DS.getTypeSpecScope();
- TL.setQualifierRange(SS.isEmpty() ? SourceRange(): SS.getRange());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
Visit(TL.getNextTypeLoc().getUnqualifiedLoc());
}
void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
@@ -2255,9 +2415,8 @@ namespace {
? DS.getTypeSpecTypeLoc()
: SourceLocation());
const CXXScopeSpec& SS = DS.getTypeSpecScope();
- TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange());
- // FIXME: load appropriate source location.
- TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
@@ -2277,9 +2436,11 @@ namespace {
? DS.getTypeSpecTypeLoc()
: SourceLocation());
const CXXScopeSpec& SS = DS.getTypeSpecScope();
- TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange());
- // FIXME: load appropriate source location.
- TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
+ }
+ void VisitTagTypeLoc(TagTypeLoc TL) {
+ TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
void VisitTypeLoc(TypeLoc TL) {
@@ -2289,10 +2450,12 @@ namespace {
};
class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> {
+ ASTContext &Context;
const DeclaratorChunk &Chunk;
public:
- DeclaratorLocFiller(const DeclaratorChunk &Chunk) : Chunk(Chunk) {}
+ DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk)
+ : Context(Context), Chunk(Chunk) {}
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
llvm_unreachable("qualified type locs not expected here!");
@@ -2312,8 +2475,48 @@ namespace {
}
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::MemberPointer);
+ const CXXScopeSpec& SS = Chunk.Mem.Scope();
+ NestedNameSpecifierLoc NNSLoc = SS.getWithLocInContext(Context);
+
+ const Type* ClsTy = TL.getClass();
+ QualType ClsQT = QualType(ClsTy, 0);
+ TypeSourceInfo *ClsTInfo = Context.CreateTypeSourceInfo(ClsQT, 0);
+ // Now copy source location info into the type loc component.
+ TypeLoc ClsTL = ClsTInfo->getTypeLoc();
+ switch (NNSLoc.getNestedNameSpecifier()->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ assert(isa<DependentNameType>(ClsTy) && "Unexpected TypeLoc");
+ {
+ DependentNameTypeLoc DNTLoc = cast<DependentNameTypeLoc>(ClsTL);
+ DNTLoc.setKeywordLoc(SourceLocation());
+ DNTLoc.setQualifierLoc(NNSLoc.getPrefix());
+ DNTLoc.setNameLoc(NNSLoc.getLocalBeginLoc());
+ }
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ if (isa<ElaboratedType>(ClsTy)) {
+ ElaboratedTypeLoc ETLoc = *cast<ElaboratedTypeLoc>(&ClsTL);
+ ETLoc.setKeywordLoc(SourceLocation());
+ ETLoc.setQualifierLoc(NNSLoc.getPrefix());
+ TypeLoc NamedTL = ETLoc.getNamedTypeLoc();
+ NamedTL.initializeFullCopy(NNSLoc.getTypeLoc());
+ } else {
+ ClsTL.initializeFullCopy(NNSLoc.getTypeLoc());
+ }
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ case NestedNameSpecifier::Global:
+ llvm_unreachable("Nested-name-specifier must name a type");
+ break;
+ }
+
+ // Finally fill in MemberPointerLocInfo fields.
TL.setStarLoc(Chunk.Loc);
- // FIXME: nested name specifier
+ TL.setClassTInfo(ClsTInfo);
}
void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::Reference);
@@ -2334,8 +2537,8 @@ namespace {
}
void VisitFunctionTypeLoc(FunctionTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::Function);
- TL.setLParenLoc(Chunk.Loc);
- TL.setRParenLoc(Chunk.EndLoc);
+ TL.setLocalRangeBegin(Chunk.Loc);
+ TL.setLocalRangeEnd(Chunk.EndLoc);
TL.setTrailingReturn(!!Chunk.Fun.TrailingReturnType);
const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun;
@@ -2378,7 +2581,13 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
- DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL);
+ while (isa<AttributedTypeLoc>(CurrTL)) {
+ AttributedTypeLoc TL = cast<AttributedTypeLoc>(CurrTL);
+ fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs());
+ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ }
+
+ DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
@@ -2434,7 +2643,8 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// A type-specifier-seq shall not define a class or enumeration
// unless it appears in the type-id of an alias-declaration
// (7.1.3).
- if (OwnedTag && OwnedTag->isDefinition())
+ if (OwnedTag && OwnedTag->isDefinition() &&
+ D.getContext() != Declarator::AliasDeclContext)
Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTypeDeclType(OwnedTag);
}
@@ -2547,7 +2757,14 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state,
return true;
}
- type = S.Context.getObjCGCQualType(type, GCAttr);
+ QualType origType = type;
+ type = S.Context.getObjCGCQualType(origType, GCAttr);
+
+ // Make an attributed type to preserve the source information.
+ if (attr.getLoc().isValid())
+ type = S.Context.getAttributedType(AttributedType::attr_objc_gc,
+ origType, type);
+
return true;
}
@@ -2775,7 +2992,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
}
// Also diagnose fastcall with regparm.
- if (fn->getRegParmType()) {
+ if (fn->getHasRegParm()) {
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< "regparm"
<< FunctionType::getNameForCallConv(CC);
@@ -2789,6 +3006,41 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
+/// Handle OpenCL image access qualifiers: read_only, write_only, read_write
+static void HandleOpenCLImageAccessAttribute(QualType& CurType,
+ const AttributeList &Attr,
+ Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
+ return;
+ }
+ Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt arg(32);
+ if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() ||
+ !sizeExpr->isIntegerConstantExpr(arg, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "opencl_image_access" << sizeExpr->getSourceRange();
+ Attr.setInvalid();
+ return;
+ }
+ unsigned iarg = static_cast<unsigned>(arg.getZExtValue());
+ switch (iarg) {
+ case CLIA_read_only:
+ case CLIA_write_only:
+ case CLIA_read_write:
+ // Implemented in a separate patch
+ break;
+ default:
+ // Implemented in a separate patch
+ S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
+ << sizeExpr->getSourceRange();
+ Attr.setInvalid();
+ break;
+ }
+}
+
/// HandleVectorSizeAttribute - this attribute is only applicable to integral
/// and float scalars, although arrays, pointers, and function return values are
/// allowed in conjunction with this construct. Aggregates with this attribute
@@ -2943,6 +3195,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
"neon_polyvector_type");
break;
+ case AttributeList::AT_opencl_image_access:
+ HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
+ break;
+
FUNCTION_TYPE_ATTRS_CASELIST:
// Never process function type attributes as part of the
// declaration-specifiers.
@@ -3088,7 +3344,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
}
QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
- ExprResult ER = CheckPlaceholderExpr(E, Loc);
+ ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
E = ER.take();
@@ -3101,7 +3357,7 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
}
QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
- ExprResult ER = CheckPlaceholderExpr(E, Loc);
+ ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
E = ER.take();
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index c3415cb847ab..ab697eeed53b 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -136,7 +136,7 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D,
if (VD && VD->getType()->isFunctionPointerType())
return;
// Also don't warn on function pointer typedefs.
- TypedefDecl *TD = dyn_cast<TypedefDecl>(D);
+ TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
TD->getUnderlyingType()->isFunctionType()))
return;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 57a44ad9d984..2a71e14265a8 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -67,7 +67,7 @@ using namespace sema;
///
/// Subclasses can customize the transformation at various levels. The
/// most coarse-grained transformations involve replacing TransformType(),
-/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifier(),
+/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifierLoc(),
/// TransformTemplateName(), or TransformTemplateArgument() with entirely
/// new implementations.
///
@@ -375,16 +375,6 @@ public:
return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D));
}
- /// \brief Transform the given nested-name-specifier.
- ///
- /// By default, transforms all of the types and declarations within the
- /// nested-name-specifier. Subclasses may override this function to provide
- /// alternate behavior.
- NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
- SourceRange Range,
- QualType ObjectType = QualType(),
- NamedDecl *FirstQualifierInScope = 0);
-
/// \brief Transform the given nested-name-specifier with source-location
/// information.
///
@@ -407,10 +397,27 @@ public:
/// \brief Transform the given template name.
///
+ /// \param SS The nested-name-specifier that qualifies the template
+ /// name. This nested-name-specifier must already have been transformed.
+ ///
+ /// \param Name The template name to transform.
+ ///
+ /// \param NameLoc The source location of the template name.
+ ///
+ /// \param ObjectType If we're translating a template name within a member
+ /// access expression, this is the type of the object whose member template
+ /// is being referenced.
+ ///
+ /// \param FirstQualifierInScope If the first part of a nested-name-specifier
+ /// also refers to a name within the current (lexical) scope, this is the
+ /// declaration it refers to.
+ ///
/// By default, transforms the template name by transforming the declarations
/// and nested-name-specifiers that occur within the template name.
/// Subclasses may override this function to provide alternate behavior.
- TemplateName TransformTemplateName(TemplateName Name,
+ TemplateName TransformTemplateName(CXXScopeSpec &SS,
+ TemplateName Name,
+ SourceLocation NameLoc,
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = 0);
@@ -483,6 +490,9 @@ public:
QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
#include "clang/AST/TypeLocNodes.def"
+ StmtResult
+ TransformSEHHandler(Stmt *Handler);
+
QualType
TransformTemplateSpecializationType(TypeLocBuilder &TLB,
TemplateSpecializationTypeLoc TL,
@@ -491,7 +501,13 @@ public:
QualType
TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
DependentTemplateSpecializationTypeLoc TL,
- NestedNameSpecifier *Prefix);
+ TemplateName Template,
+ CXXScopeSpec &SS);
+
+ QualType
+ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
+ DependentTemplateSpecializationTypeLoc TL,
+ NestedNameSpecifierLoc QualifierLoc);
/// \brief Transforms the parameters of a function type into the
/// given vectors.
@@ -508,7 +524,11 @@ public:
/// \brief Transforms a single function-type parameter. Return null
/// on error.
+ ///
+ /// \param indexAdjustment - A number to add to the parameter's
+ /// scope index; can be negative
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
+ int indexAdjustment,
llvm::Optional<unsigned> NumExpansions);
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
@@ -656,7 +676,7 @@ public:
QualType RebuildUnresolvedUsingType(Decl *D);
/// \brief Build a new typedef type.
- QualType RebuildTypedefType(TypedefDecl *Typedef) {
+ QualType RebuildTypedefType(TypedefNameDecl *Typedef) {
return SemaRef.Context.getTypeDeclType(Typedef);
}
@@ -701,7 +721,7 @@ public:
/// different behavior.
QualType RebuildTemplateSpecializationType(TemplateName Template,
SourceLocation TemplateLoc,
- const TemplateArgumentListInfo &Args);
+ TemplateArgumentListInfo &Args);
/// \brief Build a new parenthesized type.
///
@@ -718,8 +738,11 @@ public:
/// Subclasses may override this routine to provide different behavior.
QualType RebuildElaboratedType(SourceLocation KeywordLoc,
ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS, QualType Named) {
- return SemaRef.Context.getElaboratedType(Keyword, NNS, Named);
+ NestedNameSpecifierLoc QualifierLoc,
+ QualType Named) {
+ return SemaRef.Context.getElaboratedType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ Named);
}
/// \brief Build a new typename type that refers to a template-id.
@@ -728,34 +751,40 @@ public:
/// nested-name-specifier and the given type. Subclasses may override
/// this routine to provide different behavior.
QualType RebuildDependentTemplateSpecializationType(
- ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- const IdentifierInfo *Name,
- SourceLocation NameLoc,
- const TemplateArgumentListInfo &Args) {
+ ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifierLoc QualifierLoc,
+ const IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ TemplateArgumentListInfo &Args) {
// Rebuild the template name.
// TODO: avoid TemplateName abstraction
- TemplateName InstName =
- getDerived().RebuildTemplateName(Qualifier, QualifierRange, *Name,
- QualType(), 0);
+ CXXScopeSpec SS;
+ SS.Adopt(QualifierLoc);
+ TemplateName InstName
+ = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(), 0);
if (InstName.isNull())
return QualType();
-
+
// If it's still dependent, make a dependent specialization.
if (InstName.getAsDependentTemplateName())
- return SemaRef.Context.getDependentTemplateSpecializationType(
- Keyword, Qualifier, Name, Args);
-
+ return SemaRef.Context.getDependentTemplateSpecializationType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ Name,
+ Args);
+
// Otherwise, make an elaborated type wrapping a non-dependent
// specialization.
QualType T =
- getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
+ getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
if (T.isNull()) return QualType();
-
- // NOTE: NNS is already recorded in template specialization type T.
- return SemaRef.Context.getElaboratedType(Keyword, /*NNS=*/0, T);
+
+ if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == 0)
+ return T;
+
+ return SemaRef.Context.getElaboratedType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ T);
}
/// \brief Build a new typename type that refers to an identifier.
@@ -764,23 +793,24 @@ public:
/// (or elaborated type). Subclasses may override this routine to provide
/// different behavior.
QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
- const IdentifierInfo *Id,
SourceLocation KeywordLoc,
- SourceRange NNSRange,
+ NestedNameSpecifierLoc QualifierLoc,
+ const IdentifierInfo *Id,
SourceLocation IdLoc) {
CXXScopeSpec SS;
- SS.MakeTrivial(SemaRef.Context, NNS, NNSRange);
+ SS.Adopt(QualifierLoc);
- if (NNS->isDependent()) {
+ if (QualifierLoc.getNestedNameSpecifier()->isDependent()) {
// If the name is still dependent, just build a new dependent name type.
if (!SemaRef.computeDeclContext(SS))
- return SemaRef.Context.getDependentNameType(Keyword, NNS, Id);
+ return SemaRef.Context.getDependentNameType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ Id);
}
if (Keyword == ETK_None || Keyword == ETK_Typename)
- return SemaRef.CheckTypenameType(Keyword, NNS, *Id,
- KeywordLoc, NNSRange, IdLoc);
+ return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
+ *Id, IdLoc);
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
@@ -828,7 +858,8 @@ public:
NamedDecl *SomeDecl = Result.getRepresentativeDecl();
unsigned Kind = 0;
if (isa<TypedefDecl>(SomeDecl)) Kind = 1;
- else if (isa<ClassTemplateDecl>(SomeDecl)) Kind = 2;
+ else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2;
+ else if (isa<ClassTemplateDecl>(SomeDecl)) Kind = 3;
SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind;
SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at);
break;
@@ -850,7 +881,9 @@ public:
// Build the elaborated-type-specifier type.
QualType T = SemaRef.Context.getTypeDeclType(Tag);
- return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
+ return SemaRef.Context.getElaboratedType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ T);
}
/// \brief Build a new pack expansion type.
@@ -865,56 +898,13 @@ public:
NumExpansions);
}
- /// \brief Build a new nested-name-specifier given the prefix and an
- /// identifier that names the next step in the nested-name-specifier.
- ///
- /// By default, performs semantic analysis when building the new
- /// nested-name-specifier. Subclasses may override this routine to provide
- /// different behavior.
- NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- IdentifierInfo &II,
- QualType ObjectType,
- NamedDecl *FirstQualifierInScope);
-
- /// \brief Build a new nested-name-specifier given the prefix and the
- /// namespace named in the next step in the nested-name-specifier.
- ///
- /// By default, performs semantic analysis when building the new
- /// nested-name-specifier. Subclasses may override this routine to provide
- /// different behavior.
- NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- NamespaceDecl *NS);
-
- /// \brief Build a new nested-name-specifier given the prefix and the
- /// namespace alias named in the next step in the nested-name-specifier.
- ///
- /// By default, performs semantic analysis when building the new
- /// nested-name-specifier. Subclasses may override this routine to provide
- /// different behavior.
- NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- NamespaceAliasDecl *Alias);
-
- /// \brief Build a new nested-name-specifier given the prefix and the
- /// type named in the next step in the nested-name-specifier.
- ///
- /// By default, performs semantic analysis when building the new
- /// nested-name-specifier. Subclasses may override this routine to provide
- /// different behavior.
- NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- bool TemplateKW,
- QualType T);
-
/// \brief Build a new template name given a nested name specifier, a flag
/// indicating whether the "template" keyword was provided, and the template
/// that the template name refers to.
///
/// By default, builds the new template name directly. Subclasses may override
/// this routine to provide different behavior.
- TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ TemplateName RebuildTemplateName(CXXScopeSpec &SS,
bool TemplateKW,
TemplateDecl *Template);
@@ -925,9 +915,9 @@ public:
/// be resolved to a specific template, then builds the appropriate kind of
/// template name. Subclasses may override this routine to provide different
/// behavior.
- TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- const IdentifierInfo &II,
+ TemplateName RebuildTemplateName(CXXScopeSpec &SS,
+ const IdentifierInfo &Name,
+ SourceLocation NameLoc,
QualType ObjectType,
NamedDecl *FirstQualifierInScope);
@@ -938,8 +928,9 @@ public:
/// be resolved to a specific template, then builds the appropriate kind of
/// template name. Subclasses may override this routine to provide different
/// behavior.
- TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ TemplateName RebuildTemplateName(CXXScopeSpec &SS,
OverloadedOperatorKind Operator,
+ SourceLocation NameLoc,
QualType ObjectType);
/// \brief Build a new template name given a template template parameter pack
@@ -1147,9 +1138,10 @@ public:
/// Subclasses may override this routine to provide different behavior.
VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
TypeSourceInfo *TInfo, QualType T) {
- return getSema().BuildObjCExceptionDecl(TInfo, T,
- ExceptionDecl->getIdentifier(),
- ExceptionDecl->getLocation());
+ return getSema().BuildObjCExceptionDecl(TInfo, T,
+ ExceptionDecl->getInnerLocStart(),
+ ExceptionDecl->getLocation(),
+ ExceptionDecl->getIdentifier());
}
/// \brief Build a new Objective-C @catch statement.
@@ -1214,11 +1206,16 @@ public:
///
/// By default, performs semantic analysis to build the new decaration.
/// Subclasses may override this routine to provide different behavior.
- VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
+ VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
TypeSourceInfo *Declarator,
- IdentifierInfo *Name,
- SourceLocation Loc) {
- return getSema().BuildExceptionDeclaration(0, Declarator, Name, Loc);
+ SourceLocation StartLoc,
+ SourceLocation IdLoc,
+ IdentifierInfo *Id) {
+ VarDecl *Var = getSema().BuildExceptionDeclaration(0, Declarator,
+ StartLoc, IdLoc, Id);
+ if (Var)
+ getSema().CurContext->addDecl(Var);
+ return Var;
}
/// \brief Build a new C++ catch statement.
@@ -1242,6 +1239,46 @@ public:
return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, move(Handlers));
}
+ /// \brief Build a new C++0x range-based for statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
+ SourceLocation ColonLoc,
+ Stmt *Range, Stmt *BeginEnd,
+ Expr *Cond, Expr *Inc,
+ Stmt *LoopVar,
+ SourceLocation RParenLoc) {
+ return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd,
+ Cond, Inc, LoopVar, RParenLoc);
+ }
+
+ /// \brief Attach body to a C++0x range-based for statement.
+ ///
+ /// By default, performs semantic analysis to finish the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body) {
+ return getSema().FinishCXXForRangeStmt(ForRange, Body);
+ }
+
+ StmtResult RebuildSEHTryStmt(bool IsCXXTry,
+ SourceLocation TryLoc,
+ Stmt *TryBlock,
+ Stmt *Handler) {
+ return getSema().ActOnSEHTryBlock(IsCXXTry,TryLoc,TryBlock,Handler);
+ }
+
+ StmtResult RebuildSEHExceptStmt(SourceLocation Loc,
+ Expr *FilterExpr,
+ Stmt *Block) {
+ return getSema().ActOnSEHExceptBlock(Loc,FilterExpr,Block);
+ }
+
+ StmtResult RebuildSEHFinallyStmt(SourceLocation Loc,
+ Stmt *Block) {
+ return getSema().ActOnSEHFinallyBlock(Loc,Block);
+ }
+
/// \brief Build a new expression that references a declaration.
///
/// By default, performs semantic analysis to build the new expression.
@@ -1257,13 +1294,12 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ ExprResult RebuildDeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
ValueDecl *VD,
const DeclarationNameInfo &NameInfo,
TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
- SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
+ SS.Adopt(QualifierLoc);
// FIXME: loses template args.
@@ -1315,25 +1351,28 @@ public:
NumComponents, RParenLoc);
}
- /// \brief Build a new sizeof or alignof expression with a type argument.
+ /// \brief Build a new sizeof, alignof or vec_step expression with a
+ /// type argument.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildSizeOfAlignOf(TypeSourceInfo *TInfo,
- SourceLocation OpLoc,
- bool isSizeOf, SourceRange R) {
- return getSema().CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeOf, R);
+ ExprResult RebuildUnaryExprOrTypeTrait(TypeSourceInfo *TInfo,
+ SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ SourceRange R) {
+ return getSema().CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, R);
}
- /// \brief Build a new sizeof or alignof expression with an expression
- /// argument.
+ /// \brief Build a new sizeof, alignof or vec step expression with an
+ /// expression argument.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildSizeOfAlignOf(Expr *SubExpr, SourceLocation OpLoc,
- bool isSizeOf, SourceRange R) {
+ ExprResult RebuildUnaryExprOrTypeTrait(Expr *SubExpr, SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ SourceRange R) {
ExprResult Result
- = getSema().CreateSizeOfAlignOfExpr(SubExpr, OpLoc, isSizeOf, R);
+ = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind, R);
if (Result.isInvalid())
return ExprError();
@@ -1371,8 +1410,7 @@ public:
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildMemberExpr(Expr *Base, SourceLocation OpLoc,
bool isArrow,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &MemberNameInfo,
ValueDecl *Member,
NamedDecl *FoundDecl,
@@ -1382,14 +1420,17 @@ public:
// We have a reference to an unnamed field. This is always the
// base of an anonymous struct/union member access, i.e. the
// field is always of record type.
- assert(!Qualifier && "Can't have an unnamed field with a qualifier!");
+ assert(!QualifierLoc && "Can't have an unnamed field with a qualifier!");
assert(Member->getType()->isRecordType() &&
"unnamed member not of record type?");
- if (getSema().PerformObjectMemberConversion(Base, Qualifier,
- FoundDecl, Member))
+ ExprResult BaseResult =
+ getSema().PerformObjectMemberConversion(Base,
+ QualifierLoc.getNestedNameSpecifier(),
+ FoundDecl, Member);
+ if (BaseResult.isInvalid())
return ExprError();
-
+ Base = BaseResult.take();
ExprValueKind VK = isArrow ? VK_LValue : Base->getValueKind();
MemberExpr *ME =
new (getSema().Context) MemberExpr(Base, isArrow,
@@ -1400,11 +1441,12 @@ public:
}
CXXScopeSpec SS;
- if (Qualifier) {
- SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
- }
+ SS.Adopt(QualifierLoc);
- getSema().DefaultFunctionArrayConversion(Base);
+ ExprResult BaseResult = getSema().DefaultFunctionArrayConversion(Base);
+ if (BaseResult.isInvalid())
+ return ExprError();
+ Base = BaseResult.take();
QualType BaseType = Base->getType();
// FIXME: this involves duplicating earlier analysis in a lot of
@@ -1586,6 +1628,22 @@ public:
RParenLoc);
}
+ /// \brief Build a new generic selection expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ TypeSourceInfo **Types,
+ Expr **Exprs,
+ unsigned NumAssocs) {
+ return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
+ ControllingExpr, Types, Exprs,
+ NumAssocs);
+ }
+
/// \brief Build a new overloaded operator call expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -1882,6 +1940,29 @@ public:
return getSema().BuildBinaryTypeTrait(Trait, StartLoc, LhsT, RhsT, RParenLoc);
}
+ /// \brief Build a new array type trait expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildArrayTypeTrait(ArrayTypeTrait Trait,
+ SourceLocation StartLoc,
+ TypeSourceInfo *TSInfo,
+ Expr *DimExpr,
+ SourceLocation RParenLoc) {
+ return getSema().BuildArrayTypeTrait(Trait, StartLoc, TSInfo, DimExpr, RParenLoc);
+ }
+
+ /// \brief Build a new expression trait expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildExpressionTrait(ExpressionTrait Trait,
+ SourceLocation StartLoc,
+ Expr *Queried,
+ SourceLocation RParenLoc) {
+ return getSema().BuildExpressionTrait(Trait, StartLoc, Queried, RParenLoc);
+ }
+
/// \brief Build a new (previously unresolved) declaration reference
/// expression.
///
@@ -1968,16 +2049,15 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildCXXDependentScopeMemberExpr(Expr *BaseE,
- QualType BaseType,
- bool IsArrow,
- SourceLocation OperatorLoc,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ QualType BaseType,
+ bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
- SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
+ SS.Adopt(QualifierLoc);
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
@@ -1994,13 +2074,12 @@ public:
QualType BaseType,
SourceLocation OperatorLoc,
bool IsArrow,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
+ NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
- SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
+ SS.Adopt(QualifierLoc);
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
@@ -2076,20 +2155,20 @@ public:
bool IsArrow, bool IsFreeIvar) {
// FIXME: We lose track of the IsFreeIvar bit.
CXXScopeSpec SS;
- Expr *Base = BaseArg;
+ ExprResult Base = getSema().Owned(BaseArg);
LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc,
Sema::LookupMemberName);
ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
/*FIME:*/IvarLoc,
SS, 0,
false);
- if (Result.isInvalid())
+ if (Result.isInvalid() || Base.isInvalid())
return ExprError();
if (Result.get())
return move(Result);
- return getSema().BuildMemberReferenceExpr(Base, Base->getType(),
+ return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IvarLoc, IsArrow, SS,
/*FirstQualifierInScope=*/0,
R,
@@ -2104,20 +2183,20 @@ public:
ObjCPropertyDecl *Property,
SourceLocation PropertyLoc) {
CXXScopeSpec SS;
- Expr *Base = BaseArg;
+ ExprResult Base = getSema().Owned(BaseArg);
LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
Sema::LookupMemberName);
bool IsArrow = false;
ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
/*FIME:*/PropertyLoc,
SS, 0, false);
- if (Result.isInvalid())
+ if (Result.isInvalid() || Base.isInvalid())
return ExprError();
if (Result.get())
return move(Result);
- return getSema().BuildMemberReferenceExpr(Base, Base->getType(),
+ return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/PropertyLoc, IsArrow,
SS,
/*FirstQualifierInScope=*/0,
@@ -2148,19 +2227,19 @@ public:
ExprResult RebuildObjCIsaExpr(Expr *BaseArg, SourceLocation IsaLoc,
bool IsArrow) {
CXXScopeSpec SS;
- Expr *Base = BaseArg;
+ ExprResult Base = getSema().Owned(BaseArg);
LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc,
Sema::LookupMemberName);
ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
/*FIME:*/IsaLoc,
SS, 0, false);
- if (Result.isInvalid())
+ if (Result.isInvalid() || Base.isInvalid())
return ExprError();
if (Result.get())
return move(Result);
- return getSema().BuildMemberReferenceExpr(Base, Base->getType(),
+ return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/IsaLoc, IsArrow, SS,
/*FirstQualifierInScope=*/0,
R,
@@ -2183,28 +2262,25 @@ public:
// Build a reference to the __builtin_shufflevector builtin
FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
- Expr *Callee
- = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(),
- VK_LValue, BuiltinLoc);
- SemaRef.UsualUnaryConversions(Callee);
+ ExprResult Callee
+ = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(),
+ VK_LValue, BuiltinLoc));
+ Callee = SemaRef.UsualUnaryConversions(Callee.take());
+ if (Callee.isInvalid())
+ return ExprError();
// Build the CallExpr
unsigned NumSubExprs = SubExprs.size();
Expr **Subs = (Expr **)SubExprs.release();
- CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee,
+ ExprResult TheCall = SemaRef.Owned(
+ new (SemaRef.Context) CallExpr(SemaRef.Context, Callee.take(),
Subs, NumSubExprs,
Builtin->getCallResultType(),
Expr::getValueKindForType(Builtin->getResultType()),
- RParenLoc);
- ExprResult OwnedCall(SemaRef.Owned(TheCall));
+ RParenLoc));
// Type-check the __builtin_shufflevector expression.
- ExprResult Result = SemaRef.SemaBuiltinShuffleVector(TheCall);
- if (Result.isInvalid())
- return ExprError();
-
- OwnedCall.release();
- return move(Result);
+ return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.take()));
}
/// \brief Build a new template argument pack expansion.
@@ -2230,7 +2306,7 @@ public:
return TemplateArgumentLoc(TemplateArgument(
Pattern.getArgument().getAsTemplate(),
NumExpansions),
- Pattern.getTemplateQualifierRange(),
+ Pattern.getTemplateQualifierLoc(),
Pattern.getTemplateNameLoc(),
EllipsisLoc);
@@ -2265,20 +2341,15 @@ public:
}
private:
- QualType TransformTypeInObjectScope(QualType T,
- QualType ObjectType,
- NamedDecl *FirstQualifierInScope,
- NestedNameSpecifier *Prefix);
-
- TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *T,
- QualType ObjectType,
- NamedDecl *FirstQualifierInScope,
- NestedNameSpecifier *Prefix);
-
TypeLoc TransformTypeInObjectScope(TypeLoc TL,
QualType ObjectType,
NamedDecl *FirstQualifierInScope,
CXXScopeSpec &SS);
+
+ TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
+ QualType ObjectType,
+ NamedDecl *FirstQualifierInScope,
+ CXXScopeSpec &SS);
};
template<typename Derived>
@@ -2426,99 +2497,6 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
}
template<typename Derived>
-NestedNameSpecifier *
-TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
- SourceRange Range,
- QualType ObjectType,
- NamedDecl *FirstQualifierInScope) {
- NestedNameSpecifier *Prefix = NNS->getPrefix();
-
- // Transform the prefix of this nested name specifier.
- if (Prefix) {
- Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range,
- ObjectType,
- FirstQualifierInScope);
- if (!Prefix)
- return 0;
- }
-
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- if (Prefix) {
- // The object type and qualifier-in-scope really apply to the
- // leftmost entity.
- ObjectType = QualType();
- FirstQualifierInScope = 0;
- }
-
- assert((Prefix || !ObjectType.isNull()) &&
- "Identifier nested-name-specifier with no prefix or object type");
- if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() &&
- ObjectType.isNull())
- return NNS;
-
- return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
- *NNS->getAsIdentifier(),
- ObjectType,
- FirstQualifierInScope);
-
- case NestedNameSpecifier::Namespace: {
- NamespaceDecl *NS
- = cast_or_null<NamespaceDecl>(
- getDerived().TransformDecl(Range.getBegin(),
- NNS->getAsNamespace()));
- if (!getDerived().AlwaysRebuild() &&
- Prefix == NNS->getPrefix() &&
- NS == NNS->getAsNamespace())
- return NNS;
-
- return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS);
- }
-
- case NestedNameSpecifier::NamespaceAlias: {
- NamespaceAliasDecl *Alias
- = cast_or_null<NamespaceAliasDecl>(
- getDerived().TransformDecl(Range.getBegin(),
- NNS->getAsNamespaceAlias()));
- if (!getDerived().AlwaysRebuild() &&
- Prefix == NNS->getPrefix() &&
- Alias == NNS->getAsNamespaceAlias())
- return NNS;
-
- return getDerived().RebuildNestedNameSpecifier(Prefix, Range, Alias);
- }
-
- case NestedNameSpecifier::Global:
- // There is no meaningful transformation that one could perform on the
- // global scope.
- return NNS;
-
- case NestedNameSpecifier::TypeSpecWithTemplate:
- case NestedNameSpecifier::TypeSpec: {
- TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName());
- QualType T = TransformTypeInObjectScope(QualType(NNS->getAsType(), 0),
- ObjectType,
- FirstQualifierInScope,
- Prefix);
- if (T.isNull())
- return 0;
-
- if (!getDerived().AlwaysRebuild() &&
- Prefix == NNS->getPrefix() &&
- T == QualType(NNS->getAsType(), 0))
- return NNS;
-
- return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
- NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
- T);
- }
- }
-
- // Required to silence a GCC warning
- return 0;
-}
-
-template<typename Derived>
NestedNameSpecifierLoc
TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS,
@@ -2594,10 +2572,11 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
<< TL.getType() << SS.getRange();
return NestedNameSpecifierLoc();
}
- }
+ }
- // The qualifier-in-scope only applies to the leftmost entity.
+ // The qualifier-in-scope and object type only apply to the leftmost entity.
FirstQualifierInScope = 0;
+ ObjectType = QualType();
}
// Don't rebuild the nested-name-specifier if we don't have to.
@@ -2669,89 +2648,73 @@ TreeTransform<Derived>
template<typename Derived>
TemplateName
-TreeTransform<Derived>::TransformTemplateName(TemplateName Name,
+TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
+ TemplateName Name,
+ SourceLocation NameLoc,
QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
- SourceLocation Loc = getDerived().getBaseLocation();
-
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
- NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(),
- /*FIXME*/ SourceRange(Loc),
- ObjectType,
- FirstQualifierInScope);
- if (!NNS)
+ TemplateDecl *Template = QTN->getTemplateDecl();
+ assert(Template && "qualified template name must refer to a template");
+
+ TemplateDecl *TransTemplate
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
+ Template));
+ if (!TransTemplate)
return TemplateName();
-
- if (TemplateDecl *Template = QTN->getTemplateDecl()) {
- TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template));
- if (!TransTemplate)
- return TemplateName();
-
- if (!getDerived().AlwaysRebuild() &&
- NNS == QTN->getQualifier() &&
- TransTemplate == Template)
- return Name;
-
- return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(),
- TransTemplate);
- }
-
- // These should be getting filtered out before they make it into the AST.
- llvm_unreachable("overloaded template name survived to here");
+
+ if (!getDerived().AlwaysRebuild() &&
+ SS.getScopeRep() == QTN->getQualifier() &&
+ TransTemplate == Template)
+ return Name;
+
+ return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(),
+ TransTemplate);
}
-
+
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
- NestedNameSpecifier *NNS = DTN->getQualifier();
- if (NNS) {
- NNS = getDerived().TransformNestedNameSpecifier(NNS,
- /*FIXME:*/SourceRange(Loc),
- ObjectType,
- FirstQualifierInScope);
- if (!NNS) return TemplateName();
-
+ if (SS.getScopeRep()) {
// These apply to the scope specifier, not the template.
ObjectType = QualType();
FirstQualifierInScope = 0;
- }
-
+ }
+
if (!getDerived().AlwaysRebuild() &&
- NNS == DTN->getQualifier() &&
+ SS.getScopeRep() == DTN->getQualifier() &&
ObjectType.isNull())
return Name;
-
+
if (DTN->isIdentifier()) {
- // FIXME: Bad range
- SourceRange QualifierRange(getDerived().getBaseLocation());
- return getDerived().RebuildTemplateName(NNS, QualifierRange,
+ return getDerived().RebuildTemplateName(SS,
*DTN->getIdentifier(),
+ NameLoc,
ObjectType,
FirstQualifierInScope);
}
- return getDerived().RebuildTemplateName(NNS, DTN->getOperator(),
+ return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc,
ObjectType);
}
-
+
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
TemplateDecl *TransTemplate
- = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template));
+ = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
+ Template));
if (!TransTemplate)
return TemplateName();
-
+
if (!getDerived().AlwaysRebuild() &&
TransTemplate == Template)
return Name;
-
+
return TemplateName(TransTemplate);
}
-
+
if (SubstTemplateTemplateParmPackStorage *SubstPack
- = Name.getAsSubstTemplateTemplateParmPack()) {
+ = Name.getAsSubstTemplateTemplateParmPack()) {
TemplateTemplateParmDecl *TransParam
- = cast_or_null<TemplateTemplateParmDecl>(
- getDerived().TransformDecl(Loc, SubstPack->getParameterPack()));
+ = cast_or_null<TemplateTemplateParmDecl>(
+ getDerived().TransformDecl(NameLoc, SubstPack->getParameterPack()));
if (!TransParam)
return TemplateName();
@@ -2785,12 +2748,25 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
break;
case TemplateArgument::Template:
- Output = TemplateArgumentLoc(Arg, SourceRange(), Loc);
- break;
-
- case TemplateArgument::TemplateExpansion:
- Output = TemplateArgumentLoc(Arg, SourceRange(), Loc, Loc);
+ case TemplateArgument::TemplateExpansion: {
+ NestedNameSpecifierLocBuilder Builder;
+ TemplateName Template = Arg.getAsTemplate();
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
+ Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
+ else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
+ Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc);
+
+ if (Arg.getKind() == TemplateArgument::Template)
+ Output = TemplateArgumentLoc(Arg,
+ Builder.getWithLocInContext(SemaRef.Context),
+ Loc);
+ else
+ Output = TemplateArgumentLoc(Arg,
+ Builder.getWithLocInContext(SemaRef.Context),
+ Loc, Loc);
+
break;
+ }
case TemplateArgument::Expression:
Output = TemplateArgumentLoc(Arg, Arg.getAsExpr());
@@ -2849,14 +2825,22 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
}
case TemplateArgument::Template: {
- TemporaryBase Rebase(*this, Input.getLocation(), DeclarationName());
+ NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc();
+ if (QualifierLoc) {
+ QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc);
+ if (!QualifierLoc)
+ return true;
+ }
+
+ CXXScopeSpec SS;
+ SS.Adopt(QualifierLoc);
TemplateName Template
- = getDerived().TransformTemplateName(Arg.getAsTemplate());
+ = getDerived().TransformTemplateName(SS, Arg.getAsTemplate(),
+ Input.getTemplateNameLoc());
if (Template.isNull())
return true;
- Output = TemplateArgumentLoc(TemplateArgument(Template),
- Input.getTemplateQualifierRange(),
+ Output = TemplateArgumentLoc(TemplateArgument(Template), QualifierLoc,
Input.getTemplateNameLoc());
return false;
}
@@ -2872,8 +2856,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
Expr *InputExpr = Input.getSourceExpression();
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
- ExprResult E
- = getDerived().TransformExpr(InputExpr);
+ ExprResult E = getDerived().TransformExpr(InputExpr);
if (E.isInvalid()) return true;
Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take());
return false;
@@ -3177,112 +3160,87 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
return Result;
}
-/// \brief Transforms a type that was written in a scope specifier,
-/// given an object type, the results of unqualified lookup, and
-/// an already-instantiated prefix.
-///
-/// The object type is provided iff the scope specifier qualifies the
-/// member of a dependent member-access expression. The prefix is
-/// provided iff the the scope specifier in which this appears has a
-/// prefix.
-///
-/// This is private to TreeTransform.
template<typename Derived>
-QualType
-TreeTransform<Derived>::TransformTypeInObjectScope(QualType T,
- QualType ObjectType,
- NamedDecl *UnqualLookup,
- NestedNameSpecifier *Prefix) {
- if (getDerived().AlreadyTransformed(T))
- return T;
-
- TypeSourceInfo *TSI =
- SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation());
-
- TSI = getDerived().TransformTypeInObjectScope(TSI, ObjectType,
- UnqualLookup, Prefix);
- if (!TSI) return QualType();
- return TSI->getType();
-}
-
-template<typename Derived>
-TypeSourceInfo *
-TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSI,
+TypeLoc
+TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
QualType ObjectType,
NamedDecl *UnqualLookup,
- NestedNameSpecifier *Prefix) {
- // TODO: in some cases, we might have some verification to do here.
- if (ObjectType.isNull())
- return getDerived().TransformType(TSI);
-
- QualType T = TSI->getType();
+ CXXScopeSpec &SS) {
+ QualType T = TL.getType();
if (getDerived().AlreadyTransformed(T))
- return TSI;
-
+ return TL;
+
TypeLocBuilder TLB;
QualType Result;
-
+
if (isa<TemplateSpecializationType>(T)) {
- TemplateSpecializationTypeLoc TL
- = cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
-
+ TemplateSpecializationTypeLoc SpecTL
+ = cast<TemplateSpecializationTypeLoc>(TL);
+
TemplateName Template =
- getDerived().TransformTemplateName(TL.getTypePtr()->getTemplateName(),
+ getDerived().TransformTemplateName(SS,
+ SpecTL.getTypePtr()->getTemplateName(),
+ SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
- if (Template.isNull()) return 0;
-
- Result = getDerived()
- .TransformTemplateSpecializationType(TLB, TL, Template);
+ if (Template.isNull())
+ return TypeLoc();
+
+ Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
+ Template);
} else if (isa<DependentTemplateSpecializationType>(T)) {
- DependentTemplateSpecializationTypeLoc TL
- = cast<DependentTemplateSpecializationTypeLoc>(TSI->getTypeLoc());
-
- Result = getDerived()
- .TransformDependentTemplateSpecializationType(TLB, TL, Prefix);
+ DependentTemplateSpecializationTypeLoc SpecTL
+ = cast<DependentTemplateSpecializationTypeLoc>(TL);
+
+ TemplateName Template
+ = getDerived().RebuildTemplateName(SS,
+ *SpecTL.getTypePtr()->getIdentifier(),
+ SpecTL.getNameLoc(),
+ ObjectType, UnqualLookup);
+ if (Template.isNull())
+ return TypeLoc();
+
+ Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
+ SpecTL,
+ Template,
+ SS);
} else {
// Nothing special needs to be done for these.
- Result = getDerived().TransformType(TLB, TSI->getTypeLoc());
+ Result = getDerived().TransformType(TLB, TL);
}
-
- if (Result.isNull()) return 0;
- return TLB.getTypeSourceInfo(SemaRef.Context, Result);
+
+ if (Result.isNull())
+ return TypeLoc();
+
+ return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc();
}
template<typename Derived>
-TypeLoc
-TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
+TypeSourceInfo *
+TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
QualType ObjectType,
NamedDecl *UnqualLookup,
CXXScopeSpec &SS) {
// FIXME: Painfully copy-paste from the above!
- // TODO: in some cases, we might have some verification to do here.
- if (ObjectType.isNull()) {
- TypeLocBuilder TLB;
- TLB.reserve(TL.getFullDataSize());
- QualType Result = getDerived().TransformType(TLB, TL);
- if (Result.isNull())
- return TypeLoc();
-
- return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc();
- }
-
- QualType T = TL.getType();
+ QualType T = TSInfo->getType();
if (getDerived().AlreadyTransformed(T))
- return TL;
+ return TSInfo;
TypeLocBuilder TLB;
QualType Result;
+ TypeLoc TL = TSInfo->getTypeLoc();
if (isa<TemplateSpecializationType>(T)) {
TemplateSpecializationTypeLoc SpecTL
= cast<TemplateSpecializationTypeLoc>(TL);
- TemplateName Template =
- getDerived().TransformTemplateName(SpecTL.getTypePtr()->getTemplateName(),
+ TemplateName Template
+ = getDerived().TransformTemplateName(SS,
+ SpecTL.getTypePtr()->getTemplateName(),
+ SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
if (Template.isNull())
- return TypeLoc();
+ return 0;
Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
@@ -3290,18 +3248,27 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
DependentTemplateSpecializationTypeLoc SpecTL
= cast<DependentTemplateSpecializationTypeLoc>(TL);
+ TemplateName Template
+ = getDerived().RebuildTemplateName(SS,
+ *SpecTL.getTypePtr()->getIdentifier(),
+ SpecTL.getNameLoc(),
+ ObjectType, UnqualLookup);
+ if (Template.isNull())
+ return 0;
+
Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
- SpecTL,
- SS.getScopeRep());
+ SpecTL,
+ Template,
+ SS);
} else {
// Nothing special needs to be done for these.
Result = getDerived().TransformType(TLB, TL);
}
if (Result.isNull())
- return TypeLoc();
+ return 0;
- return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc();
+ return TLB.getTypeSourceInfo(SemaRef.Context, Result);
}
template <class TyLoc> static inline
@@ -3438,23 +3405,34 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
MemberPointerTypeLoc TL) {
- const MemberPointerType *T = TL.getTypePtr();
-
QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc());
if (PointeeType.isNull())
return QualType();
- // TODO: preserve source information for this.
- QualType ClassType
- = getDerived().TransformType(QualType(T->getClass(), 0));
- if (ClassType.isNull())
- return QualType();
+ TypeSourceInfo* OldClsTInfo = TL.getClassTInfo();
+ TypeSourceInfo* NewClsTInfo = 0;
+ if (OldClsTInfo) {
+ NewClsTInfo = getDerived().TransformType(OldClsTInfo);
+ if (!NewClsTInfo)
+ return QualType();
+ }
+
+ const MemberPointerType *T = TL.getTypePtr();
+ QualType OldClsType = QualType(T->getClass(), 0);
+ QualType NewClsType;
+ if (NewClsTInfo)
+ NewClsType = NewClsTInfo->getType();
+ else {
+ NewClsType = getDerived().TransformType(OldClsType);
+ if (NewClsType.isNull())
+ return QualType();
+ }
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != T->getPointeeType() ||
- ClassType != QualType(T->getClass(), 0)) {
- Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType,
+ NewClsType != OldClsType) {
+ Result = getDerived().RebuildMemberPointerType(PointeeType, NewClsType,
TL.getStarLoc());
if (Result.isNull())
return QualType();
@@ -3462,6 +3440,7 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
MemberPointerTypeLoc NewTL = TLB.push<MemberPointerTypeLoc>(Result);
NewTL.setSigilLoc(TL.getSigilLoc());
+ NewTL.setClassTInfo(NewClsTInfo);
return Result;
}
@@ -3707,6 +3686,7 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
template<typename Derived>
ParmVarDecl *
TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
+ int indexAdjustment,
llvm::Optional<unsigned> NumExpansions) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
@@ -3741,18 +3721,22 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
if (!NewDI)
return 0;
- if (NewDI == OldDI)
+ if (NewDI == OldDI && indexAdjustment == 0)
return OldParm;
- else
- return ParmVarDecl::Create(SemaRef.Context,
- OldParm->getDeclContext(),
- OldParm->getLocation(),
- OldParm->getIdentifier(),
- NewDI->getType(),
- NewDI,
- OldParm->getStorageClass(),
- OldParm->getStorageClassAsWritten(),
- /* DefArg */ NULL);
+
+ ParmVarDecl *newParm = ParmVarDecl::Create(SemaRef.Context,
+ OldParm->getDeclContext(),
+ OldParm->getInnerLocStart(),
+ OldParm->getLocation(),
+ OldParm->getIdentifier(),
+ NewDI->getType(),
+ NewDI,
+ OldParm->getStorageClass(),
+ OldParm->getStorageClassAsWritten(),
+ /* DefArg */ NULL);
+ newParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
+ OldParm->getFunctionScopeIndex() + indexAdjustment);
+ return newParm;
}
template<typename Derived>
@@ -3762,9 +3746,14 @@ bool TreeTransform<Derived>::
const QualType *ParamTypes,
llvm::SmallVectorImpl<QualType> &OutParamTypes,
llvm::SmallVectorImpl<ParmVarDecl*> *PVars) {
+ int indexAdjustment = 0;
+
for (unsigned i = 0; i != NumParams; ++i) {
if (ParmVarDecl *OldParm = Params[i]) {
+ assert(OldParm->getFunctionScopeIndex() == i);
+
llvm::Optional<unsigned> NumExpansions;
+ ParmVarDecl *NewParm = 0;
if (OldParm->isParameterPack()) {
// We have a function parameter pack that may need to be expanded.
llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
@@ -3774,7 +3763,8 @@ bool TreeTransform<Derived>::
PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(TL);
TypeLoc Pattern = ExpansionTL.getPatternLoc();
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
-
+ assert(Unexpanded.size() > 0 && "Could not find parameter packs!");
+
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
@@ -3799,6 +3789,7 @@ bool TreeTransform<Derived>::
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
ParmVarDecl *NewParm
= getDerived().TransformFunctionTypeParam(OldParm,
+ indexAdjustment++,
OrigNumExpansions);
if (!NewParm)
return true;
@@ -3814,6 +3805,7 @@ bool TreeTransform<Derived>::
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
ParmVarDecl *NewParm
= getDerived().TransformFunctionTypeParam(OldParm,
+ indexAdjustment++,
OrigNumExpansions);
if (!NewParm)
return true;
@@ -3823,17 +3815,28 @@ bool TreeTransform<Derived>::
PVars->push_back(NewParm);
}
+ // The next parameter should have the same adjustment as the
+ // last thing we pushed, but we post-incremented indexAdjustment
+ // on every push. Also, if we push nothing, the adjustment should
+ // go down by one.
+ indexAdjustment--;
+
// We're done with the pack expansion.
continue;
}
// We'll substitute the parameter now without expanding the pack
// expansion.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+ NewParm = getDerived().TransformFunctionTypeParam(OldParm,
+ indexAdjustment,
+ NumExpansions);
+ } else {
+ NewParm = getDerived().TransformFunctionTypeParam(OldParm,
+ indexAdjustment,
+ llvm::Optional<unsigned>());
}
-
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
- ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm,
- NumExpansions);
+
if (!NewParm)
return true;
@@ -3848,6 +3851,7 @@ bool TreeTransform<Derived>::
QualType OldType = ParamTypes[i];
bool IsPackExpansion = false;
llvm::Optional<unsigned> NumExpansions;
+ QualType NewType;
if (const PackExpansionType *Expansion
= dyn_cast<PackExpansionType>(OldType)) {
// We have a function parameter pack that may need to be expanded.
@@ -3902,10 +3906,12 @@ bool TreeTransform<Derived>::
// expansion.
OldType = Expansion->getPattern();
IsPackExpansion = true;
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+ NewType = getDerived().TransformType(OldType);
+ } else {
+ NewType = getDerived().TransformType(OldType);
}
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
- QualType NewType = getDerived().TransformType(OldType);
if (NewType.isNull())
return true;
@@ -3918,8 +3924,16 @@ bool TreeTransform<Derived>::
PVars->push_back(0);
}
- return false;
+#ifndef NDEBUG
+ if (PVars) {
+ for (unsigned i = 0, e = PVars->size(); i != e; ++i)
+ if (ParmVarDecl *parm = (*PVars)[i])
+ assert(parm->getFunctionScopeIndex() == i);
}
+#endif
+
+ return false;
+}
template<typename Derived>
QualType
@@ -3983,8 +3997,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
}
FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result);
- NewTL.setLParenLoc(TL.getLParenLoc());
- NewTL.setRParenLoc(TL.getRParenLoc());
+ NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+ NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
NewTL.setTrailingReturn(TL.getTrailingReturn());
for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i)
NewTL.setArg(i, ParamDecls[i]);
@@ -4007,8 +4021,8 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
Result = getDerived().RebuildFunctionNoProtoType(ResultType);
FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result);
- NewTL.setLParenLoc(TL.getLParenLoc());
- NewTL.setRParenLoc(TL.getRParenLoc());
+ NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+ NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
NewTL.setTrailingReturn(false);
return Result;
@@ -4041,9 +4055,9 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
TypedefTypeLoc TL) {
const TypedefType *T = TL.getTypePtr();
- TypedefDecl *Typedef
- = cast_or_null<TypedefDecl>(getDerived().TransformDecl(TL.getNameLoc(),
- T->getDecl()));
+ TypedefNameDecl *Typedef
+ = cast_or_null<TypedefNameDecl>(getDerived().TransformDecl(TL.getNameLoc(),
+ T->getDecl()));
if (!Typedef)
return QualType();
@@ -4236,7 +4250,28 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
TypeLocBuilder &TLB,
SubstTemplateTypeParmTypeLoc TL) {
- return TransformTypeSpecType(TLB, TL);
+ const SubstTemplateTypeParmType *T = TL.getTypePtr();
+
+ // Substitute into the replacement type, which itself might involve something
+ // that needs to be transformed. This only tends to occur with default
+ // template arguments of template template parameters.
+ TemporaryBase Rebase(*this, TL.getNameLoc(), DeclarationName());
+ QualType Replacement = getDerived().TransformType(T->getReplacementType());
+ if (Replacement.isNull())
+ return QualType();
+
+ // Always canonicalize the replacement type.
+ Replacement = SemaRef.Context.getCanonicalType(Replacement);
+ QualType Result
+ = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(),
+ Replacement);
+
+ // Propagate type-source information.
+ SubstTemplateTypeParmTypeLoc NewTL
+ = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
+
}
template<typename Derived>
@@ -4252,8 +4287,12 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
TemplateSpecializationTypeLoc TL) {
const TemplateSpecializationType *T = TL.getTypePtr();
+ // The nested-name-specifier never matters in a TemplateSpecializationType,
+ // because we can't have a dependent nested-name-specifier anyway.
+ CXXScopeSpec SS;
TemplateName Template
- = getDerived().TransformTemplateName(T->getTemplateName());
+ = getDerived().TransformTemplateName(SS, T->getTemplateName(),
+ TL.getTemplateNameLoc());
if (Template.isNull())
return QualType();
@@ -4362,18 +4401,76 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
return Result;
}
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
+ TypeLocBuilder &TLB,
+ DependentTemplateSpecializationTypeLoc TL,
+ TemplateName Template,
+ CXXScopeSpec &SS) {
+ TemplateArgumentListInfo NewTemplateArgs;
+ NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
+ NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
+ typedef TemplateArgumentLocContainerIterator<
+ DependentTemplateSpecializationTypeLoc> ArgIterator;
+ if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
+ ArgIterator(TL, TL.getNumArgs()),
+ NewTemplateArgs))
+ return QualType();
+
+ // FIXME: maybe don't rebuild if all the template arguments are the same.
+
+ if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
+ QualType Result
+ = getSema().Context.getDependentTemplateSpecializationType(
+ TL.getTypePtr()->getKeyword(),
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ NewTemplateArgs);
+
+ DependentTemplateSpecializationTypeLoc NewTL
+ = TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getKeywordLoc());
+
+ NewTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context));
+ NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setLAngleLoc(TL.getLAngleLoc());
+ NewTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
+ NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
+ return Result;
+ }
+
+ QualType Result
+ = getDerived().RebuildTemplateSpecializationType(Template,
+ TL.getNameLoc(),
+ NewTemplateArgs);
+
+ if (!Result.isNull()) {
+ /// FIXME: Wrap this in an elaborated-type-specifier?
+ TemplateSpecializationTypeLoc NewTL
+ = TLB.push<TemplateSpecializationTypeLoc>(Result);
+ NewTL.setTemplateNameLoc(TL.getNameLoc());
+ NewTL.setLAngleLoc(TL.getLAngleLoc());
+ NewTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
+ NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
+ }
+
+ return Result;
+}
+
template<typename Derived>
QualType
TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
ElaboratedTypeLoc TL) {
const ElaboratedType *T = TL.getTypePtr();
- NestedNameSpecifier *NNS = 0;
+ NestedNameSpecifierLoc QualifierLoc;
// NOTE: the qualifier in an ElaboratedType is optional.
- if (T->getQualifier() != 0) {
- NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
- TL.getQualifierRange());
- if (!NNS)
+ if (TL.getQualifierLoc()) {
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc());
+ if (!QualifierLoc)
return QualType();
}
@@ -4383,18 +4480,18 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
- NNS != T->getQualifier() ||
+ QualifierLoc != TL.getQualifierLoc() ||
NamedT != T->getNamedType()) {
Result = getDerived().RebuildElaboratedType(TL.getKeywordLoc(),
- T->getKeyword(), NNS, NamedT);
+ T->getKeyword(),
+ QualifierLoc, NamedT);
if (Result.isNull())
return QualType();
}
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
NewTL.setKeywordLoc(TL.getKeywordLoc());
- NewTL.setQualifierRange(TL.getQualifierRange());
-
+ NewTL.setQualifierLoc(QualifierLoc);
return Result;
}
@@ -4462,17 +4559,16 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
DependentNameTypeLoc TL) {
const DependentNameType *T = TL.getTypePtr();
- NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
- TL.getQualifierRange());
- if (!NNS)
+ NestedNameSpecifierLoc QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc());
+ if (!QualifierLoc)
return QualType();
QualType Result
- = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
- T->getIdentifier(),
+ = getDerived().RebuildDependentNameType(T->getKeyword(),
TL.getKeywordLoc(),
- TL.getQualifierRange(),
+ QualifierLoc,
+ T->getIdentifier(),
TL.getNameLoc());
if (Result.isNull())
return QualType();
@@ -4483,11 +4579,11 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
NewTL.setKeywordLoc(TL.getKeywordLoc());
- NewTL.setQualifierRange(TL.getQualifierRange());
+ NewTL.setQualifierLoc(QualifierLoc);
} else {
DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
NewTL.setKeywordLoc(TL.getKeywordLoc());
- NewTL.setQualifierRange(TL.getQualifierRange());
+ NewTL.setQualifierLoc(QualifierLoc);
NewTL.setNameLoc(TL.getNameLoc());
}
return Result;
@@ -4497,65 +4593,79 @@ template<typename Derived>
QualType TreeTransform<Derived>::
TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
DependentTemplateSpecializationTypeLoc TL) {
- const DependentTemplateSpecializationType *T = TL.getTypePtr();
-
- NestedNameSpecifier *NNS
- = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
- TL.getQualifierRange());
- if (!NNS)
- return QualType();
-
+ NestedNameSpecifierLoc QualifierLoc;
+ if (TL.getQualifierLoc()) {
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc());
+ if (!QualifierLoc)
+ return QualType();
+ }
+
return getDerived()
- .TransformDependentTemplateSpecializationType(TLB, TL, NNS);
+ .TransformDependentTemplateSpecializationType(TLB, TL, QualifierLoc);
}
template<typename Derived>
QualType TreeTransform<Derived>::
- TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
- DependentTemplateSpecializationTypeLoc TL,
- NestedNameSpecifier *NNS) {
+TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
+ DependentTemplateSpecializationTypeLoc TL,
+ NestedNameSpecifierLoc QualifierLoc) {
const DependentTemplateSpecializationType *T = TL.getTypePtr();
-
+
TemplateArgumentListInfo NewTemplateArgs;
NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
-
- // FIXME: Nested-name-specifier source location info!
+
typedef TemplateArgumentLocContainerIterator<
- DependentTemplateSpecializationTypeLoc> ArgIterator;
+ DependentTemplateSpecializationTypeLoc> ArgIterator;
if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
ArgIterator(TL, TL.getNumArgs()),
NewTemplateArgs))
return QualType();
-
+
QualType Result
= getDerived().RebuildDependentTemplateSpecializationType(T->getKeyword(),
- NNS,
- TL.getQualifierRange(),
+ QualifierLoc,
T->getIdentifier(),
- TL.getNameLoc(),
- NewTemplateArgs);
+ TL.getNameLoc(),
+ NewTemplateArgs);
if (Result.isNull())
return QualType();
-
+
if (const ElaboratedType *ElabT = dyn_cast<ElaboratedType>(Result)) {
QualType NamedT = ElabT->getNamedType();
-
+
// Copy information relevant to the template specialization.
TemplateSpecializationTypeLoc NamedTL
= TLB.push<TemplateSpecializationTypeLoc>(NamedT);
+ NamedTL.setTemplateNameLoc(TL.getNameLoc());
NamedTL.setLAngleLoc(TL.getLAngleLoc());
NamedTL.setRAngleLoc(TL.getRAngleLoc());
- for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
- NamedTL.setArgLocInfo(I, TL.getArgLocInfo(I));
-
+ for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
+ NamedTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo());
+
// Copy information relevant to the elaborated type.
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
NewTL.setKeywordLoc(TL.getKeywordLoc());
- NewTL.setQualifierRange(TL.getQualifierRange());
+ NewTL.setQualifierLoc(QualifierLoc);
+ } else if (isa<DependentTemplateSpecializationType>(Result)) {
+ DependentTemplateSpecializationTypeLoc SpecTL
+ = TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
+ SpecTL.setKeywordLoc(TL.getKeywordLoc());
+ SpecTL.setQualifierLoc(QualifierLoc);
+ SpecTL.setNameLoc(TL.getNameLoc());
+ SpecTL.setLAngleLoc(TL.getLAngleLoc());
+ SpecTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
+ SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo());
} else {
- TypeLoc NewTL(Result, TL.getOpaqueData());
- TLB.pushFullCopy(NewTL);
+ TemplateSpecializationTypeLoc SpecTL
+ = TLB.push<TemplateSpecializationTypeLoc>(Result);
+ SpecTL.setTemplateNameLoc(TL.getNameLoc());
+ SpecTL.setLAngleLoc(TL.getLAngleLoc());
+ SpecTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
+ SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo());
}
return Result;
}
@@ -5304,8 +5414,9 @@ TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
return StmtError();
Var = getDerived().RebuildExceptionDecl(ExceptionDecl, T,
- ExceptionDecl->getIdentifier(),
- ExceptionDecl->getLocation());
+ ExceptionDecl->getInnerLocStart(),
+ ExceptionDecl->getLocation(),
+ ExceptionDecl->getIdentifier());
if (!Var || Var->isInvalidDecl())
return StmtError();
}
@@ -5356,6 +5467,112 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
move_arg(Handlers));
}
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
+ StmtResult Range = getDerived().TransformStmt(S->getRangeStmt());
+ if (Range.isInvalid())
+ return StmtError();
+
+ StmtResult BeginEnd = getDerived().TransformStmt(S->getBeginEndStmt());
+ if (BeginEnd.isInvalid())
+ return StmtError();
+
+ ExprResult Cond = getDerived().TransformExpr(S->getCond());
+ if (Cond.isInvalid())
+ return StmtError();
+
+ ExprResult Inc = getDerived().TransformExpr(S->getInc());
+ if (Inc.isInvalid())
+ return StmtError();
+
+ StmtResult LoopVar = getDerived().TransformStmt(S->getLoopVarStmt());
+ if (LoopVar.isInvalid())
+ return StmtError();
+
+ StmtResult NewStmt = S;
+ if (getDerived().AlwaysRebuild() ||
+ Range.get() != S->getRangeStmt() ||
+ BeginEnd.get() != S->getBeginEndStmt() ||
+ Cond.get() != S->getCond() ||
+ Inc.get() != S->getInc() ||
+ LoopVar.get() != S->getLoopVarStmt())
+ NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
+ S->getColonLoc(), Range.get(),
+ BeginEnd.get(), Cond.get(),
+ Inc.get(), LoopVar.get(),
+ S->getRParenLoc());
+
+ StmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return StmtError();
+
+ // Body has changed but we didn't rebuild the for-range statement. Rebuild
+ // it now so we have a new statement to attach the body to.
+ if (Body.get() != S->getBody() && NewStmt.get() == S)
+ NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
+ S->getColonLoc(), Range.get(),
+ BeginEnd.get(), Cond.get(),
+ Inc.get(), LoopVar.get(),
+ S->getRParenLoc());
+
+ if (NewStmt.get() == S)
+ return SemaRef.Owned(S);
+
+ return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
+ StmtResult TryBlock; // = getDerived().TransformCompoundStmt(S->getTryBlock());
+ if(TryBlock.isInvalid()) return StmtError();
+
+ StmtResult Handler = getDerived().TransformSEHHandler(S->getHandler());
+ if(!getDerived().AlwaysRebuild() &&
+ TryBlock.get() == S->getTryBlock() &&
+ Handler.get() == S->getHandler())
+ return SemaRef.Owned(S);
+
+ return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(),
+ S->getTryLoc(),
+ TryBlock.take(),
+ Handler.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) {
+ StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock());
+ if(Block.isInvalid()) return StmtError();
+
+ return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(),
+ Block.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHExceptStmt(SEHExceptStmt *S) {
+ ExprResult FilterExpr = getDerived().TransformExpr(S->getFilterExpr());
+ if(FilterExpr.isInvalid()) return StmtError();
+
+ StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock());
+ if(Block.isInvalid()) return StmtError();
+
+ return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(),
+ FilterExpr.take(),
+ Block.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) {
+ if(isa<SEHFinallyStmt>(Handler))
+ return getDerived().TransformSEHFinallyStmt(cast<SEHFinallyStmt>(Handler));
+ else
+ return getDerived().TransformSEHExceptStmt(cast<SEHExceptStmt>(Handler));
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -5368,11 +5585,11 @@ TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
- NestedNameSpecifier *Qualifier = 0;
- if (E->getQualifier()) {
- Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange());
- if (!Qualifier)
+ NestedNameSpecifierLoc QualifierLoc;
+ if (E->getQualifierLoc()) {
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
+ if (!QualifierLoc)
return ExprError();
}
@@ -5390,7 +5607,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
}
if (!getDerived().AlwaysRebuild() &&
- Qualifier == E->getQualifier() &&
+ QualifierLoc == E->getQualifierLoc() &&
ND == E->getDecl() &&
NameInfo.getName() == E->getDecl()->getDeclName() &&
!E->hasExplicitTemplateArgs()) {
@@ -5413,8 +5630,8 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
return ExprError();
}
- return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(),
- ND, NameInfo, TemplateArgs);
+ return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo,
+ TemplateArgs);
}
template<typename Derived>
@@ -5449,6 +5666,42 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
+ ExprResult ControllingExpr =
+ getDerived().TransformExpr(E->getControllingExpr());
+ if (ControllingExpr.isInvalid())
+ return ExprError();
+
+ llvm::SmallVector<Expr *, 4> AssocExprs;
+ llvm::SmallVector<TypeSourceInfo *, 4> AssocTypes;
+ for (unsigned i = 0; i != E->getNumAssocs(); ++i) {
+ TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i);
+ if (TS) {
+ TypeSourceInfo *AssocType = getDerived().TransformType(TS);
+ if (!AssocType)
+ return ExprError();
+ AssocTypes.push_back(AssocType);
+ } else {
+ AssocTypes.push_back(0);
+ }
+
+ ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i));
+ if (AssocExpr.isInvalid())
+ return ExprError();
+ AssocExprs.push_back(AssocExpr.release());
+ }
+
+ return getDerived().RebuildGenericSelectionExpr(E->getGenericLoc(),
+ E->getDefaultLoc(),
+ E->getRParenLoc(),
+ ControllingExpr.release(),
+ AssocTypes.data(),
+ AssocExprs.data(),
+ E->getNumAssocs());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
@@ -5498,8 +5751,8 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
const Node &ON = E->getComponent(I);
Component Comp;
Comp.isBrackets = true;
- Comp.LocStart = ON.getRange().getBegin();
- Comp.LocEnd = ON.getRange().getEnd();
+ Comp.LocStart = ON.getSourceRange().getBegin();
+ Comp.LocEnd = ON.getSourceRange().getEnd();
switch (ON.getKind()) {
case Node::Array: {
Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex());
@@ -5552,7 +5805,8 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) {
template<typename Derived>
ExprResult
-TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *E) {
if (E->isArgumentType()) {
TypeSourceInfo *OldT = E->getArgumentTypeInfo();
@@ -5563,9 +5817,9 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (!getDerived().AlwaysRebuild() && OldT == NewT)
return SemaRef.Owned(E);
- return getDerived().RebuildSizeOfAlignOf(NewT, E->getOperatorLoc(),
- E->isSizeOf(),
- E->getSourceRange());
+ return getDerived().RebuildUnaryExprOrTypeTrait(NewT, E->getOperatorLoc(),
+ E->getKind(),
+ E->getSourceRange());
}
ExprResult SubExpr;
@@ -5583,9 +5837,10 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
return SemaRef.Owned(E);
}
- return getDerived().RebuildSizeOfAlignOf(SubExpr.get(), E->getOperatorLoc(),
- E->isSizeOf(),
- E->getSourceRange());
+ return getDerived().RebuildUnaryExprOrTypeTrait(SubExpr.get(),
+ E->getOperatorLoc(),
+ E->getKind(),
+ E->getSourceRange());
}
template<typename Derived>
@@ -5646,12 +5901,12 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
if (Base.isInvalid())
return ExprError();
- NestedNameSpecifier *Qualifier = 0;
+ NestedNameSpecifierLoc QualifierLoc;
if (E->hasQualifier()) {
- Qualifier
- = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange());
- if (Qualifier == 0)
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
+
+ if (!QualifierLoc)
return ExprError();
}
@@ -5673,7 +5928,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase() &&
- Qualifier == E->getQualifier() &&
+ QualifierLoc == E->getQualifierLoc() &&
Member == E->getMemberDecl() &&
FoundDecl == E->getFoundDecl() &&
!E->hasExplicitTemplateArgs()) {
@@ -5706,8 +5961,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
E->isArrow(),
- Qualifier,
- E->getQualifierRange(),
+ QualifierLoc,
E->getMemberNameInfo(),
Member,
FoundDecl,
@@ -6333,7 +6587,7 @@ TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) {
TInfo == E->getTypeOperandSourceInfo())
return SemaRef.Owned(E);
- return getDerived().RebuildCXXTypeidExpr(E->getType(),
+ return getDerived().RebuildCXXUuidofExpr(E->getType(),
E->getLocStart(),
TInfo,
E->getLocEnd());
@@ -6623,8 +6877,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
if (E->getDestroyedTypeInfo()) {
TypeSourceInfo *DestroyedTypeInfo
= getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(),
- ObjectType, 0,
- QualifierLoc.getNestedNameSpecifier());
+ ObjectType, 0, SS);
if (!DestroyedTypeInfo)
return ExprError();
Destroyed = DestroyedTypeInfo;
@@ -6670,8 +6923,6 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnresolvedLookupExpr(
UnresolvedLookupExpr *Old) {
- TemporaryBase Rebase(*this, Old->getNameLoc(), DeclarationName());
-
LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(),
Sema::LookupOrdinaryName);
@@ -6708,14 +6959,13 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
// Rebuild the nested-name qualifier, if present.
CXXScopeSpec SS;
- NestedNameSpecifier *Qualifier = 0;
- if (Old->getQualifier()) {
- Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(),
- Old->getQualifierRange());
- if (!Qualifier)
+ if (Old->getQualifierLoc()) {
+ NestedNameSpecifierLoc QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(Old->getQualifierLoc());
+ if (!QualifierLoc)
return ExprError();
- SS.MakeTrivial(SemaRef.Context, Qualifier, Old->getQualifierRange());
+ SS.Adopt(QualifierLoc);
}
if (Old->getNamingClass()) {
@@ -6785,6 +7035,53 @@ TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo());
+ if (!T)
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getQueriedTypeSourceInfo())
+ return SemaRef.Owned(E);
+
+ ExprResult SubExpr;
+ {
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ SubExpr = getDerived().TransformExpr(E->getDimensionExpression());
+ if (SubExpr.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getDimensionExpression())
+ return SemaRef.Owned(E);
+ }
+
+ return getDerived().RebuildArrayTypeTrait(E->getTrait(),
+ E->getLocStart(),
+ T,
+ SubExpr.get(),
+ E->getLocEnd());
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformExpressionTraitExpr(ExpressionTraitExpr *E) {
+ ExprResult SubExpr;
+ {
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ SubExpr = getDerived().TransformExpr(E->getQueriedExpression());
+ if (SubExpr.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getQueriedExpression())
+ return SemaRef.Owned(E);
+ }
+
+ return getDerived().RebuildExpressionTrait(
+ E->getTrait(), E->getLocStart(), SubExpr.get(), E->getLocEnd());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *E) {
NestedNameSpecifierLoc QualifierLoc
@@ -6994,16 +7291,16 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
// the member name.
NamedDecl *FirstQualifierInScope
= getDerived().TransformFirstQualifierInScope(
- E->getFirstQualifierFoundInScope(),
- E->getQualifierRange().getBegin());
+ E->getFirstQualifierFoundInScope(),
+ E->getQualifierLoc().getBeginLoc());
- NestedNameSpecifier *Qualifier = 0;
+ NestedNameSpecifierLoc QualifierLoc;
if (E->getQualifier()) {
- Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange(),
- ObjectType,
- FirstQualifierInScope);
- if (!Qualifier)
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc(),
+ ObjectType,
+ FirstQualifierInScope);
+ if (!QualifierLoc)
return ExprError();
}
@@ -7022,7 +7319,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
if (!getDerived().AlwaysRebuild() &&
Base.get() == OldBase &&
BaseType == E->getBaseType() &&
- Qualifier == E->getQualifier() &&
+ QualifierLoc == E->getQualifierLoc() &&
NameInfo.getName() == E->getMember() &&
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
return SemaRef.Owned(E);
@@ -7031,8 +7328,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
BaseType,
E->isArrow(),
E->getOperatorLoc(),
- Qualifier,
- E->getQualifierRange(),
+ QualifierLoc,
FirstQualifierInScope,
NameInfo,
/*TemplateArgs*/ 0);
@@ -7048,8 +7344,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
BaseType,
E->isArrow(),
E->getOperatorLoc(),
- Qualifier,
- E->getQualifierRange(),
+ QualifierLoc,
FirstQualifierInScope,
NameInfo,
&TransArgs);
@@ -7070,12 +7365,11 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
BaseType = getDerived().TransformType(Old->getBaseType());
}
- NestedNameSpecifier *Qualifier = 0;
- if (Old->getQualifier()) {
- Qualifier
- = getDerived().TransformNestedNameSpecifier(Old->getQualifier(),
- Old->getQualifierRange());
- if (Qualifier == 0)
+ NestedNameSpecifierLoc QualifierLoc;
+ if (Old->getQualifierLoc()) {
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(Old->getQualifierLoc());
+ if (!QualifierLoc)
return ExprError();
}
@@ -7093,8 +7387,10 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
// This can happen because of dependent hiding.
if (isa<UsingShadowDecl>(*I))
continue;
- else
+ else {
+ R.clear();
return ExprError();
+ }
}
// Expand using declarations.
@@ -7143,8 +7439,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
BaseType,
Old->getOperatorLoc(),
Old->isArrow(),
- Qualifier,
- Old->getQualifierRange(),
+ QualifierLoc,
FirstQualifierInScope,
R,
(Old->hasExplicitTemplateArgs()
@@ -7490,8 +7785,6 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
- NestedNameSpecifier *Qualifier = 0;
-
ValueDecl *ND
= cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getLocation(),
E->getDecl()));
@@ -7508,7 +7801,7 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
}
DeclarationNameInfo NameInfo(E->getDecl()->getDeclName(), E->getLocation());
- return getDerived().RebuildDeclRefExpr(Qualifier, SourceLocation(),
+ return getDerived().RebuildDeclRefExpr(NestedNameSpecifierLoc(),
ND, NameInfo, 0);
}
@@ -7720,88 +8013,33 @@ template<typename Derived>
QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
TemplateName Template,
SourceLocation TemplateNameLoc,
- const TemplateArgumentListInfo &TemplateArgs) {
+ TemplateArgumentListInfo &TemplateArgs) {
return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
}
template<typename Derived>
-NestedNameSpecifier *
-TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- IdentifierInfo &II,
- QualType ObjectType,
- NamedDecl *FirstQualifierInScope) {
- CXXScopeSpec SS;
- // FIXME: The source location information is all wrong.
- SS.MakeTrivial(SemaRef.Context, Prefix, Range);
- if (SemaRef.BuildCXXNestedNameSpecifier(0, II, /*FIXME:*/Range.getBegin(),
- /*FIXME:*/Range.getEnd(),
- ObjectType, false,
- SS, FirstQualifierInScope,
- false))
- return 0;
-
- return SS.getScopeRep();
-}
-
-template<typename Derived>
-NestedNameSpecifier *
-TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- NamespaceDecl *NS) {
- return NestedNameSpecifier::Create(SemaRef.Context, Prefix, NS);
-}
-
-template<typename Derived>
-NestedNameSpecifier *
-TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- NamespaceAliasDecl *Alias) {
- return NestedNameSpecifier::Create(SemaRef.Context, Prefix, Alias);
-}
-
-template<typename Derived>
-NestedNameSpecifier *
-TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
- SourceRange Range,
- bool TemplateKW,
- QualType T) {
- if (T->isDependentType() || T->isRecordType() ||
- (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
- assert(!T.hasLocalQualifiers() && "Can't get cv-qualifiers here");
- return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW,
- T.getTypePtr());
- }
-
- SemaRef.Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
- return 0;
-}
-
-template<typename Derived>
TemplateName
-TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
bool TemplateKW,
TemplateDecl *Template) {
- return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW,
+ return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW,
Template);
}
template<typename Derived>
TemplateName
-TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- const IdentifierInfo &II,
+TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
+ const IdentifierInfo &Name,
+ SourceLocation NameLoc,
QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
- CXXScopeSpec SS;
- SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
- UnqualifiedId Name;
- Name.setIdentifier(&II, /*FIXME:*/getDerived().getBaseLocation());
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(&Name, NameLoc);
Sema::TemplateTy Template;
getSema().ActOnDependentTemplateName(/*Scope=*/0,
- /*FIXME:*/getDerived().getBaseLocation(),
+ /*FIXME:*/SourceLocation(),
SS,
- Name,
+ TemplateName,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
Template);
@@ -7810,18 +8048,17 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
template<typename Derived>
TemplateName
-TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
OverloadedOperatorKind Operator,
+ SourceLocation NameLoc,
QualType ObjectType) {
- CXXScopeSpec SS;
- SS.MakeTrivial(SemaRef.Context, Qualifier, SourceRange(getDerived().getBaseLocation()));
UnqualifiedId Name;
- SourceLocation SymbolLocations[3]; // FIXME: Bogus location information.
- Name.setOperatorFunctionId(/*FIXME:*/getDerived().getBaseLocation(),
- Operator, SymbolLocations);
+ // FIXME: Bogus location information.
+ SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc };
+ Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations);
Sema::TemplateTy Template;
getSema().ActOnDependentTemplateName(/*Scope=*/0,
- /*FIXME:*/getDerived().getBaseLocation(),
+ /*FIXME:*/SourceLocation(),
SS,
Name,
ParsedType::make(ObjectType),
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 1e0a7c454675..3570737d11bc 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -44,8 +44,7 @@ class TypeLocBuilder {
public:
TypeLocBuilder()
- : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity)
- {}
+ : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
~TypeLocBuilder() {
if (Buffer != InlineBuffer)
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 5e94f59ad493..782e5c6aa79f 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -50,7 +50,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break;
case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
+ case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break;
case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
+ case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
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;
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index d4166998d1cf..838df13f2d8f 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -23,7 +23,9 @@ namespace serialization {
enum DeclUpdateKind {
UPD_CXX_SET_DEFINITIONDATA,
UPD_CXX_ADDED_IMPLICIT_MEMBER,
- UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION
+ UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
+ UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER
};
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index c3953ba554dc..d2e41a96c946 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Lex/MacroInfo.h"
@@ -36,6 +37,7 @@
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
+#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -77,6 +79,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_BENIGN(Digraphs);
PARSE_LANGOPT_BENIGN(HexFloats);
PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99);
+ PARSE_LANGOPT_IMPORTANT(C1X, diag::warn_pch_c1x);
PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions);
PARSE_LANGOPT_BENIGN(MSCVersion);
PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus);
@@ -126,6 +129,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level);
PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline);
PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline);
+ PARSE_LANGOPT_IMPORTANT(Deprecated, diag::warn_pch_deprecated);
PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control);
PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed);
PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar);
@@ -953,8 +957,16 @@ bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
return false;
}
-void ASTReader::Error(const char *Msg) {
- Diag(diag::err_fe_pch_malformed) << Msg;
+void ASTReader::Error(llvm::StringRef Msg) {
+ Error(diag::err_fe_pch_malformed, Msg);
+}
+
+void ASTReader::Error(unsigned DiagID,
+ llvm::StringRef Arg1, llvm::StringRef Arg2) {
+ if (Diags.isDiagnosticInFlight())
+ Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
+ else
+ Diag(DiagID) << Arg1 << Arg2;
}
/// \brief Tell the AST listener about the predefines buffers in the chain.
@@ -1306,8 +1318,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
|| (time_t)Record[5] != File->getModificationTime()
#endif
)) {
- Diag(diag::err_fe_pch_file_modified)
- << Filename;
+ Error(diag::err_fe_pch_file_modified, Filename);
return Failure;
}
@@ -2460,20 +2471,26 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName,
if (CurrentDir.empty()) CurrentDir = ".";
}
- // Open the AST file.
- //
- // FIXME: This shouldn't be here, we should just take a raw_ostream.
- std::string ErrStr;
- llvm::error_code ec;
- if (FileName == "-") {
- ec = llvm::MemoryBuffer::getSTDIN(F.Buffer);
- if (ec)
- ErrStr = ec.message();
- } else
- F.Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrStr));
- if (!F.Buffer) {
- Error(ErrStr.c_str());
- return IgnorePCH;
+ if (!ASTBuffers.empty()) {
+ F.Buffer.reset(ASTBuffers.back());
+ ASTBuffers.pop_back();
+ assert(F.Buffer && "Passed null buffer");
+ } else {
+ // Open the AST file.
+ //
+ // FIXME: This shouldn't be here, we should just take a raw_ostream.
+ std::string ErrStr;
+ llvm::error_code ec;
+ if (FileName == "-") {
+ ec = llvm::MemoryBuffer::getSTDIN(F.Buffer);
+ if (ec)
+ ErrStr = ec.message();
+ } else
+ F.Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrStr));
+ if (!F.Buffer) {
+ Error(ErrStr.c_str());
+ return IgnorePCH;
+ }
}
// Initialize the stream
@@ -2668,6 +2685,11 @@ void ASTReader::InitializeContext(ASTContext &Ctx) {
if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED])
Context->setInt128Installed();
+ if (unsigned AutoDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_DEDUCT])
+ Context->AutoDeductTy = GetType(AutoDeduct);
+ if (unsigned AutoRRefDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_RREF_DEDUCT])
+ Context->AutoRRefDeductTy = GetType(AutoRRefDeduct);
+
ReadPragmaDiagnosticMappings(Context->getDiagnostics());
// If there were any CUDA special declarations, deserialize them.
@@ -2786,6 +2808,7 @@ bool ASTReader::ParseLanguageOptions(
PARSE_LANGOPT(Digraphs);
PARSE_LANGOPT(HexFloats);
PARSE_LANGOPT(C99);
+ PARSE_LANGOPT(C1X);
PARSE_LANGOPT(Microsoft);
PARSE_LANGOPT(CPlusPlus);
PARSE_LANGOPT(CPlusPlus0x);
@@ -2823,6 +2846,7 @@ bool ASTReader::ParseLanguageOptions(
PARSE_LANGOPT(PICLevel);
PARSE_LANGOPT(GNUInline);
PARSE_LANGOPT(NoInline);
+ PARSE_LANGOPT(Deprecated);
PARSE_LANGOPT(AccessControl);
PARSE_LANGOPT(CharIsSigned);
PARSE_LANGOPT(ShortWChar);
@@ -2836,7 +2860,9 @@ bool ASTReader::ParseLanguageOptions(
PARSE_LANGOPT(CUDA);
PARSE_LANGOPT(CatchUndefined);
PARSE_LANGOPT(DefaultFPContract);
- // FIXME: Missing ElideConstructors?!
+ PARSE_LANGOPT(ElideConstructors);
+ PARSE_LANGOPT(SpellChecking);
+ PARSE_LANGOPT(MRTD);
#undef PARSE_LANGOPT
return Listener->ReadLanguageOptions(LangOpts);
@@ -2999,12 +3025,12 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
}
case TYPE_LVALUE_REFERENCE: {
- if (Record.size() != 1) {
+ if (Record.size() != 2) {
Error("Incorrect encoding of lvalue reference type");
return QualType();
}
QualType PointeeType = GetType(Record[0]);
- return Context->getLValueReferenceType(PointeeType);
+ return Context->getLValueReferenceType(PointeeType, Record[1]);
}
case TYPE_RVALUE_REFERENCE: {
@@ -3082,12 +3108,12 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
}
case TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 4) {
+ if (Record.size() != 5) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
QualType ResultType = GetType(Record[0]);
- FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]);
+ FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], (CallingConv)Record[4]);
return Context->getFunctionNoProtoType(ResultType, Info);
}
@@ -3096,10 +3122,11 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
- /*regparm*/ Record[2],
- static_cast<CallingConv>(Record[3]));
+ /*hasregparm*/ Record[2],
+ /*regparm*/ Record[3],
+ static_cast<CallingConv>(Record[4]));
- unsigned Idx = 4;
+ unsigned Idx = 5;
unsigned NumParams = Record[Idx++];
llvm::SmallVector<QualType, 16> ParamTypes;
for (unsigned I = 0; I != NumParams; ++I)
@@ -3108,13 +3135,18 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
EPI.Variadic = Record[Idx++];
EPI.TypeQuals = Record[Idx++];
EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
- EPI.HasExceptionSpec = Record[Idx++];
- EPI.HasAnyExceptionSpec = Record[Idx++];
- EPI.NumExceptions = Record[Idx++];
- llvm::SmallVector<QualType, 2> Exceptions;
- for (unsigned I = 0; I != EPI.NumExceptions; ++I)
- Exceptions.push_back(GetType(Record[Idx++]));
- EPI.Exceptions = Exceptions.data();
+ ExceptionSpecificationType EST =
+ static_cast<ExceptionSpecificationType>(Record[Idx++]);
+ EPI.ExceptionSpecType = EST;
+ if (EST == EST_Dynamic) {
+ EPI.NumExceptions = Record[Idx++];
+ llvm::SmallVector<QualType, 2> Exceptions;
+ for (unsigned I = 0; I != EPI.NumExceptions; ++I)
+ Exceptions.push_back(GetType(Record[Idx++]));
+ EPI.Exceptions = Exceptions.data();
+ } else if (EST == EST_ComputedNoexcept) {
+ EPI.NoexceptExpr = ReadExpr(*Loc.F);
+ }
return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
EPI);
}
@@ -3128,7 +3160,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
Error("incorrect encoding of typedef type");
return QualType();
}
- TypedefDecl *Decl = cast<TypedefDecl>(GetDecl(Record[0]));
+ TypedefNameDecl *Decl = cast<TypedefNameDecl>(GetDecl(Record[0]));
QualType Canonical = GetType(Record[1]);
if (!Canonical.isNull())
Canonical = Context->getCanonicalType(Canonical);
@@ -3271,8 +3303,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
unsigned Depth = Record[Idx++];
unsigned Index = Record[Idx++];
bool Pack = Record[Idx++];
- IdentifierInfo *Name = GetIdentifierInfo(Record, Idx);
- return Context->getTemplateTypeParmType(Depth, Index, Pack, Name);
+ TemplateTypeParmDecl *D =
+ cast_or_null<TemplateTypeParmDecl>(GetDecl(Record[Idx++]));
+ return Context->getTemplateTypeParmType(Depth, Index, Pack, D);
}
case TYPE_DEPENDENT_NAME: {
@@ -3398,6 +3431,7 @@ void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
}
void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
TL.setStarLoc(ReadSourceLocation(Record, Idx));
+ TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
}
void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
TL.setLBracketLoc(ReadSourceLocation(Record, Idx));
@@ -3431,8 +3465,8 @@ void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
- TL.setLParenLoc(ReadSourceLocation(Record, Idx));
- TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx));
+ TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
TL.setTrailingReturn(Record[Idx++]);
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
@@ -3517,20 +3551,20 @@ void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
}
void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
TL.setKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setQualifierRange(Reader.ReadSourceRange(F, Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
}
void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
TL.setKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setQualifierRange(Reader.ReadSourceRange(F, Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
TL.setKeywordLoc(ReadSourceLocation(Record, Idx));
- TL.setQualifierRange(Reader.ReadSourceRange(F, Record, Idx));
+ TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
TL.setNameLoc(ReadSourceLocation(Record, Idx));
TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
@@ -3605,7 +3639,9 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break;
case PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break;
case PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break;
+ case PREDEF_TYPE_BOUND_MEMBER: T = Context->BoundMemberTy; break;
case PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break;
+ case PREDEF_TYPE_UNKNOWN_ANY: T = Context->UnknownAnyTy; break;
case PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break;
case PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break;
case PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break;
@@ -3675,16 +3711,18 @@ ASTReader::GetTemplateArgumentLocInfo(PerFileData &F,
case TemplateArgument::Type:
return GetTypeSourceInfo(F, Record, Index);
case TemplateArgument::Template: {
- SourceRange QualifierRange = ReadSourceRange(F, Record, Index);
+ NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
+ Index);
SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
- return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc,
+ return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
SourceLocation());
}
case TemplateArgument::TemplateExpansion: {
- SourceRange QualifierRange = ReadSourceRange(F, Record, Index);
+ NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record,
+ Index);
SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index);
SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index);
- return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc,
+ return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc,
EllipsisLoc);
}
case TemplateArgument::Null:
@@ -3722,11 +3760,13 @@ ASTReader::GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID) {
--ID;
uint64_t Offset = 0;
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (ID < Chain[I]->LocalNumCXXBaseSpecifiers)
- return Offset + Chain[I]->CXXBaseSpecifiersOffsets[ID];
+ PerFileData &F = *Chain[N - I - 1];
+
+ if (ID < F.LocalNumCXXBaseSpecifiers)
+ return Offset + F.CXXBaseSpecifiersOffsets[ID];
- ID -= Chain[I]->LocalNumCXXBaseSpecifiers;
- Offset += Chain[I]->SizeInBits;
+ ID -= F.LocalNumCXXBaseSpecifiers;
+ Offset += F.SizeInBits;
}
assert(false && "CXXBaseSpecifiers not found");
@@ -3737,14 +3777,14 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
// Figure out which AST file contains this offset.
PerFileData *F = 0;
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (Offset < Chain[I]->SizeInBits) {
- F = Chain[I];
+ if (Offset < Chain[N - I - 1]->SizeInBits) {
+ F = Chain[N - I - 1];
break;
}
- Offset -= Chain[I]->SizeInBits;
+ Offset -= Chain[N - I - 1]->SizeInBits;
}
-
+
if (!F) {
Error("Malformed AST file: C++ base specifiers at impossible offset");
return 0;
@@ -4014,6 +4054,23 @@ void ASTReader::PrintStats() {
std::fprintf(stderr, "\n");
}
+/// Return the amount of memory used by memory buffers, breaking down
+/// by heap-backed versus mmap'ed memory.
+void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
+ for (unsigned i = 0, e = Chain.size(); i != e; ++i)
+ if (llvm::MemoryBuffer *buf = Chain[i]->Buffer.get()) {
+ size_t bytes = buf->getBufferSize();
+ switch (buf->getBufferKind()) {
+ case llvm::MemoryBuffer::MemoryBuffer_Malloc:
+ sizes.malloc_bytes += bytes;
+ break;
+ case llvm::MemoryBuffer::MemoryBuffer_MMap:
+ sizes.mmap_bytes += bytes;
+ break;
+ }
+ }
+}
+
void ASTReader::InitializeSema(Sema &S) {
SemaObj = &S;
S.ExternalSource = this;
@@ -4054,7 +4111,7 @@ void ASTReader::InitializeSema(Sema &S) {
// and add them to Sema's vector of such declarations.
for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I)
SemaObj->ExtVectorDecls.push_back(
- cast<TypedefDecl>(GetDecl(ExtVectorDecls[I])));
+ cast<TypedefNameDecl>(GetDecl(ExtVectorDecls[I])));
// FIXME: Do VTable uses and dynamic classes deserialize too much ?
// Can we cut them down before writing them ?
@@ -4087,22 +4144,22 @@ void ASTReader::InitializeSema(Sema &S) {
SemaObj->ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
}
}
-
- // If there were any pending implicit instantiations, deserialize them
- // and add them to Sema's queue of such instantiations.
- assert(F->PendingInstantiations.size() % 2 == 0 &&
- "Expected pairs of entries");
- for (unsigned Idx = 0, N = F->PendingInstantiations.size(); Idx < N;) {
- ValueDecl *D=cast<ValueDecl>(GetDecl(F->PendingInstantiations[Idx++]));
- SourceLocation Loc = ReadSourceLocation(*F, F->PendingInstantiations,Idx);
- SemaObj->PendingInstantiations.push_back(std::make_pair(D, Loc));
- }
}
- // The two special data sets below always come from the most recent PCH,
+ // The special data sets below always come from the most recent PCH,
// which is at the front of the chain.
PerFileData &F = *Chain.front();
+ // If there were any pending implicit instantiations, deserialize them
+ // and add them to Sema's queue of such instantiations.
+ assert(F.PendingInstantiations.size() % 2 == 0 &&
+ "Expected pairs of entries");
+ for (unsigned Idx = 0, N = F.PendingInstantiations.size(); Idx < N;) {
+ ValueDecl *D=cast<ValueDecl>(GetDecl(F.PendingInstantiations[Idx++]));
+ SourceLocation Loc = ReadSourceLocation(F, F.PendingInstantiations,Idx);
+ SemaObj->PendingInstantiations.push_back(std::make_pair(D, Loc));
+ }
+
// If there were any weak undeclared identifiers, deserialize them and add to
// Sema's list of weak undeclared identifiers.
if (!WeakUndeclaredIdentifiers.empty()) {
@@ -4354,8 +4411,8 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) {
return IdentifiersLoaded[ID];
}
-void ASTReader::ReadSLocEntry(unsigned ID) {
- ReadSLocEntryRecord(ID);
+bool ASTReader::ReadSLocEntry(unsigned ID) {
+ return ReadSLocEntryRecord(ID) != Success;
}
Selector ASTReader::DecodeSelector(unsigned ID) {
@@ -4762,103 +4819,57 @@ NestedNameSpecifierLoc
ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record,
unsigned &Idx) {
unsigned N = Record[Idx++];
- NestedNameSpecifier *NNS = 0, *Prev = 0;
- llvm::SmallVector<char, 32> LocationData;
+ NestedNameSpecifierLocBuilder Builder;
for (unsigned I = 0; I != N; ++I) {
NestedNameSpecifier::SpecifierKind Kind
= (NestedNameSpecifier::SpecifierKind)Record[Idx++];
switch (Kind) {
case NestedNameSpecifier::Identifier: {
- // Nested-name-specifier
- IdentifierInfo *II = GetIdentifierInfo(Record, Idx);
- NNS = NestedNameSpecifier::Create(*Context, Prev, II);
-
- // Location information
+ IdentifierInfo *II = GetIdentifierInfo(Record, Idx);
SourceRange Range = ReadSourceRange(F, Record, Idx);
- unsigned RawStart = Range.getBegin().getRawEncoding();
- unsigned RawEnd = Range.getEnd().getRawEncoding();
- LocationData.append(reinterpret_cast<char*>(&RawStart),
- reinterpret_cast<char*>(&RawStart) +sizeof(unsigned));
- LocationData.append(reinterpret_cast<char*>(&RawEnd),
- reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned));
+ Builder.Extend(*Context, II, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::Namespace: {
- // Nested-name-specifier
NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++]));
- NNS = NestedNameSpecifier::Create(*Context, Prev, NS);
-
- // Location information
SourceRange Range = ReadSourceRange(F, Record, Idx);
- unsigned RawStart = Range.getBegin().getRawEncoding();
- unsigned RawEnd = Range.getEnd().getRawEncoding();
- LocationData.append(reinterpret_cast<char*>(&RawStart),
- reinterpret_cast<char*>(&RawStart) +sizeof(unsigned));
- LocationData.append(reinterpret_cast<char*>(&RawEnd),
- reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned));
+ Builder.Extend(*Context, NS, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::NamespaceAlias: {
- // Nested-name-specifier
NamespaceAliasDecl *Alias
= cast<NamespaceAliasDecl>(GetDecl(Record[Idx++]));
- NNS = NestedNameSpecifier::Create(*Context, Prev, Alias);
-
- // Location information
SourceRange Range = ReadSourceRange(F, Record, Idx);
- unsigned RawStart = Range.getBegin().getRawEncoding();
- unsigned RawEnd = Range.getEnd().getRawEncoding();
- LocationData.append(reinterpret_cast<char*>(&RawStart),
- reinterpret_cast<char*>(&RawStart) +sizeof(unsigned));
- LocationData.append(reinterpret_cast<char*>(&RawEnd),
- reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned));
-
+ Builder.Extend(*Context, Alias, Range.getBegin(), Range.getEnd());
break;
}
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- // Nested-name-specifier
bool Template = Record[Idx++];
TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx);
if (!T)
return NestedNameSpecifierLoc();
- NNS = NestedNameSpecifier::Create(*Context, Prev, Template,
- T->getType().getTypePtr());
-
- // Location information.
SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
- unsigned RawLocation = ColonColonLoc.getRawEncoding();
- void *OpaqueTypeData = T->getTypeLoc().getOpaqueData();
- LocationData.append(reinterpret_cast<char*>(&OpaqueTypeData),
- (reinterpret_cast<char*>(&OpaqueTypeData)
- + sizeof(void *)));
- LocationData.append(reinterpret_cast<char*>(&RawLocation),
- (reinterpret_cast<char*>(&RawLocation) +
- sizeof(unsigned)));
+
+ // FIXME: 'template' keyword location not saved anywhere, so we fake it.
+ Builder.Extend(*Context,
+ Template? T->getTypeLoc().getBeginLoc() : SourceLocation(),
+ T->getTypeLoc(), ColonColonLoc);
break;
}
case NestedNameSpecifier::Global: {
- // Nested-name-specifier
- NNS = NestedNameSpecifier::GlobalSpecifier(*Context);
-
SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx);
- unsigned RawLocation = ColonColonLoc.getRawEncoding();
- LocationData.append(reinterpret_cast<char*>(&RawLocation),
- (reinterpret_cast<char*>(&RawLocation) +
- sizeof(unsigned)));
+ Builder.MakeGlobal(*Context, ColonColonLoc);
break;
}
}
- Prev = NNS;
}
- void *Mem = Context->Allocate(LocationData.size(), llvm::alignOf<void*>());
- memcpy(Mem, LocationData.data(), LocationData.size());
- return NestedNameSpecifierLoc(NNS, Mem);
+ return Builder.getWithLocInContext(*Context);
}
SourceRange
@@ -4897,6 +4908,18 @@ std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) {
return Result;
}
+VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
+ unsigned &Idx) {
+ unsigned Major = Record[Idx++];
+ unsigned Minor = Record[Idx++];
+ unsigned Subminor = Record[Idx++];
+ if (Minor == 0)
+ return VersionTuple(Major);
+ if (Subminor == 0)
+ return VersionTuple(Major, Minor - 1);
+ return VersionTuple(Major, Minor - 1, Subminor - 1);
+}
+
CXXTemporary *ASTReader::ReadCXXTemporary(const RecordData &Record,
unsigned &Idx) {
CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++]));
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 493ccbad8618..3a825de6e6d8 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -38,6 +38,9 @@ namespace clang {
const RecordData &Record;
unsigned &Idx;
TypeID TypeIDForTypeDecl;
+
+ DeclID DeclContextIDForTemplateParmDecl;
+ DeclID LexicalDeclContextIDForTemplateParmDecl;
uint64_t GetCurrentCursorOffset();
SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
@@ -79,7 +82,8 @@ namespace clang {
void Visit(Decl *D);
- void UpdateDecl(Decl *D, const RecordData &Record);
+ void UpdateDecl(Decl *D, ASTReader::PerFileData &Module,
+ const RecordData &Record);
void VisitDecl(Decl *D);
void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
@@ -90,6 +94,7 @@ namespace clang {
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *TD);
void VisitTypedefDecl(TypedefDecl *TD);
+ void VisitTypeAliasDecl(TypeAliasDecl *TD);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
void VisitTagDecl(TagDecl *TD);
void VisitEnumDecl(EnumDecl *ED);
@@ -175,13 +180,32 @@ void ASTDeclReader::Visit(Decl *D) {
// FunctionDecl's body was written last after all other Stmts/Exprs.
if (Record[Idx++])
FD->setLazyBody(GetCurrentCursorOffset());
+ } else if (D->isTemplateParameter()) {
+ // If we have a fully initialized template parameter, we can now
+ // set its DeclContext.
+ D->setDeclContext(
+ cast_or_null<DeclContext>(
+ Reader.GetDecl(DeclContextIDForTemplateParmDecl)));
+ D->setLexicalDeclContext(
+ cast_or_null<DeclContext>(
+ Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl)));
}
}
void ASTDeclReader::VisitDecl(Decl *D) {
- D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
- D->setLexicalDeclContext(
+ if (D->isTemplateParameter()) {
+ // We don't want to deserialize the DeclContext of a template
+ // parameter immediately, because the template parameter might be
+ // used in the formulation of its DeclContext. Use the translation
+ // unit DeclContext as a placeholder.
+ DeclContextIDForTemplateParmDecl = Record[Idx++];
+ LexicalDeclContextIDForTemplateParmDecl = Record[Idx++];
+ D->setDeclContext(Reader.getContext()->getTranslationUnitDecl());
+ } else {
+ D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+ D->setLexicalDeclContext(
cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+ }
D->setLocation(ReadSourceLocation(Record, Idx));
D->setInvalidDecl(Record[Idx++]);
if (Record[Idx++]) { // hasAttrs
@@ -191,6 +215,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
}
D->setImplicit(Record[Idx++]);
D->setUsed(Record[Idx++]);
+ D->setReferenced(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
D->setPCHLevel(Record[Idx++] + (F.Type <= ASTReader::PCH));
}
@@ -208,6 +233,7 @@ void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) {
void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
VisitNamedDecl(TD);
+ TD->setLocStart(ReadSourceLocation(Record, Idx));
// Delay type reading until after we have fully initialized the decl.
TypeIDForTypeDecl = Record[Idx++];
}
@@ -217,6 +243,11 @@ void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
}
+void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
+ VisitTypeDecl(TD);
+ TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+}
+
void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
VisitTypeDecl(TD);
VisitRedeclarable(TD);
@@ -225,14 +256,13 @@ void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
TD->setDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
- TD->setTagKeywordLoc(ReadSourceLocation(Record, Idx));
if (Record[Idx++]) { // hasExtInfo
TagDecl::ExtInfo *Info = new (*Reader.getContext()) TagDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
- TD->TypedefDeclOrQualifier = Info;
+ TD->TypedefNameDeclOrQualifier = Info;
} else
- TD->setTypedefForAnonDecl(
- cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
+ TD->setTypedefNameForAnonDecl(
+ cast_or_null<TypedefNameDecl>(Reader.GetDecl(Record[Idx++])));
}
void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -272,6 +302,7 @@ void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
VisitValueDecl(DD);
+ DD->setInnerLocStart(ReadSourceLocation(Record, Idx));
if (Record[Idx++]) { // hasExtInfo
DeclaratorDecl::ExtInfo *Info
= new (*Reader.getContext()) DeclaratorDecl::ExtInfo();
@@ -655,12 +686,13 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VisitDeclaratorDecl(VD);
VisitRedeclarable(VD);
- VD->SClass = (StorageClass)Record[Idx++];
- VD->setStorageClassAsWritten((StorageClass)Record[Idx++]);
- VD->setThreadSpecified(Record[Idx++]);
- VD->setCXXDirectInitializer(Record[Idx++]);
- VD->setExceptionVariable(Record[Idx++]);
- VD->setNRVOVariable(Record[Idx++]);
+ VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
+ VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++];
+ VD->VarDeclBits.ThreadSpecified = Record[Idx++];
+ VD->VarDeclBits.HasCXXDirectInit = Record[Idx++];
+ VD->VarDeclBits.ExceptionVar = Record[Idx++];
+ VD->VarDeclBits.NRVOVariable = Record[Idx++];
+ VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
if (Record[Idx++])
VD->setInit(Reader.ReadExpr(F));
@@ -678,8 +710,19 @@ void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
VisitVarDecl(PD);
- PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
- PD->setHasInheritedDefaultArg(Record[Idx++]);
+ unsigned isObjCMethodParam = Record[Idx++];
+ unsigned scopeDepth = Record[Idx++];
+ unsigned scopeIndex = Record[Idx++];
+ unsigned declQualifier = Record[Idx++];
+ if (isObjCMethodParam) {
+ assert(scopeDepth == 0);
+ PD->setObjCMethodScopeInfo(scopeIndex);
+ PD->ParmVarDeclBits.ScopeDepthOrObjCQuals = declQualifier;
+ } else {
+ PD->setScopeInfo(scopeDepth, scopeIndex);
+ }
+ PD->ParmVarDeclBits.IsKNRPromoted = Record[Idx++];
+ PD->ParmVarDeclBits.HasInheritedDefaultArg = Record[Idx++];
if (Record[Idx++]) // hasUninstantiatedDefaultArg.
PD->setUninstantiatedDefaultArg(Reader.ReadExpr(F));
}
@@ -687,6 +730,7 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
VisitDecl(AD);
AD->setAsmString(cast<StringLiteral>(Reader.ReadExpr(F)));
+ AD->setRParenLoc(ReadSourceLocation(Record, Idx));
}
void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
@@ -720,19 +764,21 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
VisitDecl(D);
D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]);
- D->setHasBraces(Record[Idx++]);
+ D->setExternLoc(ReadSourceLocation(Record, Idx));
+ D->setRBraceLoc(ReadSourceLocation(Record, Idx));
}
void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
VisitNamedDecl(D);
+ D->setLocStart(ReadSourceLocation(Record, Idx));
}
void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
VisitNamedDecl(D);
D->IsInline = Record[Idx++];
- D->LBracLoc = ReadSourceLocation(Record, Idx);
- D->RBracLoc = ReadSourceLocation(Record, Idx);
+ D->LocStart = ReadSourceLocation(Record, Idx);
+ D->RBraceLoc = ReadSourceLocation(Record, Idx);
D->NextNamespace = Record[Idx++];
bool IsOriginal = Record[Idx++];
@@ -790,7 +836,6 @@ void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
UnresolvedUsingTypenameDecl *D) {
VisitTypeDecl(D);
- D->UsingLocation = ReadSourceLocation(Record, Idx);
D->TypenameLocation = ReadSourceLocation(Record, Idx);
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
}
@@ -807,10 +852,19 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.Empty = Record[Idx++];
Data.Polymorphic = Record[Idx++];
Data.Abstract = Record[Idx++];
+ Data.IsStandardLayout = Record[Idx++];
+ Data.HasNoNonEmptyBases = Record[Idx++];
+ Data.HasPrivateFields = Record[Idx++];
+ Data.HasProtectedFields = Record[Idx++];
+ Data.HasPublicFields = Record[Idx++];
Data.HasTrivialConstructor = Record[Idx++];
+ Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
Data.HasTrivialCopyConstructor = Record[Idx++];
+ Data.HasTrivialMoveConstructor = Record[Idx++];
Data.HasTrivialCopyAssignment = Record[Idx++];
+ Data.HasTrivialMoveAssignment = Record[Idx++];
Data.HasTrivialDestructor = Record[Idx++];
+ Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
Data.DeclaredDefaultConstructor = Record[Idx++];
Data.DeclaredCopyConstructor = Record[Idx++];
@@ -1172,7 +1226,6 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
VisitTypeDecl(D);
D->setDeclaredWithTypename(Record[Idx++]);
- D->setParameterPack(Record[Idx++]);
bool Inherited = Record[Idx++];
TypeSourceInfo *DefArg = GetTypeSourceInfo(Record, Idx);
@@ -1217,6 +1270,7 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
D->AssertExpr = Reader.ReadExpr(F);
D->Message = cast<StringLiteral>(Reader.ReadExpr(F));
+ D->RParenLoc = ReadSourceLocation(Record, Idx);
}
std::pair<uint64_t, uint64_t>
@@ -1398,7 +1452,12 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
D = Context->getTranslationUnitDecl();
break;
case DECL_TYPEDEF:
- D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ D = TypedefDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ 0, 0);
+ break;
+ case DECL_TYPEALIAS:
+ D = TypeAliasDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ 0, 0);
break;
case DECL_ENUM:
D = EnumDecl::Create(*Context, Decl::EmptyShell());
@@ -1411,19 +1470,20 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
0, llvm::APSInt());
break;
case DECL_FUNCTION:
- D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(),
- QualType(), 0);
+ D = FunctionDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ DeclarationName(), QualType(), 0);
break;
case DECL_LINKAGE_SPEC:
- D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(),
+ D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
(LinkageSpecDecl::LanguageIDs)0,
- false);
+ SourceLocation());
break;
case DECL_LABEL:
D = LabelDecl::Create(*Context, 0, SourceLocation(), 0);
break;
case DECL_NAMESPACE:
- D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0);
+ D = NamespaceDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0);
break;
case DECL_NAMESPACE_ALIAS:
D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(),
@@ -1460,8 +1520,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
D = CXXRecordDecl::Create(*Context, Decl::EmptyShell());
break;
case DECL_CXX_METHOD:
- D = CXXMethodDecl::Create(*Context, 0, DeclarationNameInfo(),
- QualType(), 0);
+ D = CXXMethodDecl::Create(*Context, 0, SourceLocation(),
+ DeclarationNameInfo(), QualType(), 0,
+ false, SC_None, false, SourceLocation());
break;
case DECL_CXX_CONSTRUCTOR:
D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell());
@@ -1482,38 +1543,38 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
D = FriendTemplateDecl::Create(*Context, Decl::EmptyShell());
break;
case DECL_CLASS_TEMPLATE:
- D = ClassTemplateDecl::Create(*Context, 0, SourceLocation(),
- DeclarationName(), 0, 0, 0);
+ D = ClassTemplateDecl::Create(*Context, Decl::EmptyShell());
break;
case DECL_CLASS_TEMPLATE_SPECIALIZATION:
D = ClassTemplateSpecializationDecl::Create(*Context, Decl::EmptyShell());
break;
case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
D = ClassTemplatePartialSpecializationDecl::Create(*Context,
- Decl::EmptyShell());
+ Decl::EmptyShell());
break;
case DECL_FUNCTION_TEMPLATE:
- D = FunctionTemplateDecl::Create(*Context, 0, SourceLocation(),
- DeclarationName(), 0, 0);
+ D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell());
break;
case DECL_TEMPLATE_TYPE_PARM:
D = TemplateTypeParmDecl::Create(*Context, Decl::EmptyShell());
break;
case DECL_NON_TYPE_TEMPLATE_PARM:
- D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0,0,0,
- QualType(), false, 0);
+ D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0, 0, 0, QualType(),
+ false, 0);
break;
case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
- D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
- 0, QualType(), 0, 0, Record[Idx++],
- 0);
+ D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0, 0, 0, QualType(),
+ 0, 0, Record[Idx++], 0);
break;
case DECL_TEMPLATE_TEMPLATE_PARM:
D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
false, 0, 0);
break;
case DECL_STATIC_ASSERT:
- D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0,
+ SourceLocation());
break;
case DECL_OBJC_METHOD:
@@ -1524,15 +1585,15 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0);
break;
case DECL_OBJC_IVAR:
- D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
- ObjCIvarDecl::None);
+ D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ 0, QualType(), 0, ObjCIvarDecl::None);
break;
case DECL_OBJC_PROTOCOL:
D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0);
break;
case DECL_OBJC_AT_DEFS_FIELD:
- D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), 0,
- QualType(), 0);
+ D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), 0, QualType(), 0);
break;
case DECL_OBJC_CLASS:
D = ObjCClassDecl::Create(*Context, 0, SourceLocation());
@@ -1564,16 +1625,16 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
SourceLocation());
break;
case DECL_FIELD:
- D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0,
- false);
+ D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
+ QualType(), 0, 0, false);
break;
case DECL_INDIRECTFIELD:
D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
0, 0);
break;
case DECL_VAR:
- D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
- SC_None, SC_None);
+ D = VarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
+ QualType(), 0, SC_None, SC_None);
break;
case DECL_IMPLICIT_PARAM:
@@ -1581,11 +1642,12 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
break;
case DECL_PARM_VAR:
- D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
- SC_None, SC_None, 0);
+ D = ParmVarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
+ QualType(), 0, SC_None, SC_None, 0);
break;
case DECL_FILE_SCOPE_ASM:
- D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0);
+ D = FileScopeAsmDecl::Create(*Context, 0, 0, SourceLocation(),
+ SourceLocation());
break;
case DECL_BLOCK:
D = BlockDecl::Create(*Context, 0, SourceLocation());
@@ -1614,22 +1676,26 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
// so we need to make sure we insert in front. For all other contexts,
// the vector is empty here anyway, so there's no loss in efficiency.
Infos.insert(Infos.begin(), Info);
+ }
- // Now add the pending visible updates for this decl context, if it has
- // any.
- DeclContextVisibleUpdatesPending::iterator I =
- PendingVisibleUpdates.find(ID);
- if (I != PendingVisibleUpdates.end()) {
- DeclContextVisibleUpdates &U = I->second;
- Info.LexicalDecls = 0;
- Info.NumLexicalDecls = 0;
- for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end();
- UI != UE; ++UI) {
- Info.NameLookupTableData = *UI;
- Infos.push_back(Info);
- }
- PendingVisibleUpdates.erase(I);
+ // Now add the pending visible updates for this decl context, if it has any.
+ DeclContextVisibleUpdatesPending::iterator I =
+ PendingVisibleUpdates.find(ID);
+ if (I != PendingVisibleUpdates.end()) {
+ // There are updates. This means the context has external visible
+ // storage, even if the original stored version didn't.
+ DC->setHasExternalVisibleStorage(true);
+ DeclContextVisibleUpdates &U = I->second;
+ DeclContextInfos &Infos = DeclContextOffsets[DC];
+ DeclContextInfo Info;
+ Info.LexicalDecls = 0;
+ Info.NumLexicalDecls = 0;
+ for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end();
+ UI != UE; ++UI) {
+ Info.NameLookupTableData = *UI;
+ Infos.push_back(Info);
}
+ PendingVisibleUpdates.erase(I);
}
}
assert(Idx == Record.size());
@@ -1652,7 +1718,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
unsigned RecCode = Cursor.ReadRecord(Code, Record);
(void)RecCode;
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
- Reader.UpdateDecl(D, Record);
+ Reader.UpdateDecl(D, *F, Record);
}
}
@@ -1666,7 +1732,8 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
return D;
}
-void ASTDeclReader::UpdateDecl(Decl *D, const RecordData &Record) {
+void ASTDeclReader::UpdateDecl(Decl *D, ASTReader::PerFileData &Module,
+ const RecordData &Record) {
unsigned Idx = 0;
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
@@ -1686,6 +1753,26 @@ void ASTDeclReader::UpdateDecl(Decl *D, const RecordData &Record) {
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's specializations set when loaded.
Reader.GetDecl(Record[Idx++]);
+ break;
+
+ case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
+ NamespaceDecl *Anon = cast<NamespaceDecl>(Reader.GetDecl(Record[Idx++]));
+ // Guard against these being loaded out of original order. Don't use
+ // getNextNamespace(), since it tries to access the context and can't in
+ // the middle of deserialization.
+ if (!Anon->NextNamespace) {
+ if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
+ TU->setAnonymousNamespace(Anon);
+ else
+ cast<NamespaceDecl>(D)->OrigOrAnonNamespace.setPointer(Anon);
+ }
+ break;
+ }
+
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
+ Reader.ReadSourceLocation(Module, Record, Idx));
+ break;
}
}
}
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 42f0b1aacef3..918db7e367c6 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -97,7 +97,7 @@ namespace clang {
void VisitParenListExpr(ParenListExpr *E);
void VisitUnaryOperator(UnaryOperator *E);
void VisitOffsetOfExpr(OffsetOfExpr *E);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
void VisitCallExpr(CallExpr *E);
void VisitMemberExpr(MemberExpr *E);
@@ -122,6 +122,7 @@ namespace clang {
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
void VisitBlockExpr(BlockExpr *E);
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+ void VisitGenericSelectionExpr(GenericSelectionExpr *E);
void VisitObjCStringLiteral(ObjCStringLiteral *E);
void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
@@ -141,6 +142,7 @@ namespace clang {
// C++ Statements
void VisitCXXCatchStmt(CXXCatchStmt *S);
void VisitCXXTryStmt(CXXTryStmt *S);
+ void VisitCXXForRangeStmt(CXXForRangeStmt *);
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
void VisitCXXConstructExpr(CXXConstructExpr *E);
@@ -177,6 +179,8 @@ namespace clang {
void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+ void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
+ void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
void VisitPackExpansionExpr(PackExpansionExpr *E);
void VisitSizeOfPackExpr(SizeOfPackExpr *E);
@@ -208,7 +212,7 @@ void ASTStmtReader::VisitStmt(Stmt *S) {
void ASTStmtReader::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
S->setSemiLoc(ReadSourceLocation(Record, Idx));
- S->LeadingEmptyMacro = Record[Idx++];
+ S->LeadingEmptyMacro = ReadSourceLocation(Record, Idx);
}
void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
@@ -421,23 +425,23 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
VisitExpr(E);
- bool HasQualifier = Record[Idx++];
- bool HasExplicitTemplateArgs = Record[Idx++];
-
- E->DecoratedD.setInt((HasQualifier? DeclRefExpr::HasQualifierFlag : 0) |
- (HasExplicitTemplateArgs
- ? DeclRefExpr::HasExplicitTemplateArgumentListFlag : 0));
-
- if (HasQualifier) {
- E->getNameQualifier()->NNS = Reader.ReadNestedNameSpecifier(Record, Idx);
- E->getNameQualifier()->Range = ReadSourceRange(Record, Idx);
- }
+ E->DeclRefExprBits.HasQualifier = Record[Idx++];
+ E->DeclRefExprBits.HasFoundDecl = Record[Idx++];
+ E->DeclRefExprBits.HasExplicitTemplateArgs = Record[Idx++];
+ unsigned NumTemplateArgs = 0;
+ if (E->hasExplicitTemplateArgs())
+ NumTemplateArgs = Record[Idx++];
+
+ if (E->hasQualifier())
+ E->getInternalQualifierLoc()
+ = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+
+ if (E->hasFoundDecl())
+ E->getInternalFoundDecl() = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
- if (HasExplicitTemplateArgs) {
- unsigned NumTemplateArgs = Record[Idx++];
+ if (E->hasExplicitTemplateArgs())
ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
NumTemplateArgs);
- }
E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
E->setLocation(ReadSourceLocation(Record, Idx));
@@ -468,7 +472,8 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) {
assert(Record[Idx] == E->getNumConcatenated() &&
"Wrong number of concatenated tokens!");
++Idx;
- E->setWide(Record[Idx++]);
+ E->IsWide = Record[Idx++];
+ E->IsPascal = Record[Idx++];
// Read string data
llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
@@ -555,9 +560,9 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
E->setIndexExpr(I, Reader.ReadSubExpr());
}
-void ASTStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
VisitExpr(E);
- E->setSizeof(Record[Idx++]);
+ E->setKind(static_cast<UnaryExprOrTypeTrait>(Record[Idx++]));
if (Record[Idx] == 0) {
E->setArgument(Reader.ReadSubExpr());
++Idx;
@@ -680,16 +685,29 @@ void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
- unsigned NumInits = Record[Idx++];
- E->reserveInits(*Reader.getContext(), NumInits);
- for (unsigned I = 0; I != NumInits; ++I)
- E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr());
E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt()));
E->setLBraceLoc(ReadSourceLocation(Record, Idx));
E->setRBraceLoc(ReadSourceLocation(Record, Idx));
- E->setInitializedFieldInUnion(
- cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])));
+ bool isArrayFiller = Record[Idx++];
+ Expr *filler = 0;
+ if (isArrayFiller) {
+ filler = Reader.ReadSubExpr();
+ E->ArrayFillerOrUnionFieldInit = filler;
+ } else
+ E->ArrayFillerOrUnionFieldInit
+ = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
E->sawArrayRangeDesignator(Record[Idx++]);
+ unsigned NumInits = Record[Idx++];
+ E->reserveInits(*Reader.getContext(), NumInits);
+ if (isArrayFiller) {
+ for (unsigned I = 0; I != NumInits; ++I) {
+ Expr *init = Reader.ReadSubExpr();
+ E->updateInit(*Reader.getContext(), I, init ? init : filler);
+ }
+ } else {
+ for (unsigned I = 0; I != NumInits; ++I)
+ E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr());
+ }
}
void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
@@ -820,6 +838,25 @@ void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
E->setConstQualAdded(Record[Idx++]);
}
+void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ VisitExpr(E);
+ E->NumAssocs = Record[Idx++];
+ E->AssocTypes = new (*Reader.getContext()) TypeSourceInfo*[E->NumAssocs];
+ E->SubExprs =
+ new(*Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs];
+
+ E->SubExprs[GenericSelectionExpr::CONTROLLING] = Reader.ReadSubExpr();
+ for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
+ E->AssocTypes[I] = GetTypeSourceInfo(Record, Idx);
+ E->SubExprs[GenericSelectionExpr::END_EXPR+I] = Reader.ReadSubExpr();
+ }
+ E->ResultIndex = Record[Idx++];
+
+ E->GenericLoc = ReadSourceLocation(Record, Idx);
+ E->DefaultLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements
@@ -998,6 +1035,19 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) {
S->getStmts()[i + 1] = Reader.ReadSubStmt();
}
+void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+ VisitStmt(S);
+ S->setForLoc(ReadSourceLocation(Record, Idx));
+ S->setColonLoc(ReadSourceLocation(Record, Idx));
+ S->setRParenLoc(ReadSourceLocation(Record, Idx));
+ S->setRangeStmt(Reader.ReadSubStmt());
+ S->setBeginEndStmt(Reader.ReadSubStmt());
+ S->setCond(Reader.ReadSubExpr());
+ S->setInc(Reader.ReadSubExpr());
+ S->setLoopVarStmt(Reader.ReadSubStmt());
+ S->setBody(Reader.ReadSubStmt());
+}
+
void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
E->setOperator((OverloadedOperatorKind)Record[Idx++]);
@@ -1201,14 +1251,13 @@ ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
Record[Idx++]);
- E->setBase(Reader.ReadSubExpr());
- E->setBaseType(Reader.GetType(Record[Idx++]));
- E->setArrow(Record[Idx++]);
- E->setOperatorLoc(ReadSourceLocation(Record, Idx));
- E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
- E->setQualifierRange(ReadSourceRange(Record, Idx));
- E->setFirstQualifierFoundInScope(
- cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->Base = Reader.ReadSubExpr();
+ E->BaseType = Reader.GetType(Record[Idx++]);
+ E->IsArrow = Record[Idx++];
+ E->OperatorLoc = ReadSourceLocation(Record, Idx);
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ E->FirstQualifierFoundInScope
+ = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
ReadDeclarationNameInfo(E->MemberNameInfo, Record, Idx);
}
@@ -1254,24 +1303,25 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
E->initializeResults(*Reader.getContext(), Decls.begin(), Decls.end());
ReadDeclarationNameInfo(E->NameInfo, Record, Idx);
- E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
- E->setQualifierRange(ReadSourceRange(Record, Idx));
+ E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
}
void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
VisitOverloadExpr(E);
- E->setArrow(Record[Idx++]);
- E->setHasUnresolvedUsing(Record[Idx++]);
- E->setBase(Reader.ReadSubExpr());
- E->setBaseType(Reader.GetType(Record[Idx++]));
- E->setOperatorLoc(ReadSourceLocation(Record, Idx));
+ E->IsArrow = Record[Idx++];
+ E->HasUnresolvedUsing = Record[Idx++];
+ E->Base = Reader.ReadSubExpr();
+ E->BaseType = Reader.GetType(Record[Idx++]);
+ E->OperatorLoc = ReadSourceLocation(Record, Idx);
}
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
- E->setRequiresADL(Record[Idx++]);
- E->setOverloaded(Record[Idx++]);
- E->setNamingClass(cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])));
+ E->RequiresADL = Record[Idx++];
+ if (E->RequiresADL)
+ E->StdIsAssociatedNamespace = Record[Idx++];
+ E->Overloaded = Record[Idx++];
+ E->NamingClass = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]));
}
void ASTStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
@@ -1295,6 +1345,26 @@ void ASTStmtReader::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
E->RhsType = GetTypeSourceInfo(Record, Idx);
}
+void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ VisitExpr(E);
+ E->ATT = (ArrayTypeTrait)Record[Idx++];
+ E->Value = (unsigned int)Record[Idx++];
+ SourceRange Range = ReadSourceRange(Record, Idx);
+ E->Loc = Range.getBegin();
+ E->RParen = Range.getEnd();
+ E->QueriedType = GetTypeSourceInfo(Record, Idx);
+}
+
+void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ VisitExpr(E);
+ E->ET = (ExpressionTrait)Record[Idx++];
+ E->Value = (bool)Record[Idx++];
+ SourceRange Range = ReadSourceRange(Record, Idx);
+ E->QueriedExpression = Reader.ReadSubExpr();
+ E->Loc = Range.getBegin();
+ E->RParen = Range.getEnd();
+}
+
void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
VisitExpr(E);
E->Value = (bool)Record[Idx++];
@@ -1500,12 +1570,13 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_DECL_REF:
- S = DeclRefExpr::CreateEmpty(*Context,
- /*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
- /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1],
- /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1]
- ? Record[ASTStmtReader::NumExprFields + 2]
- : 0);
+ S = DeclRefExpr::CreateEmpty(
+ *Context,
+ /*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
+ /*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1],
+ /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2],
+ /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ?
+ Record[ASTStmtReader::NumExprFields + 3] : 0);
break;
case EXPR_INTEGER_LITERAL:
@@ -1548,7 +1619,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
break;
case EXPR_SIZEOF_ALIGN_OF:
- S = new (Context) SizeOfAlignOfExpr(Empty);
+ S = new (Context) UnaryExprOrTypeTraitExpr(Empty);
break;
case EXPR_ARRAY_SUBSCRIPT:
@@ -1565,11 +1636,9 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
// logic with a MemberExpr::CreateEmpty.
assert(Idx == 0);
- NestedNameSpecifier *NNS = 0;
- SourceRange QualifierRange;
+ NestedNameSpecifierLoc QualifierLoc;
if (Record[Idx++]) { // HasQualifier.
- NNS = ReadNestedNameSpecifier(Record, Idx);
- QualifierRange = ReadSourceRange(F, Record, Idx);
+ QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
}
TemplateArgumentListInfo ArgInfo;
@@ -1595,7 +1664,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc);
bool IsArrow = Record[Idx++];
- S = MemberExpr::Create(*Context, Base, IsArrow, NNS, QualifierRange,
+ S = MemberExpr::Create(*Context, Base, IsArrow, QualifierLoc,
MemberD, FoundDecl, MemberNameInfo,
HasExplicitTemplateArgs ? &ArgInfo : 0, T, VK, OK);
ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc,
@@ -1683,6 +1752,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
S = new (Context) BlockDeclRefExpr(Empty);
break;
+ case EXPR_GENERIC_SELECTION:
+ S = new (Context) GenericSelectionExpr(Empty);
+ break;
+
case EXPR_OBJC_STRING_LITERAL:
S = new (Context) ObjCStringLiteral(Empty);
break;
@@ -1741,6 +1814,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
/*NumHandlers=*/Record[ASTStmtReader::NumStmtFields]);
break;
+ case STMT_CXX_FOR_RANGE:
+ S = new (Context) CXXForRangeStmt(Empty);
+ break;
+
case EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(*Context, Empty);
break;
@@ -1881,6 +1958,14 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
S = new (Context) BinaryTypeTraitExpr(Empty);
break;
+ case EXPR_ARRAY_TYPE_TRAIT:
+ S = new (Context) ArrayTypeTraitExpr(Empty);
+ break;
+
+ case EXPR_CXX_EXPRESSION_TRAIT:
+ S = new (Context) ExpressionTraitExpr(Empty);
+ break;
+
case EXPR_CXX_NOEXCEPT:
S = new (Context) CXXNoexceptExpr(Empty);
break;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 383ca3dffc6c..6d44fb63e5a2 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -37,6 +37,7 @@
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
+#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringExtras.h"
@@ -50,12 +51,16 @@ using namespace clang;
using namespace clang::serialization;
template <typename T, typename Allocator>
-T *data(std::vector<T, Allocator> &v) {
- return v.empty() ? 0 : &v.front();
+static llvm::StringRef data(const std::vector<T, Allocator> &v) {
+ if (v.empty()) return llvm::StringRef();
+ return llvm::StringRef(reinterpret_cast<const char*>(&v[0]),
+ sizeof(T) * v.size());
}
-template <typename T, typename Allocator>
-const T *data(const std::vector<T, Allocator> &v) {
- return v.empty() ? 0 : &v.front();
+
+template <typename T>
+static llvm::StringRef data(const llvm::SmallVectorImpl<T> &v) {
+ return llvm::StringRef(reinterpret_cast<const char*>(v.data()),
+ sizeof(T) * v.size());
}
//===----------------------------------------------------------------------===//
@@ -104,12 +109,13 @@ void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
}
void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
- Writer.AddTypeRef(T->getPointeeType(), Record);
+ Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
+ Record.push_back(T->isSpelledAsLValue());
Code = TYPE_LVALUE_REFERENCE;
}
void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
- Writer.AddTypeRef(T->getPointeeType(), Record);
+ Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record);
Code = TYPE_RVALUE_REFERENCE;
}
@@ -160,6 +166,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
Writer.AddTypeRef(T->getResultType(), Record);
FunctionType::ExtInfo C = T->getExtInfo();
Record.push_back(C.getNoReturn());
+ Record.push_back(C.getHasRegParm());
Record.push_back(C.getRegParm());
// FIXME: need to stabilize encoding of calling convention...
Record.push_back(C.getCC());
@@ -178,11 +185,14 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
Record.push_back(T->isVariadic());
Record.push_back(T->getTypeQuals());
Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
- Record.push_back(T->hasExceptionSpec());
- Record.push_back(T->hasAnyExceptionSpec());
- Record.push_back(T->getNumExceptions());
- for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
- Writer.AddTypeRef(T->getExceptionType(I), Record);
+ Record.push_back(T->getExceptionSpecType());
+ if (T->getExceptionSpecType() == EST_Dynamic) {
+ Record.push_back(T->getNumExceptions());
+ for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
+ Writer.AddTypeRef(T->getExceptionType(I), Record);
+ } else if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
+ Writer.AddStmt(T->getNoexceptExpr());
+ }
Code = TYPE_FUNCTION_PROTO;
}
@@ -293,7 +303,7 @@ ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
Record.push_back(T->getDepth());
Record.push_back(T->getIndex());
Record.push_back(T->isParameterPack());
- Writer.AddIdentifierRef(T->getName(), Record);
+ Writer.AddDeclRef(T->getDecl(), Record);
Code = TYPE_TEMPLATE_TYPE_PARM;
}
@@ -418,6 +428,7 @@ void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
}
void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getStarLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getClassTInfo(), Record);
}
void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) {
Writer.AddSourceLocation(TL.getLBracketLoc(), Record);
@@ -450,8 +461,8 @@ void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
- Writer.AddSourceLocation(TL.getLParenLoc(), Record);
- Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record);
+ Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record);
Record.push_back(TL.getTrailingReturn());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
Writer.AddDeclRef(TL.getArg(i), Record);
@@ -532,20 +543,20 @@ void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) {
}
void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
- Writer.AddSourceRange(TL.getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
}
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
- Writer.AddSourceRange(TL.getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
- Writer.AddSourceRange(TL.getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
Writer.AddSourceLocation(TL.getNameLoc(), Record);
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
@@ -652,6 +663,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_SHUFFLE_VECTOR);
RECORD(EXPR_BLOCK);
RECORD(EXPR_BLOCK_DECL_REF);
+ RECORD(EXPR_GENERIC_SELECTION);
RECORD(EXPR_OBJC_STRING_LITERAL);
RECORD(EXPR_OBJC_ENCODE);
RECORD(EXPR_OBJC_SELECTOR_EXPR);
@@ -1000,6 +1012,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.Digraphs); // C94, C99 and C++
Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants.
Record.push_back(LangOpts.C99); // C99 Support
+ Record.push_back(LangOpts.C1X); // C1X Support
Record.push_back(LangOpts.Microsoft); // Microsoft extensions.
// LangOpts.MSCVersion is ignored because all it does it set a macro, which is
// already saved elsewhere.
@@ -1054,6 +1067,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be
// used (instead of C99 semantics).
Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined.
+ Record.push_back(LangOpts.Deprecated); // Should __DEPRECATED be defined.
Record.push_back(LangOpts.AccessControl); // Whether C++ access control should
// be enabled.
Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or
@@ -1072,6 +1086,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.DefaultFPContract);
Record.push_back(LangOpts.ElideConstructors);
Record.push_back(LangOpts.SpellChecking);
+ Record.push_back(LangOpts.MRTD);
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
}
@@ -1427,7 +1442,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Figure out which record code to use.
unsigned Code;
if (SLoc->isFile()) {
- if (SLoc->getFile().getContentCache()->Entry)
+ if (SLoc->getFile().getContentCache()->OrigEntry)
Code = SM_SLOC_FILE_ENTRY;
else
Code = SM_SLOC_BUFFER_ENTRY;
@@ -1444,17 +1459,27 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(File.hasLineDirectives());
const SrcMgr::ContentCache *Content = File.getContentCache();
- if (Content->Entry) {
+ if (Content->OrigEntry) {
+ assert(Content->OrigEntry == Content->ContentsEntry &&
+ "Writing to AST an overriden file is not supported");
+
// The source location entry is a file. The blob associated
// with this entry is the file name.
// Emit size/modification time for this file.
- Record.push_back(Content->Entry->getSize());
- Record.push_back(Content->Entry->getModificationTime());
+ Record.push_back(Content->OrigEntry->getSize());
+ Record.push_back(Content->OrigEntry->getModificationTime());
// Turn the file name into an absolute path, if it isn't already.
- const char *Filename = Content->Entry->getName();
+ const char *Filename = Content->OrigEntry->getName();
llvm::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();
@@ -1517,9 +1542,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(SLocEntryOffsets.size());
unsigned BaseOffset = Chain ? Chain->getNextSLocOffset() : 0;
Record.push_back(SourceMgr.getNextOffset() - BaseOffset);
- Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record,
- (const char *)data(SLocEntryOffsets),
- SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0]));
+ Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
@@ -1778,8 +1801,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
Record.push_back(NumPreprocessingRecords);
Record.push_back(MacroDefinitionOffsets.size());
Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
- (const char *)data(MacroDefinitionOffsets),
- MacroDefinitionOffsets.size() * sizeof(uint32_t));
+ data(MacroDefinitionOffsets));
}
}
@@ -1809,6 +1831,29 @@ void ASTWriter::WritePragmaDiagnosticMappings(const Diagnostic &Diag) {
Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
}
+void ASTWriter::WriteCXXBaseSpecifiersOffsets() {
+ if (CXXBaseSpecifiersOffsets.empty())
+ return;
+
+ RecordData Record;
+
+ // Create a blob abbreviation for the C++ base specifiers offsets.
+ using namespace llvm;
+
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the selector offsets table.
+ Record.clear();
+ Record.push_back(CXX_BASE_SPECIFIER_OFFSETS);
+ Record.push_back(CXXBaseSpecifiersOffsets.size());
+ Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record,
+ data(CXXBaseSpecifiersOffsets));
+}
+
//===----------------------------------------------------------------------===//
// Type Serialization
//===----------------------------------------------------------------------===//
@@ -1881,9 +1926,7 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D)));
++NumLexicalDeclContexts;
- Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record,
- reinterpret_cast<char*>(Decls.data()),
- Decls.size() * sizeof(KindDeclIDPair));
+ Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, data(Decls));
return Offset;
}
@@ -1900,9 +1943,7 @@ void ASTWriter::WriteTypeDeclOffsets() {
Record.clear();
Record.push_back(TYPE_OFFSET);
Record.push_back(TypeOffsets.size());
- Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record,
- (const char *)data(TypeOffsets),
- TypeOffsets.size() * sizeof(TypeOffsets[0]));
+ Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets));
// Write the declaration offsets array
Abbrev = new BitCodeAbbrev();
@@ -1913,9 +1954,7 @@ void ASTWriter::WriteTypeDeclOffsets() {
Record.clear();
Record.push_back(DECL_OFFSET);
Record.push_back(DeclOffsets.size());
- Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record,
- (const char *)data(DeclOffsets),
- DeclOffsets.size() * sizeof(DeclOffsets[0]));
+ Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets));
}
//===----------------------------------------------------------------------===//
@@ -2102,8 +2141,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
Record.push_back(SELECTOR_OFFSETS);
Record.push_back(SelectorOffsets.size());
Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record,
- (const char *)data(SelectorOffsets),
- SelectorOffsets.size() * 4);
+ data(SelectorOffsets));
}
}
@@ -2305,8 +2343,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
Record.push_back(IDENTIFIER_OFFSET);
Record.push_back(IdentifierOffsets.size());
Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,
- (const char *)data(IdentifierOffsets),
- IdentifierOffsets.size() * sizeof(uint32_t));
+ data(IdentifierOffsets));
}
//===----------------------------------------------------------------------===//
@@ -2583,6 +2620,19 @@ void ASTWriter::AddString(llvm::StringRef Str, RecordDataImpl &Record) {
Record.insert(Record.end(), Str.begin(), Str.end());
}
+void ASTWriter::AddVersionTuple(const VersionTuple &Version,
+ RecordDataImpl &Record) {
+ Record.push_back(Version.getMajor());
+ if (llvm::Optional<unsigned> Minor = Version.getMinor())
+ Record.push_back(*Minor + 1);
+ else
+ Record.push_back(0);
+ if (llvm::Optional<unsigned> Subminor = Version.getSubminor())
+ Record.push_back(*Subminor + 1);
+ else
+ Record.push_back(0);
+}
+
/// \brief Note that the identifier II occurs at the given offset
/// within the identifier table.
void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) {
@@ -2770,6 +2820,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddTypeRef(Context.ObjCSelRedefinitionType, Record);
AddTypeRef(Context.getRawNSConstantStringType(), Record);
Record.push_back(Context.isInt128Installed());
+ AddTypeRef(Context.AutoDeductTy, Record);
+ AddTypeRef(Context.AutoRRefDeductTy, Record);
Stream.EmitRecord(SPECIAL_TYPES, Record);
// Keep writing types and declarations until all types and
@@ -2797,25 +2849,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
WriteTypeDeclOffsets();
WritePragmaDiagnosticMappings(Context.getDiagnostics());
- // Write the C++ base-specifier set offsets.
- if (!CXXBaseSpecifiersOffsets.empty()) {
- // Create a blob abbreviation for the C++ base specifiers offsets.
- using namespace llvm;
-
- BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
-
- // Write the selector offsets table.
- Record.clear();
- Record.push_back(CXX_BASE_SPECIFIER_OFFSETS);
- Record.push_back(CXXBaseSpecifiersOffsets.size());
- Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record,
- (const char *)CXXBaseSpecifiersOffsets.data(),
- CXXBaseSpecifiersOffsets.size() * sizeof(uint32_t));
- }
+ WriteCXXBaseSpecifiersOffsets();
// Write the record containing external, unnamed definitions.
if (!ExternalDefinitions.empty())
@@ -2911,8 +2945,7 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Record.clear();
Record.push_back(TU_UPDATE_LEXICAL);
Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
- reinterpret_cast<const char*>(NewGlobalDecls.data()),
- NewGlobalDecls.size() * sizeof(KindDeclIDPair));
+ data(NewGlobalDecls));
// And a visible updates block for the DeclContexts.
Abv = new llvm::BitCodeAbbrev();
Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));
@@ -2997,10 +3030,8 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
for (std::deque<Sema::PendingImplicitInstantiation>::iterator
I = SemaRef.PendingInstantiations.begin(),
N = SemaRef.PendingInstantiations.end(); I != N; ++I) {
- if (I->first->getPCHLevel() == 0) {
- AddDeclRef(I->first, PendingInstantiations);
- AddSourceLocation(I->second, PendingInstantiations);
- }
+ AddDeclRef(I->first, PendingInstantiations);
+ AddSourceLocation(I->second, PendingInstantiations);
}
assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&
"There are local ones at end of translation unit!");
@@ -3040,6 +3071,8 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// write all of them again).
WritePragmaDiagnosticMappings(Context.getDiagnostics());
+ WriteCXXBaseSpecifiersOffsets();
+
/// Build a record containing first declarations from a chained PCH and the
/// most recent declarations in this AST that they point to.
RecordData FirstLatestDeclIDs;
@@ -3245,11 +3278,11 @@ void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record);
break;
case TemplateArgument::Template:
- AddSourceRange(Arg.getTemplateQualifierRange(), Record);
+ AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record);
AddSourceLocation(Arg.getTemplateNameLoc(), Record);
break;
case TemplateArgument::TemplateExpansion:
- AddSourceRange(Arg.getTemplateQualifierRange(), Record);
+ AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record);
AddSourceLocation(Arg.getTemplateNameLoc(), Record);
AddSourceLocation(Arg.getTemplateEllipsisLoc(), Record);
break;
@@ -3452,7 +3485,7 @@ void ASTWriter::AddQualifierInfo(const QualifierInfo &Info,
void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
RecordDataImpl &Record) {
// Nested name specifiers usually aren't too long. I think that 8 would
- // typically accomodate the vast majority.
+ // typically accommodate the vast majority.
llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames;
// Push each of the NNS's onto a stack for serialization in reverse order.
@@ -3495,7 +3528,7 @@ void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS,
void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
RecordDataImpl &Record) {
// Nested name specifiers usually aren't too long. I think that 8 would
- // typically accomodate the vast majority.
+ // typically accommodate the vast majority.
llvm::SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
// Push each of the nested-name-specifiers's onto a stack for
@@ -3749,10 +3782,19 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.Empty);
Record.push_back(Data.Polymorphic);
Record.push_back(Data.Abstract);
+ Record.push_back(Data.IsStandardLayout);
+ Record.push_back(Data.HasNoNonEmptyBases);
+ Record.push_back(Data.HasPrivateFields);
+ Record.push_back(Data.HasProtectedFields);
+ Record.push_back(Data.HasPublicFields);
Record.push_back(Data.HasTrivialConstructor);
+ Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
Record.push_back(Data.HasTrivialCopyConstructor);
+ Record.push_back(Data.HasTrivialMoveConstructor);
Record.push_back(Data.HasTrivialCopyAssignment);
+ Record.push_back(Data.HasTrivialMoveAssignment);
Record.push_back(Data.HasTrivialDestructor);
+ Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
Record.push_back(Data.DeclaredDefaultConstructor);
Record.push_back(Data.DeclaredCopyConstructor);
@@ -3897,4 +3939,37 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
AddDeclRef(D, Record);
}
+void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
+ const FunctionDecl *D) {
+ // The specializations set is kept in the canonical template.
+ TD = TD->getCanonicalDecl();
+ if (!(D->getPCHLevel() == 0 && TD->getPCHLevel() > 0))
+ return; // Not a source specialization added to a template from PCH.
+
+ UpdateRecord &Record = DeclUpdates[TD];
+ Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
+ AddDeclRef(D, Record);
+}
+
+void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
+ if (D->getPCHLevel() == 0)
+ return; // Declaration not imported from PCH.
+
+ // Implicit decl from a PCH was defined.
+ // FIXME: Should implicit definition be a separate FunctionDecl?
+ RewriteDecl(D);
+}
+
+void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
+ if (D->getPCHLevel() == 0)
+ return;
+
+ // Since the actual instantiation is delayed, this really means that we need
+ // to update the instantiation location.
+ UpdateRecord &Record = DeclUpdates[D];
+ Record.push_back(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER);
+ AddSourceLocation(
+ D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record);
+}
+
ASTSerializationListener::~ASTSerializationListener() { }
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 12d1226be94e..1ca00a32f820 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
+#include "ASTCommon.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
@@ -21,6 +22,7 @@
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
+using namespace serialization;
//===----------------------------------------------------------------------===//
// Declaration serialization
@@ -53,6 +55,7 @@ namespace clang {
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
+ void VisitTypeAliasDecl(TypeAliasDecl *D);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
void VisitTagDecl(TagDecl *D);
void VisitEnumDecl(EnumDecl *D);
@@ -140,6 +143,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Writer.WriteAttributes(D->getAttrs(), Record);
Record.push_back(D->isImplicit());
Record.push_back(D->isUsed(false));
+ Record.push_back(D->isReferenced());
Record.push_back(D->getAccess());
Record.push_back(D->getPCHLevel());
}
@@ -157,6 +161,7 @@ void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) {
void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
}
@@ -166,6 +171,12 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
Code = serialization::DECL_TYPEDEF;
}
+void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ VisitTypeDecl(D);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ Code = serialization::DECL_TYPEALIAS;
+}
+
void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
VisitTypeDecl(D);
VisitRedeclarable(D);
@@ -174,12 +185,11 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
Record.push_back(D->isDefinition());
Record.push_back(D->isEmbeddedInDeclarator());
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
- Writer.AddSourceLocation(D->getTagKeywordLoc(), Record);
Record.push_back(D->hasExtInfo());
if (D->hasExtInfo())
Writer.AddQualifierInfo(*D->getExtInfo(), Record);
else
- Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
+ Writer.AddDeclRef(D->getTypedefNameForAnonDecl(), Record);
}
void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
@@ -221,6 +231,7 @@ void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
VisitValueDecl(D);
+ Writer.AddSourceLocation(D->getInnerLocStart(), Record);
Record.push_back(D->hasExtInfo());
if (D->hasExtInfo())
Writer.AddQualifierInfo(*D->getExtInfo(), Record);
@@ -552,6 +563,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->hasCXXDirectInitializer());
Record.push_back(D->isExceptionVariable());
Record.push_back(D->isNRVOVariable());
+ Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->getInit() ? 1 : 0);
if (D->getInit())
Writer.AddStmt(D->getInit());
@@ -575,7 +587,11 @@ void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
VisitVarDecl(D);
+ Record.push_back(D->isObjCMethodParameter());
+ Record.push_back(D->getFunctionScopeDepth());
+ Record.push_back(D->getFunctionScopeIndex());
Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding
+ Record.push_back(D->isKNRPromoted());
Record.push_back(D->hasInheritedDefaultArg());
Record.push_back(D->hasUninstantiatedDefaultArg());
if (D->hasUninstantiatedDefaultArg())
@@ -593,7 +609,9 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
D->getPCHLevel() == 0 &&
D->getStorageClass() == 0 &&
!D->hasCXXDirectInitializer() && // Can params have this ever?
+ D->getFunctionScopeDepth() == 0 &&
D->getObjCDeclQualifier() == 0 &&
+ !D->isKNRPromoted() &&
!D->hasInheritedDefaultArg() &&
D->getInit() == 0 &&
!D->hasUninstantiatedDefaultArg()) // No default expr.
@@ -613,6 +631,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getAsmString());
+ Writer.AddSourceLocation(D->getRParenLoc(), Record);
Code = serialization::DECL_FILE_SCOPE_ASM;
}
@@ -645,15 +664,15 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
VisitDecl(D);
- // FIXME: It might be nice to serialize the brace locations for this
- // declaration, which don't seem to be readily available in the AST.
Record.push_back(D->getLanguage());
- Record.push_back(D->hasBraces());
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getRBraceLoc(), Record);
Code = serialization::DECL_LINKAGE_SPEC;
}
void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
Code = serialization::DECL_LABEL;
}
@@ -661,8 +680,8 @@ void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
VisitNamedDecl(D);
Record.push_back(D->isInline());
- Writer.AddSourceLocation(D->getLBracLoc(), Record);
- Writer.AddSourceLocation(D->getRBracLoc(), Record);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Writer.AddSourceLocation(D->getRBraceLoc(), Record);
Writer.AddDeclRef(D->getNextNamespace(), Record);
// Only write one reference--original or anonymous
@@ -692,6 +711,20 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
}
}
}
+
+ if (Writer.hasChain() && D->isAnonymousNamespace() && !D->getNextNamespace()){
+ // This is a most recent reopening of the anonymous namespace. If its parent
+ // is in a previous PCH (or is the TU), mark that parent for update, because
+ // the original namespace always points to the latest re-opening of its
+ // anonymous namespace.
+ Decl *Parent = cast<Decl>(
+ D->getParent()->getRedeclContext()->getPrimaryContext());
+ if (Parent->getPCHLevel() > 0) {
+ ASTWriter::UpdateRecord &Record = Writer.DeclUpdates[Parent];
+ Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
+ Writer.AddDeclRef(D, Record);
+ }
+ }
}
void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@@ -743,7 +776,6 @@ void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
UnresolvedUsingTypenameDecl *D) {
VisitTypeDecl(D);
- Writer.AddSourceLocation(D->getUsingLoc(), Record);
Writer.AddSourceLocation(D->getTypenameLoc(), Record);
Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Code = serialization::DECL_UNRESOLVED_USING_TYPENAME;
@@ -1001,7 +1033,6 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
VisitTypeDecl(D);
Record.push_back(D->wasDeclaredWithTypename());
- Record.push_back(D->isParameterPack());
Record.push_back(D->defaultArgumentWasInherited());
Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record);
@@ -1054,6 +1085,7 @@ void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getAssertExpr());
Writer.AddStmt(D->getMessage());
+ Writer.AddSourceLocation(D->getRParenLoc(), Record);
Code = serialization::DECL_STATIC_ASSERT;
}
@@ -1121,6 +1153,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
@@ -1130,6 +1163,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
Abv->Add(BitCodeAbbrevOp(serialization::PREDEF_TYPE_NULL_ID)); // InfoType
// VarDecl
@@ -1140,10 +1174,15 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
+ Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
// ParmVarDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsObjCMethodParameter
+ Abv->Add(BitCodeAbbrevOp(0)); // ScopeDepth
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ScopeIndex
Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
+ Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg
Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index af846a92800c..bd5889ad9299 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -68,7 +68,7 @@ namespace clang {
void VisitParenListExpr(ParenListExpr *E);
void VisitUnaryOperator(UnaryOperator *E);
void VisitOffsetOfExpr(OffsetOfExpr *E);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
void VisitCallExpr(CallExpr *E);
void VisitMemberExpr(MemberExpr *E);
@@ -93,6 +93,7 @@ namespace clang {
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
void VisitBlockExpr(BlockExpr *E);
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+ void VisitGenericSelectionExpr(GenericSelectionExpr *E);
// Objective-C Expressions
void VisitObjCStringLiteral(ObjCStringLiteral *E);
@@ -115,6 +116,7 @@ namespace clang {
// C++ Statements
void VisitCXXCatchStmt(CXXCatchStmt *S);
void VisitCXXTryStmt(CXXTryStmt *S);
+ void VisitCXXForRangeStmt(CXXForRangeStmt *);
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
void VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
@@ -151,6 +153,8 @@ namespace clang {
void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+ void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
+ void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
void VisitPackExpansionExpr(PackExpansionExpr *E);
void VisitSizeOfPackExpr(SizeOfPackExpr *E);
@@ -177,7 +181,7 @@ void ASTStmtWriter::VisitStmt(Stmt *S) {
void ASTStmtWriter::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getSemiLoc(), Record);
- Record.push_back(S->LeadingEmptyMacro);
+ Writer.AddSourceLocation(S->LeadingEmptyMacro, Record);
Code = serialization::STMT_NULL;
}
@@ -380,19 +384,23 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
VisitExpr(E);
Record.push_back(E->hasQualifier());
+ Record.push_back(E->getDecl() != E->getFoundDecl());
Record.push_back(E->hasExplicitTemplateArgs());
- if (E->hasQualifier()) {
- Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
- Writer.AddSourceRange(E->getQualifierRange(), Record);
- }
-
if (E->hasExplicitTemplateArgs()) {
unsigned NumTemplateArgs = E->getNumTemplateArgs();
Record.push_back(NumTemplateArgs);
- AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs());
}
+ if (E->hasQualifier())
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+
+ if (E->getDecl() != E->getFoundDecl())
+ Writer.AddDeclRef(E->getFoundDecl(), Record);
+
+ if (E->hasExplicitTemplateArgs())
+ AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs());
+
Writer.AddDeclRef(E->getDecl(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
Writer.AddDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName(), Record);
@@ -425,6 +433,7 @@ void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) {
Record.push_back(E->getByteLength());
Record.push_back(E->getNumConcatenated());
Record.push_back(E->isWide());
+ Record.push_back(E->isPascal());
// FIXME: String data should be stored as a blob at the end of the
// StringLiteral. However, we can't do so now because we have no
// provision for coping with abbreviations when we're jumping around
@@ -479,8 +488,8 @@ void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I);
Record.push_back(ON.getKind()); // FIXME: Stable encoding
- Writer.AddSourceLocation(ON.getRange().getBegin(), Record);
- Writer.AddSourceLocation(ON.getRange().getEnd(), Record);
+ Writer.AddSourceLocation(ON.getSourceRange().getBegin(), Record);
+ Writer.AddSourceLocation(ON.getSourceRange().getEnd(), Record);
switch (ON.getKind()) {
case OffsetOfExpr::OffsetOfNode::Array:
Record.push_back(ON.getArrayExprIndex());
@@ -504,9 +513,9 @@ void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
Code = serialization::EXPR_OFFSETOF;
}
-void ASTStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+void ASTStmtWriter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
VisitExpr(E);
- Record.push_back(E->isSizeOf());
+ Record.push_back(E->getKind());
if (E->isArgumentType())
Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record);
else {
@@ -541,10 +550,8 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
// Don't call VisitExpr, we'll write everything here.
Record.push_back(E->hasQualifier());
- if (E->hasQualifier()) {
- Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
- Writer.AddSourceRange(E->getQualifierRange(), Record);
- }
+ if (E->hasQualifier())
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
Record.push_back(E->hasExplicitTemplateArgs());
if (E->hasExplicitTemplateArgs()) {
@@ -666,14 +673,27 @@ void ASTStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
- Record.push_back(E->getNumInits());
- for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
- Writer.AddStmt(E->getInit(I));
Writer.AddStmt(E->getSyntacticForm());
Writer.AddSourceLocation(E->getLBraceLoc(), Record);
Writer.AddSourceLocation(E->getRBraceLoc(), Record);
- Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
+ bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is<Expr*>();
+ Record.push_back(isArrayFiller);
+ if (isArrayFiller)
+ Writer.AddStmt(E->getArrayFiller());
+ else
+ Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
Record.push_back(E->hadArrayRangeDesignator());
+ Record.push_back(E->getNumInits());
+ if (isArrayFiller) {
+ // ArrayFiller may have filled "holes" due to designated initializer.
+ // Replace them by 0 to indicate that the filler goes in that place.
+ Expr *filler = E->getArrayFiller();
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
+ Writer.AddStmt(E->getInit(I) != filler ? E->getInit(I) : 0);
+ } else {
+ for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
+ Writer.AddStmt(E->getInit(I));
+ }
Code = serialization::EXPR_INIT_LIST;
}
@@ -785,6 +805,23 @@ void ASTStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
Code = serialization::EXPR_BLOCK_DECL_REF;
}
+void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumAssocs());
+
+ Writer.AddStmt(E->getControllingExpr());
+ for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
+ Writer.AddTypeSourceInfo(E->getAssocTypeSourceInfo(I), Record);
+ Writer.AddStmt(E->getAssocExpr(I));
+ }
+ Record.push_back(E->isResultDependent() ? -1U : E->getResultIndex());
+
+ Writer.AddSourceLocation(E->getGenericLoc(), Record);
+ Writer.AddSourceLocation(E->getDefaultLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_GENERIC_SELECTION;
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements.
//===----------------------------------------------------------------------===//
@@ -964,6 +1001,20 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) {
Code = serialization::STMT_CXX_TRY;
}
+void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getForLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
+ Writer.AddSourceLocation(S->getRParenLoc(), Record);
+ Writer.AddStmt(S->getRangeStmt());
+ Writer.AddStmt(S->getBeginEndStmt());
+ Writer.AddStmt(S->getCond());
+ Writer.AddStmt(S->getInc());
+ Writer.AddStmt(S->getLoopVarStmt());
+ Writer.AddStmt(S->getBody());
+ Code = serialization::STMT_CXX_FOR_RANGE;
+}
+
void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
Record.push_back(E->getOperator());
@@ -1196,8 +1247,7 @@ ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
Writer.AddTypeRef(E->getBaseType(), Record);
Record.push_back(E->isArrow());
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
- Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
- Writer.AddSourceRange(E->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
Writer.AddDeclRef(E->getFirstQualifierFoundInScope(), Record);
Writer.AddDeclarationNameInfo(E->MemberNameInfo, Record);
Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
@@ -1253,8 +1303,7 @@ void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
}
Writer.AddDeclarationNameInfo(E->NameInfo, Record);
- Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
- Writer.AddSourceRange(E->getQualifierRange(), Record);
+ Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
}
void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
@@ -1270,6 +1319,8 @@ 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;
@@ -1294,6 +1345,24 @@ void ASTStmtWriter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
Code = serialization::EXPR_BINARY_TYPE_TRAIT;
}
+void ASTStmtWriter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getTrait());
+ Record.push_back(E->getValue());
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Writer.AddTypeSourceInfo(E->getQueriedTypeSourceInfo(), Record);
+ Code = serialization::EXPR_ARRAY_TYPE_TRAIT;
+}
+
+void ASTStmtWriter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getTrait());
+ Record.push_back(E->getValue());
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Writer.AddStmt(E->getQueriedExpression());
+ Code = serialization::EXPR_CXX_EXPRESSION_TRAIT;
+}
+
void ASTStmtWriter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
VisitExpr(E);
Record.push_back(E->getValue());
@@ -1424,7 +1493,7 @@ void ASTWriter::FlushStmts() {
WriteSubStmt(StmtsToEmit[I]);
assert(N == StmtsToEmit.size() &&
- "Substatement writen via AddStmt rather than WriteSubStmt!");
+ "Substatement written via AddStmt rather than WriteSubStmt!");
// Note that we are at the end of a full expression. Any
// expression records that follow this one are part of a different
diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt
index 10c8904b7aa5..66a72ee19d08 100644
--- a/lib/Serialization/CMakeLists.txt
+++ b/lib/Serialization/CMakeLists.txt
@@ -2,7 +2,6 @@
#set(LLVM_USED_LIBS ???)
add_clang_library(clangSerialization
- GeneratePCH.cpp
ASTCommon.cpp
ASTReader.cpp
ASTReaderDecl.cpp
@@ -10,6 +9,8 @@ add_clang_library(clangSerialization
ASTWriter.cpp
ASTWriterDecl.cpp
ASTWriterStmt.cpp
+ ChainedIncludesSource.cpp
+ GeneratePCH.cpp
)
add_dependencies(clangSerialization
diff --git a/lib/Serialization/ChainedIncludesSource.cpp b/lib/Serialization/ChainedIncludesSource.cpp
new file mode 100644
index 000000000000..da5be957a530
--- /dev/null
+++ b/lib/Serialization/ChainedIncludesSource.cpp
@@ -0,0 +1,235 @@
+//===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ChainedIncludesSource class, which converts headers
+// to chained PCHs in memory, mainly used for testing.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/ChainedIncludesSource.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTWriter.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace clang;
+
+static ASTReader *createASTReader(CompilerInstance &CI,
+ llvm::StringRef pchFile,
+ llvm::MemoryBuffer **memBufs,
+ unsigned numBufs,
+ ASTDeserializationListener *deserialListener = 0) {
+ Preprocessor &PP = CI.getPreprocessor();
+ llvm::OwningPtr<ASTReader> Reader;
+ Reader.reset(new ASTReader(PP, &CI.getASTContext(), /*isysroot=*/0,
+ /*DisableValidation=*/true));
+ Reader->setASTMemoryBuffers(memBufs, numBufs);
+ Reader->setDeserializationListener(deserialListener);
+ switch (Reader->ReadAST(pchFile, ASTReader::PCH)) {
+ 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:
+ break;
+ }
+ return 0;
+}
+
+ChainedIncludesSource::~ChainedIncludesSource() {
+ for (unsigned i = 0, e = CIs.size(); i != e; ++i)
+ delete CIs[i];
+}
+
+ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
+
+ std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
+ assert(!includes.empty() && "No '-chain-include' in options!");
+
+ llvm::OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
+ InputKind IK = CI.getFrontendOpts().Inputs[0].first;
+
+ llvm::SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
+
+ for (unsigned i = 0, e = includes.size(); i != e; ++i) {
+ bool firstInclude = (i == 0);
+ llvm::OwningPtr<CompilerInvocation> CInvok;
+ CInvok.reset(new CompilerInvocation(CI.getInvocation()));
+
+ CInvok->getPreprocessorOpts().ChainedIncludes.clear();
+ CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
+ CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
+ CInvok->getPreprocessorOpts().DisablePCHValidation = true;
+ CInvok->getPreprocessorOpts().Includes.clear();
+ CInvok->getPreprocessorOpts().MacroIncludes.clear();
+ CInvok->getPreprocessorOpts().Macros.clear();
+
+ CInvok->getFrontendOpts().Inputs.clear();
+ CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(IK, includes[i]));
+
+ TextDiagnosticPrinter *DiagClient =
+ new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID,
+ DiagClient));
+
+ llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ Clang->setInvocation(CInvok.take());
+ Clang->setDiagnostics(Diags.getPtr());
+ Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
+ Clang->getTargetOpts()));
+ Clang->createFileManager();
+ Clang->createSourceManager(Clang->getFileManager());
+ Clang->createPreprocessor();
+ Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
+ &Clang->getPreprocessor());
+ Clang->createASTContext();
+
+ llvm::SmallVector<char, 256> serialAST;
+ llvm::raw_svector_ostream OS(serialAST);
+ llvm::OwningPtr<ASTConsumer> consumer;
+ consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-",
+ /*Chaining=*/!firstInclude,
+ /*isysroot=*/0, &OS));
+ Clang->getASTContext().setASTMutationListener(
+ consumer->GetASTMutationListener());
+ Clang->setASTConsumer(consumer.take());
+ Clang->createSema(/*CompleteTranslationUnit=*/false, 0);
+
+ if (firstInclude) {
+ Preprocessor &PP = Clang->getPreprocessor();
+ PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
+ PP.getLangOptions());
+ } else {
+ assert(!serialBufs.empty());
+ llvm::SmallVector<llvm::MemoryBuffer *, 4> bufs;
+ for (unsigned si = 0, se = serialBufs.size(); si != se; ++si) {
+ bufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::StringRef(serialBufs[si]->getBufferStart(),
+ serialBufs[si]->getBufferSize())));
+ }
+ std::string pchName = includes[i-1];
+ llvm::raw_string_ostream os(pchName);
+ os << ".pch" << i-1;
+ os.flush();
+ llvm::OwningPtr<ExternalASTSource> Reader;
+ Reader.reset(createASTReader(*Clang, pchName, bufs.data(), bufs.size(),
+ Clang->getASTConsumer().GetASTDeserializationListener()));
+ if (!Reader)
+ return 0;
+ Clang->getASTContext().setExternalSource(Reader);
+ }
+
+ if (!Clang->InitializeSourceManager(includes[i]))
+ return 0;
+
+ ParseAST(Clang->getSema());
+ OS.flush();
+ Clang->getDiagnosticClient().EndSourceFile();
+ serialBufs.push_back(
+ llvm::MemoryBuffer::getMemBufferCopy(llvm::StringRef(serialAST.data(),
+ serialAST.size())));
+ source->CIs.push_back(Clang.take());
+ }
+
+ assert(!serialBufs.empty());
+ std::string pchName = includes.back() + ".pch-final";
+ llvm::OwningPtr<ASTReader> Reader;
+ Reader.reset(createASTReader(CI, pchName,
+ serialBufs.data(), serialBufs.size()));
+ if (!Reader)
+ return 0;
+
+ source->FinalReader.reset(Reader.take());
+ return source.take();
+}
+
+//===----------------------------------------------------------------------===//
+// ExternalASTSource interface.
+//===----------------------------------------------------------------------===//
+
+Decl *ChainedIncludesSource::GetExternalDecl(uint32_t ID) {
+ return getFinalReader().GetExternalDecl(ID);
+}
+Selector ChainedIncludesSource::GetExternalSelector(uint32_t ID) {
+ return getFinalReader().GetExternalSelector(ID);
+}
+uint32_t ChainedIncludesSource::GetNumExternalSelectors() {
+ return getFinalReader().GetNumExternalSelectors();
+}
+Stmt *ChainedIncludesSource::GetExternalDeclStmt(uint64_t Offset) {
+ return getFinalReader().GetExternalDeclStmt(Offset);
+}
+CXXBaseSpecifier *
+ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
+ return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
+}
+DeclContextLookupResult
+ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
+}
+void ChainedIncludesSource::MaterializeVisibleDecls(const DeclContext *DC) {
+ return getFinalReader().MaterializeVisibleDecls(DC);
+}
+bool ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ llvm::SmallVectorImpl<Decl*> &Result) {
+ return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result);
+}
+void ChainedIncludesSource::CompleteType(TagDecl *Tag) {
+ return getFinalReader().CompleteType(Tag);
+}
+void ChainedIncludesSource::CompleteType(ObjCInterfaceDecl *Class) {
+ return getFinalReader().CompleteType(Class);
+}
+void ChainedIncludesSource::StartedDeserializing() {
+ return getFinalReader().StartedDeserializing();
+}
+void ChainedIncludesSource::FinishedDeserializing() {
+ return getFinalReader().FinishedDeserializing();
+}
+void ChainedIncludesSource::StartTranslationUnit(ASTConsumer *Consumer) {
+ return getFinalReader().StartTranslationUnit(Consumer);
+}
+void ChainedIncludesSource::PrintStats() {
+ return getFinalReader().PrintStats();
+}
+void ChainedIncludesSource::getMemoryBufferSizes(MemoryBufferSizes &sizes)const{
+ for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
+ if (const ExternalASTSource *eSrc =
+ CIs[i]->getASTContext().getExternalSource()) {
+ eSrc->getMemoryBufferSizes(sizes);
+ }
+ }
+
+ getFinalReader().getMemoryBufferSizes(sizes);
+}
+
+void ChainedIncludesSource::InitializeSema(Sema &S) {
+ return getFinalReader().InitializeSema(S);
+}
+void ChainedIncludesSource::ForgetSema() {
+ return getFinalReader().ForgetSema();
+}
+std::pair<ObjCMethodList,ObjCMethodList>
+ChainedIncludesSource::ReadMethodPool(Selector Sel) {
+ return getFinalReader().ReadMethodPool(Sel);
+}
+bool ChainedIncludesSource::LookupUnqualified(LookupResult &R, Scope *S) {
+ return getFinalReader().LookupUnqualified(R, S);
+}
+
diff --git a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
index 8832b053db00..8fc6d2a2933e 100644
--- a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
@@ -13,34 +13,25 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class AdjustedReturnValueChecker :
- public CheckerVisitor<AdjustedReturnValueChecker> {
+ public Checker< check::PostStmt<CallExpr> > {
public:
- AdjustedReturnValueChecker() {}
-
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-
- static void *getTag() {
- static int x = 0; return &x;
- }
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
};
}
-void ento::RegisterAdjustedReturnValueChecker(ExprEngine &Eng) {
- Eng.registerCheck(new AdjustedReturnValueChecker());
-}
-
-void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
+void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
// Get the result type of the call.
QualType expectedResultTy = CE->getType();
@@ -94,3 +85,7 @@ void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
C.generateNode(state->BindExpr(CE, V));
}
}
+
+void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) {
+ mgr.registerChecker<AdjustedReturnValueChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index 7b68887f6640..983427afb62d 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -9,13 +9,13 @@
// This file reports various statistics about analyzer visitation.
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-// FIXME: Restructure checker registration.
-#include "ExperimentalChecks.h"
-
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -23,32 +23,20 @@ using namespace clang;
using namespace ento;
namespace {
-class AnalyzerStatsChecker : public CheckerVisitor<AnalyzerStatsChecker> {
+class AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
public:
- static void *getTag();
- void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng);
-
-private:
- llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
};
}
-void *AnalyzerStatsChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-void ento::RegisterAnalyzerStatsChecker(ExprEngine &Eng) {
- Eng.registerCheck(new AnalyzerStatsChecker());
-}
-
-void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
+void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &B,
- ExprEngine &Eng) {
+ ExprEngine &Eng) const {
const CFG *C = 0;
const Decl *D = 0;
const LocationContext *LC = 0;
const SourceManager &SM = B.getSourceManager();
+ llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
// Iterate over explodedgraph
for (ExplodedGraph::node_iterator I = G.nodes_begin();
@@ -100,8 +88,8 @@ void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
}
output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
- << unreachable << " | Aborted Block: "
- << (Eng.wasBlockAborted() ? "yes" : "no")
+ << unreachable << " | Exhausted Block: "
+ << (Eng.wasBlocksExhausted() ? "yes" : "no")
<< " | Empty WorkList: "
<< (Eng.hasEmptyWorkList() ? "yes" : "no");
@@ -109,10 +97,10 @@ void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
D->getLocation());
// Emit warning for each block we bailed out on
- typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
+ typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
const CoreEngine &CE = Eng.getCoreEngine();
- for (AbortedIterator I = CE.blocks_aborted_begin(),
- E = CE.blocks_aborted_end(); I != E; ++I) {
+ for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
+ E = CE.blocks_exhausted_end(); I != E; ++I) {
const BlockEdge &BE = I->first;
const CFGBlock *Exit = BE.getDst();
const CFGElement &CE = Exit->front();
@@ -121,3 +109,7 @@ void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
"stopped analyzing at this point", CS->getStmt()->getLocStart());
}
}
+
+void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
+ mgr.registerChecker<AnalyzerStatsChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 25e224e50c68..eb9665a4a343 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class ArrayBoundChecker :
- public CheckerV2<check::Location> {
+ public Checker<check::Location> {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index f803d27a2678..65a6e633dc8e 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/CharUnits.h"
@@ -23,18 +25,16 @@ using namespace ento;
namespace {
class ArrayBoundCheckerV2 :
- public CheckerVisitor<ArrayBoundCheckerV2> {
- BuiltinBug *BT;
+ public Checker<check::Location> {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
enum OOB_Kind { OOB_Precedes, OOB_Excedes };
void reportOOB(CheckerContext &C, const GRState *errorState,
- OOB_Kind kind);
+ OOB_Kind kind) const;
public:
- ArrayBoundCheckerV2() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad);
+ void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
};
// FIXME: Eventually replace RegionRawOffset with this class.
@@ -62,13 +62,24 @@ public:
};
}
-void ento::RegisterArrayBoundCheckerV2(ExprEngine &Eng) {
- Eng.registerCheck(new ArrayBoundCheckerV2());
+static SVal computeExtentBegin(SValBuilder &svalBuilder,
+ const MemRegion *region) {
+ while (true)
+ switch (region->getKind()) {
+ default:
+ return svalBuilder.makeZeroArrayIndex();
+ case MemRegion::SymbolicRegionKind:
+ // FIXME: improve this later by tracking symbolic lower bounds
+ // for symbolic regions.
+ return UnknownVal();
+ case MemRegion::ElementRegionKind:
+ region = cast<SubRegion>(region)->getSuperRegion();
+ continue;
+ }
}
-void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext,
- const Stmt *S,
- SVal location, bool isLoad) {
+void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
+ CheckerContext &checkerContext) const {
// NOTE: Instead of using GRState::assumeInBound(), we are prototyping
// some new logic here that reasons directly about memory region extents.
@@ -89,31 +100,36 @@ void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext,
if (!rawOffset.getRegion())
return;
- // CHECK LOWER BOUND: Is byteOffset < 0? If so, we are doing a load/store
+ // CHECK LOWER BOUND: Is byteOffset < extent begin?
+ // If so, we are doing a load/store
// before the first valid offset in the memory region.
- SVal lowerBound
- = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
- svalBuilder.makeZeroArrayIndex(),
- svalBuilder.getConditionType());
+ SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
+
+ if (isa<NonLoc>(extentBegin)) {
+ SVal lowerBound
+ = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
+ cast<NonLoc>(extentBegin),
+ svalBuilder.getConditionType());
- NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
- if (!lowerBoundToCheck)
- return;
+ NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
+ if (!lowerBoundToCheck)
+ return;
- const GRState *state_precedesLowerBound, *state_withinLowerBound;
- llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
+ const GRState *state_precedesLowerBound, *state_withinLowerBound;
+ llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
state->assume(*lowerBoundToCheck);
- // Are we constrained enough to definitely precede the lower bound?
- if (state_precedesLowerBound && !state_withinLowerBound) {
- reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
- return;
- }
+ // Are we constrained enough to definitely precede the lower bound?
+ if (state_precedesLowerBound && !state_withinLowerBound) {
+ reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
+ return;
+ }
- // Otherwise, assume the constraint of the lower bound.
- assert(state_withinLowerBound);
- state = state_withinLowerBound;
+ // Otherwise, assume the constraint of the lower bound.
+ assert(state_withinLowerBound);
+ state = state_withinLowerBound;
+ }
do {
// CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)? If so,
@@ -153,14 +169,14 @@ void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext,
void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
const GRState *errorState,
- OOB_Kind kind) {
+ OOB_Kind kind) const {
ExplodedNode *errorNode = checkerContext.generateSink(errorState);
if (!errorNode)
return;
if (!BT)
- BT = new BuiltinBug("Out-of-bound access");
+ BT.reset(new BuiltinBug("Out-of-bound access"));
// FIXME: This diagnostics are preliminary. We should get far better
// diagnostics for explaining buffer overruns.
@@ -237,9 +253,11 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state,
while (region) {
switch (region->getKind()) {
default: {
- if (const SubRegion *subReg = dyn_cast<SubRegion>(region))
+ if (const SubRegion *subReg = dyn_cast<SubRegion>(region)) {
+ offset = getValue(offset, svalBuilder);
if (!offset.isUnknownOrUndef())
return RegionRawOffsetV2(subReg, offset);
+ }
return RegionRawOffsetV2();
}
case MemRegion::ElementRegionKind: {
@@ -274,4 +292,6 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state,
}
-
+void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) {
+ mgr.registerChecker<ArrayBoundCheckerV2>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
index e4865b142c0c..d88a111e9a56 100644
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
@@ -12,33 +12,27 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class AttrNonNullChecker
- : public CheckerVisitor<AttrNonNullChecker> {
- BugType *BT;
+ : public Checker< check::PreStmt<CallExpr> > {
+ mutable llvm::OwningPtr<BugType> BT;
public:
- AttrNonNullChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
-void ento::RegisterAttrNonNullChecker(ExprEngine &Eng) {
- Eng.registerCheck(new AttrNonNullChecker());
-}
-
-void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
+void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
// Check if the callee has a 'nonnull' attribute.
@@ -103,8 +97,8 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
// created. Ownership is transferred to the BugReporter object once
// the BugReport is passed to 'EmitWarning'.
if (!BT)
- BT = new BugType("Argument with 'nonnull' attribute passed null",
- "API");
+ BT.reset(new BugType("Argument with 'nonnull' attribute passed null",
+ "API"));
EnhancedBugReport *R =
new EnhancedBugReport(*BT,
@@ -134,3 +128,7 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
// If 'state' has been updated generated a new node.
C.addTransition(state);
}
+
+void ento::registerAttrNonNullChecker(CheckerManager &mgr) {
+ mgr.registerChecker<AttrNonNullChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 7aff2010d84d..235b400eb9e3 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -13,10 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "BasicObjCFoundationChecks.h"
-
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
@@ -24,7 +23,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
@@ -44,20 +42,21 @@ public:
// Utility functions.
//===----------------------------------------------------------------------===//
-static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
+static const char* GetReceiverNameType(const ObjCMessage &msg) {
if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
- return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
- return NULL;
+ return ID->getIdentifier()->getNameStart();
+ return 0;
}
-static const char* GetReceiverNameType(const ObjCMessage &msg) {
- if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
- return ReceiverType->getDecl()->getIdentifier()->getNameStart();
- return NULL;
-}
+static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID,
+ llvm::StringRef ClassName) {
+ if (ID->getIdentifier()->getName() == ClassName)
+ return true;
-static bool isNSString(llvm::StringRef ClassName) {
- return ClassName == "NSString" || ClassName == "NSMutableString";
+ if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
+ return isReceiverClassOrSuperclass(Super, ClassName);
+
+ return false;
}
static inline bool isNil(SVal X) {
@@ -69,7 +68,7 @@ static inline bool isNil(SVal X) {
//===----------------------------------------------------------------------===//
namespace {
- class NilArgChecker : public CheckerV2<check::PreObjCMessage> {
+ class NilArgChecker : public Checker<check::PreObjCMessage> {
mutable llvm::OwningPtr<APIMisuse> BT;
void WarnNilArg(CheckerContext &C,
@@ -101,11 +100,11 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
CheckerContext &C) const {
- const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
- if (!ReceiverType)
+ const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
+ if (!ID)
return;
- if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
+ if (isReceiverClassOrSuperclass(ID, "NSString")) {
Selector S = msg.getSelector();
if (S.isUnarySelector())
@@ -140,7 +139,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
//===----------------------------------------------------------------------===//
namespace {
-class CFNumberCreateChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
mutable llvm::OwningPtr<APIMisuse> BT;
mutable IdentifierInfo* II;
public:
@@ -347,7 +346,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
//===----------------------------------------------------------------------===//
namespace {
-class CFRetainReleaseChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable llvm::OwningPtr<APIMisuse> BT;
mutable IdentifierInfo *Retain, *Release;
public:
@@ -429,7 +428,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE,
//===----------------------------------------------------------------------===//
namespace {
-class ClassReleaseChecker : public CheckerV2<check::PreObjCMessage> {
+class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
mutable Selector releaseS;
mutable Selector retainS;
mutable Selector autoreleaseS;
@@ -479,6 +478,165 @@ void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
}
//===----------------------------------------------------------------------===//
+// Check for passing non-Objective-C types to variadic methods that expect
+// only Objective-C types.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
+ mutable Selector arrayWithObjectsS;
+ mutable Selector dictionaryWithObjectsAndKeysS;
+ mutable Selector setWithObjectsS;
+ mutable Selector initWithObjectsS;
+ mutable Selector initWithObjectsAndKeysS;
+ mutable llvm::OwningPtr<BugType> BT;
+
+ bool isVariadicMessage(const ObjCMessage &msg) const;
+
+public:
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+};
+}
+
+/// isVariadicMessage - Returns whether the given message is a variadic message,
+/// where all arguments must be Objective-C types.
+bool
+VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
+ const ObjCMethodDecl *MD = msg.getMethodDecl();
+
+ if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
+ return false;
+
+ Selector S = msg.getSelector();
+
+ if (msg.isInstanceMessage()) {
+ // FIXME: Ideally we'd look at the receiver interface here, but that's not
+ // useful for init, because alloc returns 'id'. In theory, this could lead
+ // to false positives, for example if there existed a class that had an
+ // initWithObjects: implementation that does accept non-Objective-C pointer
+ // types, but the chance of that happening is pretty small compared to the
+ // gains that this analysis gives.
+ const ObjCInterfaceDecl *Class = MD->getClassInterface();
+
+ // -[NSArray initWithObjects:]
+ if (isReceiverClassOrSuperclass(Class, "NSArray") &&
+ S == initWithObjectsS)
+ return true;
+
+ // -[NSDictionary initWithObjectsAndKeys:]
+ if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
+ S == initWithObjectsAndKeysS)
+ return true;
+
+ // -[NSSet initWithObjects:]
+ if (isReceiverClassOrSuperclass(Class, "NSSet") &&
+ S == initWithObjectsS)
+ return true;
+ } else {
+ const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
+
+ // -[NSArray arrayWithObjects:]
+ if (isReceiverClassOrSuperclass(Class, "NSArray") &&
+ S == arrayWithObjectsS)
+ return true;
+
+ // -[NSDictionary dictionaryWithObjectsAndKeys:]
+ if (isReceiverClassOrSuperclass(Class, "NSDictionary") &&
+ S == dictionaryWithObjectsAndKeysS)
+ return true;
+
+ // -[NSSet setWithObjects:]
+ if (isReceiverClassOrSuperclass(Class, "NSSet") &&
+ S == setWithObjectsS)
+ return true;
+ }
+
+ return false;
+}
+
+void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
+ if (!BT) {
+ BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
+ "Objective-C pointer types"));
+
+ ASTContext &Ctx = C.getASTContext();
+ arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
+ dictionaryWithObjectsAndKeysS =
+ GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
+ setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
+
+ initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
+ initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
+ }
+
+ if (!isVariadicMessage(msg))
+ return;
+
+ // We are not interested in the selector arguments since they have
+ // well-defined types, so the compiler will issue a warning for them.
+ unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
+
+ // We're not interested in the last argument since it has to be nil or the
+ // compiler would have issued a warning for it elsewhere.
+ unsigned variadicArgsEnd = msg.getNumArgs() - 1;
+
+ if (variadicArgsEnd <= variadicArgsBegin)
+ return;
+
+ // Verify that all arguments have Objective-C types.
+ llvm::Optional<ExplodedNode*> errorNode;
+ const GRState *state = C.getState();
+
+ for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
+ QualType ArgTy = msg.getArgType(I);
+ if (ArgTy->isObjCObjectPointerType())
+ continue;
+
+ // Block pointers are treaded as Objective-C pointers.
+ if (ArgTy->isBlockPointerType())
+ continue;
+
+ // Ignore pointer constants.
+ if (isa<loc::ConcreteInt>(msg.getArgSVal(I, state)))
+ continue;
+
+ // Ignore pointer types annotated with 'NSObject' attribute.
+ if (C.getASTContext().isObjCNSObjectType(ArgTy))
+ continue;
+
+ // Ignore CF references, which can be toll-free bridged.
+ if (cocoa::isCFObjectRef(ArgTy))
+ continue;
+
+ // Generate only one error node to use for all bug reports.
+ if (!errorNode.hasValue()) {
+ errorNode = C.generateNode();
+ }
+
+ if (!errorNode.getValue())
+ continue;
+
+ llvm::SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+
+ if (const char *TypeName = GetReceiverNameType(msg))
+ os << "Argument to '" << TypeName << "' method '";
+ else
+ os << "Argument to method '";
+
+ os << msg.getSelector().getAsString()
+ << "' should be an Objective-C pointer type, not '"
+ << ArgTy.getAsString() << "'";
+
+ RangedBugReport *R = new RangedBugReport(*BT, os.str(),
+ errorNode.getValue());
+ R->addRange(msg.getArgSourceRange(I));
+ C.EmitReport(R);
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Check registration.
//===----------------------------------------------------------------------===//
@@ -497,3 +655,7 @@ void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
void ento::registerClassReleaseChecker(CheckerManager &mgr) {
mgr.registerChecker<ClassReleaseChecker>();
}
+
+void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<VariadicMethodTypeChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h
deleted file mode 100644
index 92cfb1ae556c..000000000000
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//== BasicObjCFoundationChecks.h - Simple Apple-Foundation checks -*- 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 BasicObjCFoundationChecks, a class that encapsulates
-// a set of simple checks to run on Objective-C code using Apple's Foundation
-// classes.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS
-#define LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS
-
-namespace clang {
-
-class ASTContext;
-class Decl;
-
-namespace ento {
-
-class BugReporter;
-class ExprEngine;
-
-void RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, const Decl &D);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 417b015ca39a..12ac652ba060 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -11,8 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
+#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;
@@ -20,19 +22,15 @@ using namespace ento;
namespace {
-class BuiltinFunctionChecker : public Checker {
+class BuiltinFunctionChecker : public Checker<eval::Call> {
public:
- static void *getTag() { static int tag = 0; return &tag; }
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
};
}
-void ento::RegisterBuiltinFunctionChecker(ExprEngine &Eng) {
- Eng.registerCheck(new BuiltinFunctionChecker());
-}
-
-bool BuiltinFunctionChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE){
+bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
+ CheckerContext &C) const{
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -81,3 +79,7 @@ bool BuiltinFunctionChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE){
return false;
}
+
+void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) {
+ mgr.registerChecker<BuiltinFunctionChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index e3083967e01d..8dc7f385a58d 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -27,10 +27,9 @@ add_clang_library(clangStaticAnalyzerCheckers
DebugCheckers.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
- ExperimentalChecks.cpp
- ExprEngine.cpp
FixedAddressChecker.cpp
IdempotentOperationChecker.cpp
+ IteratorsChecker.cpp
LLVMConventionsChecker.cpp
MacOSXAPIChecker.cpp
MallocChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 2566e3cbb430..a6a256a87bcf 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -24,7 +24,7 @@ using namespace clang;
using namespace ento;
namespace {
-class CStringChecker : public CheckerV2< eval::Call,
+class CStringChecker : public Checker< eval::Call,
check::PreStmt<DeclStmt>,
check::LiveSymbols,
check::DeadSymbols,
@@ -49,11 +49,14 @@ public:
const CallExpr *) const;
void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
+ void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
- void evalCopyCommon(CheckerContext &C, const GRState *state,
+ void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
+ const GRState *state,
const Expr *Size, const Expr *Source, const Expr *Dest,
- bool Restricted = false) const;
+ bool Restricted = false,
+ bool IsMempcpy = false) const;
void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
@@ -66,7 +69,16 @@ public:
void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd,
- bool isStrncpy) const;
+ bool isBounded, bool isAppending) const;
+
+ void evalStrcat(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
+
+ void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrncmp(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
+ bool isBounded = false, bool ignoreCase = false) const;
// Utility methods
std::pair<const GRState*, const GRState*>
@@ -81,6 +93,11 @@ public:
SVal getCStringLength(CheckerContext &C, const GRState *&state,
const Expr *Ex, SVal Buf) const;
+ const StringLiteral *getCStringLiteral(CheckerContext &C,
+ const GRState *&state,
+ const Expr *expr,
+ SVal val) const;
+
static const GRState *InvalidateBuffer(CheckerContext &C,
const GRState *state,
const Expr *Ex, SVal V);
@@ -275,7 +292,7 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
NonLoc LastOffset = cast<NonLoc>(svalBuilder.evalBinOpNN(state, BO_Sub,
*Length, One, sizeTy));
- // Check that the first buffer is sufficently long.
+ // Check that the first buffer is sufficiently long.
SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
@@ -581,6 +598,26 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
}
}
+const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
+ const GRState *&state, const Expr *expr, SVal val) const {
+
+ // Get the memory region pointed to by the val.
+ const MemRegion *bufRegion = val.getAsRegion();
+ if (!bufRegion)
+ return NULL;
+
+ // Strip casts off the memory region.
+ bufRegion = bufRegion->StripCasts();
+
+ // Cast the memory region to a string region.
+ const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
+ if (!strRegion)
+ return NULL;
+
+ // Return the actual string in the string region.
+ return strRegion->getStringLiteral();
+}
+
const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
const GRState *state,
const Expr *E, SVal V) {
@@ -655,9 +692,12 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
// evaluation of individual function calls.
//===----------------------------------------------------------------------===//
-void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
+void CStringChecker::evalCopyCommon(CheckerContext &C,
+ const CallExpr *CE,
+ const GRState *state,
const Expr *Size, const Expr *Dest,
- const Expr *Source, bool Restricted) const {
+ const Expr *Source, bool Restricted,
+ bool IsMempcpy) const {
// See if the size argument is zero.
SVal sizeVal = state->getSVal(Size);
QualType sizeTy = Size->getType();
@@ -665,12 +705,39 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
const GRState *stateZeroSize, *stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy);
- // If the size is zero, there won't be any actual memory access.
- if (stateZeroSize)
+ // Get the value of the Dest.
+ SVal destVal = state->getSVal(Dest);
+
+ // If the size is zero, there won't be any actual memory access, so
+ // just bind the return value to the destination buffer and return.
+ if (stateZeroSize) {
C.addTransition(stateZeroSize);
+ if (IsMempcpy)
+ state->BindExpr(CE, destVal);
+ else
+ state->BindExpr(CE, sizeVal);
+ return;
+ }
// If the size can be nonzero, we have to check the other arguments.
if (stateNonZeroSize) {
+
+ // Ensure the destination is not null. If it is NULL there will be a
+ // NULL pointer dereference.
+ state = checkNonNull(C, state, Dest, destVal);
+ if (!state)
+ return;
+
+ // Get the value of the Src.
+ SVal srcVal = state->getSVal(Source);
+
+ // Ensure the source is not null. If it is NULL there will be a
+ // NULL pointer dereference.
+ state = checkNonNull(C, state, Source, srcVal);
+ if (!state)
+ return;
+
+ // Ensure the buffers do not overlap.
state = stateNonZeroSize;
state = CheckBufferAccess(C, state, Size, Dest, Source,
/* FirstIsDst = */ true);
@@ -678,6 +745,26 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
state = CheckOverlap(C, state, Size, Dest, Source);
if (state) {
+
+ // If this is mempcpy, get the byte after the last byte copied and
+ // bind the expr.
+ if (IsMempcpy) {
+ loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
+
+ // Get the length to copy.
+ SVal lenVal = state->getSVal(Size);
+ NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&lenVal);
+
+ // Get the byte after the last byte copied.
+ SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
+ *destRegVal,
+ *lenValNonLoc,
+ Dest->getType());
+
+ // The byte after the last byte copied is the return value.
+ state = state->BindExpr(CE, lastElement);
+ }
+
// Invalidate the destination.
// FIXME: Even if we can't perfectly model the copy, we should see if we
// can use LazyCompoundVals to copy the source values into the destination.
@@ -696,7 +783,16 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
const Expr *Dest = CE->getArg(0);
const GRState *state = C.getState();
state = state->BindExpr(CE, state->getSVal(Dest));
- evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true);
+ evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true);
+}
+
+void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
+ // void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
+ // The return value is a pointer to the byte following the last written byte.
+ const Expr *Dest = CE->getArg(0);
+ const GRState *state = C.getState();
+
+ evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true);
}
void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
@@ -705,12 +801,13 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
const Expr *Dest = CE->getArg(0);
const GRState *state = C.getState();
state = state->BindExpr(CE, state->getSVal(Dest));
- evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1));
+ evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1));
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
// void bcopy(const void *src, void *dst, size_t n);
- evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0));
+ evalCopyCommon(C, CE, C.getState(),
+ CE->getArg(2), CE->getArg(1), CE->getArg(0));
}
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
@@ -849,24 +946,50 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
// char *strcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ false);
+ evalStrcpyCommon(C, CE,
+ /* returnEnd = */ false,
+ /* isBounded = */ false,
+ /* isAppending = */ false);
}
void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
// char *strcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ true);
+ evalStrcpyCommon(C, CE,
+ /* returnEnd = */ false,
+ /* isBounded = */ true,
+ /* isAppending = */ false);
}
void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
// char *stpcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ true, /* isStrncpy = */ false);
+ evalStrcpyCommon(C, CE,
+ /* returnEnd = */ true,
+ /* isBounded = */ false,
+ /* isAppending = */ false);
+}
+
+void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
+ //char *strcat(char *restrict s1, const char *restrict s2);
+ evalStrcpyCommon(C, CE,
+ /* returnEnd = */ false,
+ /* isBounded = */ false,
+ /* isAppending = */ true);
+}
+
+void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
+ //char *strncat(char *restrict s1, const char *restrict s2, size_t n);
+ evalStrcpyCommon(C, CE,
+ /* returnEnd = */ false,
+ /* isBounded = */ true,
+ /* isAppending = */ true);
}
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
- bool returnEnd, bool isStrncpy) const {
+ bool returnEnd, bool isBounded,
+ bool isAppending) const {
const GRState *state = C.getState();
- // Check that the destination is non-null
+ // Check that the destination is non-null.
const Expr *Dst = CE->getArg(0);
SVal DstVal = state->getSVal(Dst);
@@ -888,18 +1011,26 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (strLength.isUndef())
return;
- if (isStrncpy) {
- // Get the max number of characters to copy
+ // If the function is strncpy, strncat, etc... it is bounded.
+ if (isBounded) {
+ // Get the max number of characters to copy.
const Expr *lenExpr = CE->getArg(2);
SVal lenVal = state->getSVal(lenExpr);
+ // Cast the length to a NonLoc SVal. If it is not a NonLoc then give up.
NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
+ if (!strLengthNL)
+ return;
+
+ // Cast the max length to a NonLoc SVal. If it is not a NonLoc then give up.
NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal);
+ if (!lenValNL)
+ return;
QualType cmpTy = C.getSValBuilder().getContext().IntTy;
const GRState *stateTrue, *stateFalse;
- // Check if the max number to copy is less than the length of the src
+ // Check if the max number to copy is less than the length of the src.
llvm::tie(stateTrue, stateFalse) =
state->assume(cast<DefinedOrUnknownSVal>
(C.getSValBuilder().evalBinOpNN(state, BO_GT,
@@ -913,6 +1044,29 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
}
}
+ // If this is an appending function (strcat, strncat...) then set the
+ // string length to strlen(src) + strlen(dst) since the buffer will
+ // ultimately contain both.
+ if (isAppending) {
+ // Get the string length of the destination, or give up.
+ SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
+ if (dstStrLength.isUndef())
+ return;
+
+ NonLoc *srcStrLengthNL = dyn_cast<NonLoc>(&strLength);
+ NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength);
+
+ // If src or dst cast to NonLoc is NULL, give up.
+ if ((!srcStrLengthNL) || (!dstStrLengthNL))
+ return;
+
+ QualType addTy = C.getSValBuilder().getContext().getSizeType();
+
+ strLength = C.getSValBuilder().evalBinOpNN(state, BO_Add,
+ *srcStrLengthNL, *dstStrLengthNL,
+ addTy);
+ }
+
SVal Result = (returnEnd ? UnknownVal() : DstVal);
// If the destination is a MemRegion, try to check for a buffer overflow and
@@ -958,6 +1112,113 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
C.addTransition(state);
}
+void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
+ //int strcmp(const char *restrict s1, const char *restrict s2);
+ evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false);
+}
+
+void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
+ //int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
+ evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false);
+}
+
+void CStringChecker::evalStrcasecmp(CheckerContext &C,
+ const CallExpr *CE) const {
+ //int strcasecmp(const char *restrict s1, const char *restrict s2);
+ evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
+}
+
+void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
+ bool isBounded, bool ignoreCase) const {
+ const GRState *state = C.getState();
+
+ // Check that the first string is non-null
+ const Expr *s1 = CE->getArg(0);
+ SVal s1Val = state->getSVal(s1);
+ state = checkNonNull(C, state, s1, s1Val);
+ if (!state)
+ return;
+
+ // Check that the second string is non-null.
+ const Expr *s2 = CE->getArg(1);
+ SVal s2Val = state->getSVal(s2);
+ state = checkNonNull(C, state, s2, s2Val);
+ if (!state)
+ return;
+
+ // Get the string length of the first string or give up.
+ SVal s1Length = getCStringLength(C, state, s1, s1Val);
+ if (s1Length.isUndef())
+ return;
+
+ // Get the string length of the second string or give up.
+ SVal s2Length = getCStringLength(C, state, s2, s2Val);
+ if (s2Length.isUndef())
+ return;
+
+ // Get the string literal of the first string.
+ const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val);
+ if (!s1StrLiteral)
+ return;
+ llvm::StringRef s1StrRef = s1StrLiteral->getString();
+
+ // Get the string literal of the second string.
+ const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val);
+ if (!s2StrLiteral)
+ return;
+ llvm::StringRef s2StrRef = s2StrLiteral->getString();
+
+ int result;
+ if (isBounded) {
+ // Get the max number of characters to compare.
+ const Expr *lenExpr = CE->getArg(2);
+ SVal lenVal = state->getSVal(lenExpr);
+
+ // Dynamically cast the length to a ConcreteInt. If it is not a ConcreteInt
+ // then give up, otherwise get the value and use it as the bounds.
+ nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&lenVal);
+ if (!CI)
+ return;
+ llvm::APSInt lenInt(CI->getValue());
+
+ // Compare using the bounds provided like strncmp() does.
+ if (ignoreCase) {
+ // TODO Implement compare_lower(RHS, n) in LLVM StringRef.
+ // result = s1StrRef.compare_lower(s2StrRef,
+ // (size_t)lenInt.getLimitedValue());
+
+ // For now, give up.
+ return;
+ } else {
+ // Create substrings of each to compare the prefix.
+ llvm::StringRef s1SubStr =
+ s1StrRef.substr(0, (size_t)lenInt.getLimitedValue());
+ llvm::StringRef s2SubStr =
+ s2StrRef.substr(0, (size_t)lenInt.getLimitedValue());
+
+ // Compare the substrings.
+ result = s1SubStr.compare(s2SubStr);
+ }
+ } else {
+ // Compare string 1 to string 2 the same way strcmp() does.
+ if (ignoreCase) {
+ result = s1StrRef.compare_lower(s2StrRef);
+ } else {
+ result = s1StrRef.compare(s2StrRef);
+ }
+ }
+
+ // Build the SVal of the comparison to bind the return value.
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ QualType intTy = svalBuilder.getContext().IntTy;
+ SVal resultVal = svalBuilder.makeIntVal(result, intTy);
+
+ // Bind the return value of the expression.
+ // Set the return value.
+ state = state->BindExpr(CE, resultVal);
+ C.addTransition(state);
+}
+
//===----------------------------------------------------------------------===//
// The driver method, and other Checker callbacks.
//===----------------------------------------------------------------------===//
@@ -982,13 +1243,19 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
.Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy)
+ .Case("mempcpy", &CStringChecker::evalMempcpy)
.Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
.Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
.Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
.Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
.Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
+ .Cases("strcat", "__strcat_chk", &CStringChecker::evalStrcat)
+ .Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat)
.Case("strlen", &CStringChecker::evalstrLength)
.Case("strnlen", &CStringChecker::evalstrnLength)
+ .Case("strcmp", &CStringChecker::evalStrcmp)
+ .Case("strncmp", &CStringChecker::evalStrncmp)
+ .Case("strcasecmp", &CStringChecker::evalStrcasecmp)
.Case("bcopy", &CStringChecker::evalBcopy)
.Default(NULL);
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 415900eb000e..dfe0a0e6f50a 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -12,62 +12,51 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class CallAndMessageChecker
- : public CheckerVisitor<CallAndMessageChecker> {
- BugType *BT_call_null;
- BugType *BT_call_undef;
- BugType *BT_call_arg;
- BugType *BT_msg_undef;
- BugType *BT_msg_arg;
- BugType *BT_msg_ret;
+ : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > {
+ mutable llvm::OwningPtr<BugType> BT_call_null;
+ mutable llvm::OwningPtr<BugType> BT_call_undef;
+ mutable llvm::OwningPtr<BugType> BT_call_arg;
+ mutable llvm::OwningPtr<BugType> BT_msg_undef;
+ mutable llvm::OwningPtr<BugType> BT_msg_arg;
+ mutable llvm::OwningPtr<BugType> BT_msg_ret;
public:
- CallAndMessageChecker() :
- BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
- BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {}
-
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
- void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
- bool evalNilReceiver(CheckerContext &C, ObjCMessage msg);
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
private:
- void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg,
- const char *BT_desc, BugType *&BT);
- bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
- const Expr *argEx, const char *BT_desc, BugType *&BT);
+ static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg,
+ const char *BT_desc, llvm::OwningPtr<BugType> &BT);
+ static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange,
+ const Expr *argEx, const char *BT_desc, llvm::OwningPtr<BugType> &BT);
- void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
+ static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
- ExplodedNode *N);
+ ExplodedNode *N) const;
void HandleNilReceiver(CheckerContext &C, const GRState *state,
- ObjCMessage msg);
+ ObjCMessage msg) const;
- void LazyInit_BT(const char *desc, BugType *&BT) {
+ static void LazyInit_BT(const char *desc, llvm::OwningPtr<BugType> &BT) {
if (!BT)
- BT = new BuiltinBug(desc);
+ BT.reset(new BuiltinBug(desc));
}
};
} // end anonymous namespace
-void ento::RegisterCallAndMessageChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CallAndMessageChecker());
-}
-
void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
const CallExpr *CE) {
ExplodedNode *N = C.generateSink();
@@ -83,7 +72,7 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
CallOrObjCMessage callOrMsg,
const char *BT_desc,
- BugType *&BT) {
+ llvm::OwningPtr<BugType> &BT) {
for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
@@ -95,7 +84,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
SVal V, SourceRange argRange,
const Expr *argEx,
const char *BT_desc,
- BugType *&BT) {
+ llvm::OwningPtr<BugType> &BT) {
if (V.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
@@ -198,25 +187,25 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
return false;
}
-void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE){
+void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const{
const Expr *Callee = CE->getCallee()->IgnoreParens();
SVal L = C.getState()->getSVal(Callee);
if (L.isUndef()) {
if (!BT_call_undef)
- BT_call_undef =
- new BuiltinBug("Called function pointer is an uninitalized pointer value");
- EmitBadCall(BT_call_undef, C, CE);
+ BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
+ "uninitalized pointer value"));
+ EmitBadCall(BT_call_undef.get(), C, CE);
return;
}
if (isa<loc::ConcreteInt>(L)) {
if (!BT_call_null)
- BT_call_null =
- new BuiltinBug("Called function pointer is null (null dereference)");
- EmitBadCall(BT_call_null, C, CE);
+ BT_call_null.reset(
+ new BuiltinBug("Called function pointer is null (null dereference)"));
+ EmitBadCall(BT_call_null.get(), C, CE);
}
PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()),
@@ -224,18 +213,19 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
BT_call_arg);
}
-void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
const GRState *state = C.getState();
// FIXME: Handle 'super'?
- if (const Expr *receiver = msg.getInstanceReceiver())
- if (state->getSVal(receiver).isUndef()) {
+ if (const Expr *receiver = msg.getInstanceReceiver()) {
+ SVal recVal = state->getSVal(receiver);
+ if (recVal.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_msg_undef)
- BT_msg_undef =
- new BuiltinBug("Receiver in message expression is an uninitialized value");
+ BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is "
+ "an uninitialized value"));
EnhancedBugReport *R =
new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
R->addRange(receiver->getSourceRange());
@@ -244,7 +234,20 @@ void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C,
C.EmitReport(R);
}
return;
+ } else {
+ // Bifurcate the state into nil and non-nil ones.
+ DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+
+ const GRState *notNilState, *nilState;
+ llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+
+ // Handle receiver must be nil.
+ if (nilState && !notNilState) {
+ HandleNilReceiver(C, state, msg);
+ return;
+ }
}
+ }
const char *bugDesc = msg.isPropertySetter() ?
"Argument for property setter is an uninitialized value"
@@ -253,20 +256,14 @@ void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C,
PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg);
}
-bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C,
- ObjCMessage msg) {
- HandleNilReceiver(C, C.getState(), msg);
- return true; // Nil receiver is not handled elsewhere.
-}
-
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
const ObjCMessage &msg,
- ExplodedNode *N) {
+ ExplodedNode *N) const {
if (!BT_msg_ret)
- BT_msg_ret =
+ BT_msg_ret.reset(
new BuiltinBug("Receiver in message expression is "
- "'nil' and returns a garbage value");
+ "'nil' and returns a garbage value"));
llvm::SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
@@ -292,7 +289,7 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const GRState *state,
- ObjCMessage msg) {
+ ObjCMessage msg) const {
ASTContext &Ctx = C.getASTContext();
// Check the return type of the message expression. A message to nil will
@@ -356,3 +353,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
C.addTransition(state);
}
+
+void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CallAndMessageChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 6a4506bcf844..585a87d498d3 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -22,7 +22,7 @@ using namespace clang;
using namespace ento;
namespace {
-class CastSizeChecker : public CheckerV2< check::PreStmt<CastExpr> > {
+class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 04cc253fc609..3210b0a4bb61 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -23,7 +23,7 @@ using namespace clang;
using namespace ento;
namespace {
-class CastToStructChecker : public CheckerV2< check::PreStmt<CastExpr> > {
+class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index ad3bab6f7ea9..0c693a0bd1b6 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.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"
@@ -267,7 +267,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D,
//===----------------------------------------------------------------------===//
namespace {
-class ObjCDeallocChecker : public CheckerV2<
+class ObjCDeallocChecker : public Checker<
check::ASTDecl<ObjCImplementationDecl> > {
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index 369ba0bbb2ac..fec06a95350e 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/DeclObjC.h"
@@ -125,7 +125,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
//===----------------------------------------------------------------------===//
namespace {
-class ObjCMethSigsChecker : public CheckerV2<
+class ObjCMethSigsChecker : public Checker<
check::ASTDecl<ObjCImplementationDecl> > {
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 185520c8df18..53810eed1255 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -12,11 +12,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace ento;
@@ -33,21 +34,13 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) {
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
- IdentifierInfo *II_gets;
- IdentifierInfo *II_getpw;
- IdentifierInfo *II_mktemp;
- enum { num_rands = 9 };
- IdentifierInfo *II_rand[num_rands];
- IdentifierInfo *II_random;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
const bool CheckRand;
public:
- WalkAST(BugReporter &br) : BR(br),
- II_gets(0), II_getpw(0), II_mktemp(0),
- II_rand(), II_random(0), II_setid(),
+ WalkAST(BugReporter &br) : BR(br), II_setid(),
CheckRand(isArc4RandomAvailable(BR.getContext())) {}
// Statement visitor methods.
@@ -59,16 +52,22 @@ public:
void VisitChildren(Stmt *S);
// Helpers.
- IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);
+ IdentifierInfo *getIdentifier(IdentifierInfo *& II, const char *str);
+ bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
+
+ typedef void (WalkAST::*FnCheck)(const CallExpr *,
+ const FunctionDecl *);
// Checker-specific methods.
- void CheckLoopConditionForFloat(const ForStmt *FS);
- void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
- void CheckUncheckedReturnValue(CallExpr *CE);
+ void checkLoopConditionForFloat(const ForStmt *FS);
+ void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
+ void checkUncheckedReturnValue(CallExpr *CE);
};
} // end anonymous namespace
@@ -76,7 +75,7 @@ public:
// Helper methods.
//===----------------------------------------------------------------------===//
-IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
+IdentifierInfo *WalkAST::getIdentifier(IdentifierInfo *& II, const char *str) {
if (!II)
II = &BR.getContext().Idents.get(str);
@@ -94,15 +93,43 @@ void WalkAST::VisitChildren(Stmt *S) {
}
void WalkAST::VisitCallExpr(CallExpr *CE) {
- if (const FunctionDecl *FD = CE->getDirectCallee()) {
- CheckCall_gets(CE, FD);
- CheckCall_getpw(CE, FD);
- CheckCall_mktemp(CE, FD);
- if (CheckRand) {
- CheckCall_rand(CE, FD);
- CheckCall_random(CE, FD);
- }
- }
+ // Get the callee.
+ const FunctionDecl *FD = CE->getDirectCallee();
+
+ if (!FD)
+ return;
+
+ // Get the name of the callee. If it's a builtin, strip off the prefix.
+ IdentifierInfo *II = FD->getIdentifier();
+ if (!II) // if no identifier, not a simple C function
+ return;
+ llvm::StringRef Name = II->getName();
+ if (Name.startswith("__builtin_"))
+ Name = Name.substr(10);
+
+ // Set the evaluation function by switching on the callee name.
+ FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
+ .Case("gets", &WalkAST::checkCall_gets)
+ .Case("getpw", &WalkAST::checkCall_getpw)
+ .Case("mktemp", &WalkAST::checkCall_mktemp)
+ .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
+ .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
+ .Case("drand48", &WalkAST::checkCall_rand)
+ .Case("erand48", &WalkAST::checkCall_rand)
+ .Case("jrand48", &WalkAST::checkCall_rand)
+ .Case("lrand48", &WalkAST::checkCall_rand)
+ .Case("mrand48", &WalkAST::checkCall_rand)
+ .Case("nrand48", &WalkAST::checkCall_rand)
+ .Case("lcong48", &WalkAST::checkCall_rand)
+ .Case("rand", &WalkAST::checkCall_rand)
+ .Case("rand_r", &WalkAST::checkCall_rand)
+ .Case("random", &WalkAST::checkCall_random)
+ .Default(NULL);
+
+ // If the callee isn't defined, it is not of security concern.
+ // Check and evaluate the call.
+ if (evalFunction)
+ (this->*evalFunction)(CE, FD);
// Recurse and check children.
VisitChildren(CE);
@@ -112,13 +139,13 @@ void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
if (Stmt *child = *I) {
if (CallExpr *CE = dyn_cast<CallExpr>(child))
- CheckUncheckedReturnValue(CE);
+ checkUncheckedReturnValue(CE);
Visit(child);
}
}
void WalkAST::VisitForStmt(ForStmt *FS) {
- CheckLoopConditionForFloat(FS);
+ checkLoopConditionForFloat(FS);
// Recurse and check children.
VisitChildren(FS);
@@ -131,7 +158,7 @@ void WalkAST::VisitForStmt(ForStmt *FS) {
//===----------------------------------------------------------------------===//
static const DeclRefExpr*
-GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
+getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
expr = expr->IgnoreParenCasts();
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
@@ -139,10 +166,10 @@ GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
B->getOpcode() == BO_Comma))
return NULL;
- if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
+ if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
return lhs;
- if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
+ if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
return rhs;
return NULL;
@@ -155,7 +182,7 @@ GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
return U->isIncrementDecrementOp()
- ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;
+ ? getIncrementedVar(U->getSubExpr(), x, y) : NULL;
return NULL;
}
@@ -164,7 +191,7 @@ GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
/// use a floating point variable as a loop counter.
/// CERT: FLP30-C, FLP30-CPP.
///
-void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
+void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
// Does the loop have a condition?
const Expr *condition = FS->getCond();
@@ -211,7 +238,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
return;
// Does either variable appear in increment?
- const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);
+ const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
if (!drInc)
return;
@@ -243,10 +270,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
// CWE-242: Use of Inherently Dangerous Function
//===----------------------------------------------------------------------===//
-void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
- return;
-
+void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if (!FPT)
@@ -278,10 +302,7 @@ void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
// CWE-477: Use of Obsolete Functions
//===----------------------------------------------------------------------===//
-void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
- return;
-
+void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if (!FPT)
@@ -317,16 +338,13 @@ void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
// CWE-377: Insecure Temporary File
//===----------------------------------------------------------------------===//
-void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp"))
- return;
-
+void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if(!FPT)
return;
- // Verify that the funcion takes a single argument.
+ // Verify that the function takes a single argument.
if (FPT->getNumArgs() != 1)
return;
@@ -349,32 +367,86 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
-// Check: Linear congruent random number generators should not be used
-// Originally: <rdar://problem/63371000>
-// CWE-338: Use of cryptographically weak prng
+// Check: Any use of 'strcpy' is insecure.
+//
+// CWE-119: Improper Restriction of Operations within
+// the Bounds of a Memory Buffer
//===----------------------------------------------------------------------===//
+void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!checkCall_strCommon(CE, FD))
+ return;
-void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
- if (II_rand[0] == NULL) {
- // This check applies to these functions
- static const char * const identifiers[num_rands] = {
- "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48",
- "lcong48",
- "rand", "rand_r"
- };
+ // Issue a warning.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
+ "call 'strcpy'",
+ "Security",
+ "Call to function 'strcpy' is insecure as it does not "
+ "provide bounding of the memory buffer. Replace "
+ "unbounded copy functions with analogous functions that "
+ "support length arguments such as 'strncpy'. CWE-119.",
+ CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Any use of 'strcat' is insecure.
+//
+// CWE-119: Improper Restriction of Operations within
+// the Bounds of a Memory Buffer
+//===----------------------------------------------------------------------===//
+void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!checkCall_strCommon(CE, FD))
+ return;
+
+ // Issue a warning.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
+ "call 'strcat'",
+ "Security",
+ "Call to function 'strcat' is insecure as it does not "
+ "provide bounding of the memory buffer. Replace "
+ "unbounded copy functions with analogous functions that "
+ "support length arguments such as 'strncat'. CWE-119.",
+ CE->getLocStart(), &R, 1);
+}
- for (size_t i = 0; i < num_rands; i++)
- II_rand[i] = &BR.getContext().Idents.get(identifiers[i]);
+//===----------------------------------------------------------------------===//
+// Common check for str* functions with no bounds parameters.
+//===----------------------------------------------------------------------===//
+bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
+ const FunctionProtoType *FPT
+ = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+ if (!FPT)
+ return false;
+
+ // Verify the function takes two arguments, three in the _chk version.
+ int numArgs = FPT->getNumArgs();
+ if (numArgs != 2 && numArgs != 3)
+ return false;
+
+ // Verify the type for both arguments.
+ for (int i = 0; i < 2; i++) {
+ // Verify that the arguments are pointers.
+ const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(i));
+ if (!PT)
+ return false;
+
+ // Verify that the argument is a 'char*'.
+ if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+ return false;
}
- const IdentifierInfo *id = FD->getIdentifier();
- size_t identifierid;
+ return true;
+}
- for (identifierid = 0; identifierid < num_rands; identifierid++)
- if (id == II_rand[identifierid])
- break;
+//===----------------------------------------------------------------------===//
+// Check: Linear congruent random number generators should not be used
+// Originally: <rdar://problem/63371000>
+// CWE-338: Use of cryptographically weak prng
+//===----------------------------------------------------------------------===//
- if (identifierid >= num_rands)
+void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!CheckRand)
return;
const FunctionProtoType *FTP
@@ -415,8 +487,8 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
// Originally: <rdar://problem/63371000>
//===----------------------------------------------------------------------===//
-void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_random, "random"))
+void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!CheckRand)
return;
const FunctionProtoType *FTP
@@ -442,7 +514,7 @@ void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
// Originally: <rdar://problem/6337132>
//===----------------------------------------------------------------------===//
-void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
+void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
const FunctionDecl *FD = CE->getDirectCallee();
if (!FD)
return;
@@ -502,7 +574,7 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
//===----------------------------------------------------------------------===//
namespace {
-class SecuritySyntaxChecker : public CheckerV2<check::ASTCodeBody> {
+class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index d46ac8121b5a..abf53fd3db28 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/StmtVisitor.h"
@@ -26,7 +26,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br) : BR(br) {}
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
void VisitStmt(Stmt *S) { VisitChildren(S); }
void VisitChildren(Stmt *S);
};
@@ -39,8 +39,8 @@ void WalkAST::VisitChildren(Stmt *S) {
}
// CWE-467: Use of sizeof() on a Pointer Type
-void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
- if (!E->isSizeOf())
+void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
+ if (E->getKind() != UETT_SizeOf)
return;
// If an explicit type is used in the code, usually the coder knows what he is
@@ -72,7 +72,7 @@ void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class SizeofPointerChecker : public CheckerV2<check::ASTCodeBody> {
+class SizeofPointerChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 894b961f7d1e..1a71fc4074ba 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -10,204 +10,366 @@
include "clang/StaticAnalyzer/Checkers/CheckerBase.td"
//===----------------------------------------------------------------------===//
+// Groups.
+//===----------------------------------------------------------------------===//
+
+def AllExperimental : CheckerGroup<"all-experimental">;
+
+//===----------------------------------------------------------------------===//
// Packages.
//===----------------------------------------------------------------------===//
def Core : Package<"core">;
-def Cocoa : Package<"cocoa">;
-def Unix : Package<"unix">;
-def MacOSX : Package<"macosx">;
+def CoreBuiltin : Package<"builtin">, InPackage<Core>;
+def CoreUninitialized : Package<"uninitialized">, InPackage<Core>;
+def CoreExperimental : Package<"experimental">, InPackage<Core>,
+ InGroup<AllExperimental>, Hidden;
-def CoreExperimental : Package<"experimental">,
- InPackage<Core>, Hidden;
+def Cplusplus : Package<"cplusplus">;
+def CplusplusExperimental : Package<"experimental">, InPackage<Cplusplus>,
+ InGroup<AllExperimental>, Hidden;
-def CocoaExperimental : Package<"experimental">,
- InPackage<Cocoa>, Hidden;
+def DeadCode : Package<"deadcode">;
+def DeadCodeExperimental : Package<"experimental">, InPackage<DeadCode>,
+ InGroup<AllExperimental>, Hidden;
-def UnixExperimental : Package<"experimental">,
- InPackage<Unix>, Hidden;
+def Security : Package <"security">;
+def SecurityExperimental : Package<"experimental">, InPackage<Security>,
+ InGroup<AllExperimental>, Hidden;
+
+def Unix : Package<"unix">;
+def UnixExperimental : Package<"experimental">, InPackage<Unix>,
+ InGroup<AllExperimental>, Hidden;
+
+def OSX : Package<"osx">;
+def Cocoa : Package<"cocoa">, InPackage<OSX>;
+def CocoaExperimental : Package<"experimental">, InPackage<Cocoa>,
+ InGroup<AllExperimental>, Hidden;
+def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>;
def LLVM : Package<"llvm">;
def Debug : Package<"debug">;
//===----------------------------------------------------------------------===//
-// Groups.
+// Core Checkers.
//===----------------------------------------------------------------------===//
-def AllExperimental : CheckerGroup<"all-experimental">,
- Hidden;
+let ParentPackage = Core in {
-//===----------------------------------------------------------------------===//
-// Checkers.
-//===----------------------------------------------------------------------===//
+def DereferenceChecker : Checker<"NullDereference">,
+ HelpText<"Check for dereferences of null pointers">,
+ DescFile<"DereferenceChecker.cpp">;
-let ParentPackage = Cocoa in {
+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 ObjCSelfInitChecker : Checker<"SelfInit">,
- HelpText<"Check that 'self' is propely initialized inside an initializer method">,
- DescFile<"ObjCSelfInitChecker.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 ObjCAtSyncChecker : Checker<"AtSync">,
- HelpText<"Check for null pointers used as mutexes for @synchronized">,
- DescFile<"ObjCAtSyncChecker.cpp">;
+def AttrNonNullChecker : Checker<"AttributeNonNull">,
+ HelpText<"Check for null pointers passed as arguments to a function whose arguments are marked with the 'nonnull' attribute">,
+ DescFile<"AttrNonNullChecker.cpp">;
-def NilArgChecker : Checker<"NilArg">,
- HelpText<"Check for prohibited nil arguments to ObjC method calls">,
- DescFile<"BasicObjCFoundationChecks.cpp">;
+def VLASizeChecker : Checker<"VLASize">,
+ HelpText<"Check for declarations of VLA of undefined or zero size">,
+ DescFile<"VLASizeChecker.cpp">;
-def ClassReleaseChecker : Checker<"ClassRelease">,
- HelpText<"Check for sending 'retain', 'release', or 'autorelease' directly to a Class">,
- DescFile<"BasicObjCFoundationChecks.cpp">;
+def DivZeroChecker : Checker<"DivideZero">,
+ HelpText<"Check for division by zero">,
+ DescFile<"DivZeroChecker.cpp">;
-def NSAutoreleasePoolChecker : Checker<"NSAutoreleasePool">,
- HelpText<"Warn for subpar uses of NSAutoreleasePool">,
- DescFile<"NSAutoreleasePoolChecker.cpp">;
+def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">,
+ HelpText<"Check for undefined results of binary operators">,
+ DescFile<"UndefResultChecker.cpp">;
-def ObjCMethSigsChecker : Checker<"MethodSigs">,
- HelpText<"Warn about Objective-C method signatures with type incompatibilities">,
- DescFile<"CheckObjCInstMethSignature.cpp">;
+def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
+ HelpText<"Check that addresses to stack memory do not escape the function">,
+ DescFile<"StackAddrEscapeChecker.cpp">;
-def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">,
- HelpText<"Warn about private ivars that are never used">,
- DescFile<"ObjCUnusedIVarsChecker.cpp">;
+} // end "core"
-} // end "cocoa"
+let ParentPackage = CoreExperimental in {
-def StackAddrEscapeChecker : Checker<"StackAddrEscape">,
- InPackage<Core>,
- HelpText<"Check that addresses to stack memory do not escape the function">,
- DescFile<"StackAddrEscapeChecker.cpp">;
+def CastSizeChecker : Checker<"CastSize">,
+ HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">,
+ DescFile<"CastSizeChecker.cpp">;
-def DeadStoresChecker : Checker<"DeadStores">,
- InPackage<Core>,
- HelpText<"Check for values stored to a variables that are never read afterwards">,
- DescFile<"DeadStoresChecker.cpp">;
+def CastToStructChecker : Checker<"CastToStruct">,
+ HelpText<"Check for cast from non-struct pointer to struct pointer">,
+ DescFile<"CastToStructChecker.cpp">;
-def UnixAPIChecker : Checker<"API">,
- InPackage<Unix>,
- HelpText<"Check calls to various UNIX/Posix functions">,
- DescFile<"UnixAPIChecker.cpp">;
+def FixedAddressChecker : Checker<"FixedAddr">,
+ HelpText<"Check for assignment of a fixed address to a pointer">,
+ DescFile<"FixedAddressChecker.cpp">;
-def MacOSXAPIChecker : Checker<"API">,
- InPackage<MacOSX>,
- HelpText<"Check for proper uses of various Mac OS X APIs">,
- DescFile<"MacOSXAPIChecker.cpp">;
+def PointerArithChecker : Checker<"PointerArithm">,
+ HelpText<"Check for pointer arithmetic on locations other than array elements">,
+ DescFile<"PointerArithChecker">;
-def CFNumberCreateChecker : Checker<"CFNumber">,
- InPackage<MacOSX>,
- HelpText<"Check for proper uses of CFNumberCreate">,
- DescFile<"BasicObjCFoundationChecks.cpp">;
+def PointerSubChecker : Checker<"PointerSub">,
+ HelpText<"Check for pointer subtractions on two pointers pointing to different memory chunks">,
+ DescFile<"PointerSubChecker">;
-def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
- InPackage<MacOSX>,
- HelpText<"Check for null arguments to CFRetain/CFRelease">,
- DescFile<"BasicObjCFoundationChecks.cpp">;
+def SizeofPointerChecker : Checker<"SizeofPtr">,
+ HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
+ DescFile<"CheckSizeofPointer.cpp">;
-def LLVMConventionsChecker : Checker<"Conventions">,
- InPackage<LLVM>,
- HelpText<"Check code for LLVM codebase conventions">,
- DescFile<"LLVMConventionsChecker.cpp">;
+} // end "core.experimental"
-def LiveVariablesDumper : Checker<"DumpLiveVars">,
- InPackage<Debug>,
- HelpText<"Print results of live variable analysis">,
- DescFile<"DebugCheckers.cpp">;
+//===----------------------------------------------------------------------===//
+// Evaluate "builtin" functions.
+//===----------------------------------------------------------------------===//
-def CFGViewer : Checker<"ViewCFG">,
- InPackage<Debug>,
- HelpText<"View Control-Flow Graphs using GraphViz">,
- DescFile<"DebugCheckers.cpp">;
+let ParentPackage = CoreBuiltin in {
-def CFGDumper : Checker<"DumpCFG">,
- InPackage<Debug>,
- HelpText<"Display Control-Flow Graphs">,
- DescFile<"DebugCheckers.cpp">;
+def NoReturnFunctionChecker : Checker<"NoReturnFunctions">,
+ HelpText<"Evaluate \"panic\" functions that are known to not return to the caller">,
+ DescFile<"NoReturnFunctionChecker.cpp">;
+
+def BuiltinFunctionChecker : Checker<"BuiltinFunctions">,
+ HelpText<"Evaluate compiler builtin functions (e.g., alloca())">,
+ DescFile<"BuiltinFunctionChecker.cpp">;
+
+} // end "core.builtin"
//===----------------------------------------------------------------------===//
-// Hidden experimental checkers.
+// Uninitialized values checkers.
//===----------------------------------------------------------------------===//
-let Group = AllExperimental in {
+let ParentPackage = CoreUninitialized in {
+
+def UndefinedArraySubscriptChecker : Checker<"ArraySubscript">,
+ HelpText<"Check for uninitialized values used as array subscripts">,
+ DescFile<"UndefinedArraySubscriptChecker.cpp">;
+
+def UndefinedAssignmentChecker : Checker<"Assign">,
+ HelpText<"Check for assigning uninitialized values">,
+ DescFile<"UndefinedAssignmentChecker.cpp">;
+
+def UndefBranchChecker : Checker<"Branch">,
+ HelpText<"Check for uninitialized values used as branch conditions">,
+ DescFile<"UndefBranchChecker.cpp">;
+
+def UndefCapturedBlockVarChecker : Checker<"CapturedBlockVariable">,
+ HelpText<"Check for blocks that capture uninitialized values">,
+ DescFile<"UndefCapturedBlockVarChecker.cpp">;
+
+def ReturnUndefChecker : Checker<"UndefReturn">,
+ HelpText<"Check for uninitialized values being returned to the caller">,
+ DescFile<"ReturnUndefChecker.cpp">;
+
+} // end "core.uninitialized"
+
+//===----------------------------------------------------------------------===//
+// C++ checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CplusplusExperimental in {
def CStringChecker : Checker<"CString">,
- InPackage<CoreExperimental>,
HelpText<"Check calls to functions in <string.h>">,
DescFile<"CStringChecker.cpp">;
-def UnreachableCodeChecker : Checker<"UnreachableCode">,
- InPackage<CoreExperimental>,
- HelpText<"Check unreachable code">,
- DescFile<"UnreachableCodeChecker.cpp">,
- Hidden; // Must be specified explicitly in order to run.
+def IteratorsChecker : Checker<"Iterators">,
+ HelpText<"Check improper uses of STL vector iterators">,
+ DescFile<"IteratorsChecker.cpp">;
+
+} // end: "cplusplus.experimental"
+
+//===----------------------------------------------------------------------===//
+// Deadcode checkers.
+//===----------------------------------------------------------------------===//
-def IdempotentOperationChecker : Checker<"IdempotentOps">,
- InPackage<CoreExperimental>,
+let ParentPackage = DeadCode in {
+
+def DeadStoresChecker : Checker<"DeadStores">,
+ HelpText<"Check for values stored to variables that are never read afterwards">,
+ DescFile<"DeadStoresChecker.cpp">;
+
+def IdempotentOperationChecker : Checker<"IdempotentOperations">,
HelpText<"Warn about idempotent operations">,
DescFile<"IdempotentOperationChecker.cpp">;
-def CastToStructChecker : Checker<"CastToStruct">,
- InPackage<CoreExperimental>,
- HelpText<"Check for cast from non-struct pointer to struct pointer">,
- DescFile<"CastToStructChecker.cpp">;
+} // end DeadCode
-def FixedAddressChecker : Checker<"FixedAddr">,
- InPackage<CoreExperimental>,
- HelpText<"Check for assignment of a fixed address to a pointer">,
- DescFile<"FixedAddressChecker.cpp">;
+let ParentPackage = DeadCodeExperimental in {
-def PointerArithChecker : Checker<"PointerArithm">,
- InPackage<CoreExperimental>,
- HelpText<"Check for pointer arithmetic on locations other than array elements">,
- DescFile<"PointerArithChecker">;
+def UnreachableCodeChecker : Checker<"UnreachableCode">,
+ HelpText<"Check unreachable code">,
+ DescFile<"UnreachableCodeChecker.cpp">;
-def PointerSubChecker : Checker<"PointerSub">,
- InPackage<CoreExperimental>,
- HelpText<"Check for pointer subtractions on two pointers pointing to different memory chunks">,
- DescFile<"PointerSubChecker">;
+} // end "deadcode.experimental"
-def SizeofPointerChecker : Checker<"SizeofPtr">,
- InPackage<CoreExperimental>,
- HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
- DescFile<"CheckSizeofPointer.cpp">;
+//===----------------------------------------------------------------------===//
+// Security checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = SecurityExperimental in {
def SecuritySyntaxChecker : Checker<"SecuritySyntactic">,
- InPackage<CoreExperimental>,
- HelpText<"Perform quick security checks that require no data flow">,
+ HelpText<"Perform quick security API checks that require no data flow">,
DescFile<"CheckSecuritySyntaxOnly.cpp">;
+def ArrayBoundChecker : Checker<"ArrayBound">,
+ HelpText<"Warn about buffer overflows (older checker)">,
+ DescFile<"ArrayBoundChecker.cpp">;
+
+def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">,
+ HelpText<"Warn about buffer overflows (newer checker)">,
+ DescFile<"ArrayBoundCheckerV2.cpp">;
+
def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">,
- InPackage<CoreExperimental>,
HelpText<"Check for an out-of-bound pointer being returned to callers">,
DescFile<"ReturnPointerRangeChecker.cpp">;
-def ArrayBoundChecker : Checker<"ArrayBound">,
- InPackage<CoreExperimental>,
- HelpText<"Check for an out-of-bound pointer being returned to callers">,
- DescFile<"ArrayBoundChecker.cpp">;
+} // end "security.experimental"
-def CastSizeChecker : Checker<"CastSize">,
- InPackage<CoreExperimental>,
- HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">,
- DescFile<"CastSizeChecker.cpp">;
+//===----------------------------------------------------------------------===//
+// Unix API checkers.
+//===----------------------------------------------------------------------===//
-def ObjCDeallocChecker : Checker<"Dealloc">,
- InPackage<CocoaExperimental>,
- HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
- DescFile<"CheckObjCDealloc.cpp">;
+let ParentPackage = Unix in {
+
+def UnixAPIChecker : Checker<"API">,
+ HelpText<"Check calls to various UNIX/Posix functions">,
+ DescFile<"UnixAPIChecker.cpp">;
+
+} // end "unix"
+
+let ParentPackage = UnixExperimental in {
def ChrootChecker : Checker<"Chroot">,
- InPackage<UnixExperimental>,
HelpText<"Check improper use of chroot">,
DescFile<"ChrootChecker.cpp">;
+def MallocChecker : Checker<"Malloc">,
+ HelpText<"Check for potential memory leaks, double free, and use-after-free problems">,
+ DescFile<"MallocChecker.cpp">;
+
def PthreadLockChecker : Checker<"PthreadLock">,
- InPackage<UnixExperimental>,
HelpText<"Simple lock -> unlock checker">,
DescFile<"PthreadLockChecker.cpp">;
def StreamChecker : Checker<"Stream">,
- InPackage<UnixExperimental>,
HelpText<"Check stream handling functions">,
DescFile<"StreamChecker.cpp">;
+} // end "unix.experimental"
+
+//===----------------------------------------------------------------------===//
+// Mac OS X, Cocoa, and Core Foundation checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = OSX in {
+
+def MacOSXAPIChecker : Checker<"API">,
+ InPackage<OSX>,
+ 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">;
+
+} // end "macosx"
+
+let ParentPackage = Cocoa in {
+
+def ObjCAtSyncChecker : Checker<"AtSync">,
+ HelpText<"Check for null pointers used as mutexes for @synchronized">,
+ DescFile<"ObjCAtSyncChecker.cpp">;
+
+def NilArgChecker : Checker<"NilArg">,
+ HelpText<"Check for prohibited nil arguments to ObjC method calls">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def ClassReleaseChecker : Checker<"ClassRelease">,
+ HelpText<"Check for sending 'retain', 'release', or 'autorelease' directly to a Class">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def VariadicMethodTypeChecker : Checker<"VariadicMethodTypes">,
+ HelpText<"Check for passing non-Objective-C types to variadic methods that expect"
+ "only Objective-C types">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def NSAutoreleasePoolChecker : Checker<"NSAutoreleasePool">,
+ HelpText<"Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode">,
+ DescFile<"NSAutoreleasePoolChecker.cpp">;
+
+def ObjCMethSigsChecker : Checker<"IncompatibleMethodTypes">,
+ HelpText<"Warn about Objective-C method signatures with type incompatibilities">,
+ DescFile<"CheckObjCInstMethSignature.cpp">;
+
+def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">,
+ HelpText<"Warn about private ivars that are never used">,
+ DescFile<"ObjCUnusedIVarsChecker.cpp">;
+
+def NSErrorChecker : Checker<"NSError">,
+ HelpText<"Check usage of NSError** parameters">,
+ DescFile<"NSErrorChecker.cpp">;
+
+} // end "cocoa"
+
+let ParentPackage = CocoaExperimental in {
+
+def ObjCSelfInitChecker : Checker<"SelfInit">,
+ HelpText<"Check that 'self' is properly initialized inside an initializer method">,
+ DescFile<"ObjCSelfInitChecker.cpp">;
+
+def ObjCDeallocChecker : Checker<"Dealloc">,
+ HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
+ DescFile<"CheckObjCDealloc.cpp">;
+
+} // end "cocoa.experimental"
+
+let ParentPackage = CoreFoundation in {
+
+def CFNumberCreateChecker : Checker<"CFNumber">,
+ HelpText<"Check for proper uses of CFNumberCreate">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def CFRetainReleaseChecker : Checker<"CFRetainRelease">,
+ HelpText<"Check for null arguments to CFRetain/CFRelease">,
+ DescFile<"BasicObjCFoundationChecks.cpp">;
+
+def CFErrorChecker : Checker<"CFError">,
+ HelpText<"Check usage of CFErrorRef* parameters">,
+ DescFile<"NSErrorChecker.cpp">;
}
+
+//===----------------------------------------------------------------------===//
+// Checkers for LLVM development.
+//===----------------------------------------------------------------------===//
+
+def LLVMConventionsChecker : Checker<"Conventions">,
+ InPackage<LLVM>,
+ HelpText<"Check code for LLVM codebase conventions">,
+ DescFile<"LLVMConventionsChecker.cpp">;
+
+//===----------------------------------------------------------------------===//
+// Debugging checkers (for analyzer development).
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Debug in {
+
+def LiveVariablesDumper : Checker<"DumpLiveVars">,
+ HelpText<"Print results of live variable analysis">,
+ DescFile<"DebugCheckers.cpp">;
+
+def CFGViewer : Checker<"ViewCFG">,
+ HelpText<"View Control-Flow Graphs using GraphViz">,
+ DescFile<"DebugCheckers.cpp">;
+
+def CFGDumper : Checker<"DumpCFG">,
+ HelpText<"Display Control-Flow Graphs">,
+ DescFile<"DebugCheckers.cpp">;
+
+def AnalyzerStatsChecker : Checker<"Stats">,
+ HelpText<"Emit warnings with analyzer statistics">,
+ DescFile<"AnalyzerStatsChecker.cpp">;
+
+} // end "debug"
+
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index b6eef6d150d4..50b57d1ae497 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -38,7 +38,7 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
// ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
// | |
// bug<--foo()-- JAIL_ENTERED<--foo()--
-class ChrootChecker : public CheckerV2<eval::Call, check::PreStmt<CallExpr> > {
+class ChrootChecker : public Checker<eval::Call, check::PreStmt<CallExpr> > {
mutable IdentifierInfo *II_chroot, *II_chdir;
// This bug refers to possibly break out of a chroot() jail.
mutable llvm::OwningPtr<BuiltinBug> BT_BreakJail;
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
index 5c0c9504db03..291f8e01f4b9 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp
@@ -45,17 +45,54 @@ struct StaticCheckerInfoRec {
const char *FullName;
void (*RegFunc)(CheckerManager &mgr);
const char *HelpText;
+ int GroupIndex;
bool Hidden;
};
+struct StaticPackageInfoRec {
+ const char *FullName;
+ int GroupIndex;
+ bool Hidden;
+};
+
+struct StaticGroupInfoRec {
+ const char *FullName;
+};
+
} // end anonymous namespace.
+static const StaticPackageInfoRec StaticPackageInfo[] = {
+#define GET_PACKAGES
+#define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \
+ { FULLNAME, GROUPINDEX, HIDDEN },
+#include "Checkers.inc"
+ { 0, -1, 0 }
+#undef PACKAGE
+#undef GET_PACKAGES
+};
+
+static const unsigned NumPackages = sizeof(StaticPackageInfo)
+ / sizeof(StaticPackageInfoRec) - 1;
+
+static const StaticGroupInfoRec StaticGroupInfo[] = {
+#define GET_GROUPS
+#define GROUP(FULLNAME) \
+ { FULLNAME },
+#include "Checkers.inc"
+ { 0 }
+#undef GROUP
+#undef GET_GROUPS
+};
+
+static const unsigned NumGroups = sizeof(StaticGroupInfo)
+ / sizeof(StaticGroupInfoRec) - 1;
+
static const StaticCheckerInfoRec StaticCheckerInfo[] = {
#define GET_CHECKERS
-#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,HIDDEN) \
- { FULLNAME, register##CLASS, HELPTEXT, HIDDEN },
+#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
+ { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN },
#include "Checkers.inc"
- { 0, 0, 0, 0}
+ { 0, 0, 0, -1, 0}
#undef CHECKER
#undef GET_CHECKERS
};
@@ -101,8 +138,9 @@ static void collectCheckers(const CheckNameOption *checkName,
if (const short *member = checkName->Members) {
if (enable) {
- if (collectHidden || !StaticCheckerInfo[*member].Hidden)
- checkers.insert(&StaticCheckerInfo[*member]);
+ for (; *member != -1; ++member)
+ if (collectHidden || !StaticCheckerInfo[*member].Hidden)
+ checkers.insert(&StaticCheckerInfo[*member]);
} else {
for (; *member != -1; ++member)
checkers.erase(&StaticCheckerInfo[*member]);
@@ -144,6 +182,48 @@ void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
}
}
+//===----------------------------------------------------------------------===//
+// Printing Help.
+//===----------------------------------------------------------------------===//
+
+static void printPackageOption(llvm::raw_ostream &OS) {
+ // Find the maximum option length.
+ unsigned OptionFieldWidth = 0;
+ for (unsigned i = 0; i != NumPackages; ++i) {
+ // Limit the amount of padding we are willing to give up for alignment.
+ unsigned Length = strlen(StaticPackageInfo[i].FullName);
+ if (Length <= 30)
+ OptionFieldWidth = std::max(OptionFieldWidth, Length);
+ }
+
+ const unsigned InitialPad = 2;
+ for (unsigned i = 0; i != NumPackages; ++i) {
+ const StaticPackageInfoRec &package = StaticPackageInfo[i];
+ const std::string &Option = package.FullName;
+ int Pad = OptionFieldWidth - int(Option.size());
+ OS.indent(InitialPad) << Option;
+
+ if (package.GroupIndex != -1 || package.Hidden) {
+ // Break on long option names.
+ if (Pad < 0) {
+ OS << "\n";
+ Pad = OptionFieldWidth + InitialPad;
+ }
+ OS.indent(Pad + 1) << "[";
+ if (package.GroupIndex != -1) {
+ OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName;
+ if (package.Hidden)
+ OS << ", ";
+ }
+ if (package.Hidden)
+ OS << "Hidden";
+ OS << "]";
+ }
+
+ OS << "\n";
+ }
+}
+
typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
@@ -161,6 +241,7 @@ static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
for (SortedCheckers::iterator
I = checkers.begin(), E = checkers.end(); I != E; ++I) {
const std::string &Option = I->first;
+ const StaticCheckerInfoRec &checker = *I->second;
int Pad = OptionFieldWidth - int(Option.size());
OS.indent(InitialPad) << Option;
@@ -169,11 +250,36 @@ static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
OS << "\n";
Pad = OptionFieldWidth + InitialPad;
}
- OS.indent(Pad + 1) << I->second->HelpText << '\n';
+ OS.indent(Pad + 1) << checker.HelpText;
+
+ if (checker.GroupIndex != -1 || checker.Hidden) {
+ OS << " [";
+ if (checker.GroupIndex != -1) {
+ OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName;
+ if (checker.Hidden)
+ OS << ", ";
+ }
+ if (checker.Hidden)
+ OS << "Hidden";
+ OS << "]";
+ }
+
+ OS << "\n";
}
}
void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
+ OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n";
+
+ OS << "\nGROUPS:\n";
+ for (unsigned i = 0; i != NumGroups; ++i)
+ OS.indent(2) << StaticGroupInfo[i].FullName << "\n";
+
+ OS << "\nPACKAGES:\n";
+ printPackageOption(OS);
+
+ OS << "\nCHECKERS:\n";
+
// Sort checkers according to their full name.
SortedCheckers checkers;
for (unsigned i = 0; i != NumCheckers; ++i)
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index 73239f55b4e4..5524b0f53276 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -21,7 +21,7 @@ namespace ento {
class CheckerManager;
#define GET_CHECKERS
-#define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,HIDDEN) \
+#define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
void register##CLASS(CheckerManager &mgr);
#include "Checkers.inc"
#undef CHECKER
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 3b39372725a4..bc1d823dde03 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -13,8 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.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"
@@ -342,7 +341,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class DeadStoresChecker : public CheckerV2<check::ASTCodeBody> {
+class DeadStoresChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 091d99b1352c..486b7f7feb1b 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
@@ -24,7 +24,7 @@ using namespace ento;
//===----------------------------------------------------------------------===//
namespace {
-class LiveVariablesDumper : public CheckerV2<check::ASTCodeBody> {
+class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
@@ -44,7 +44,7 @@ void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
//===----------------------------------------------------------------------===//
namespace {
-class CFGViewer : public CheckerV2<check::ASTCodeBody> {
+class CFGViewer : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
@@ -64,7 +64,7 @@ void ento::registerCFGViewer(CheckerManager &mgr) {
//===----------------------------------------------------------------------===//
namespace {
-class CFGDumper : public CheckerV2<check::ASTCodeBody> {
+class CFGDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 606ac4ab4e4e..baaf8b3aff8a 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -12,51 +12,31 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
namespace {
-class DereferenceChecker : public Checker {
- BuiltinBug *BT_null;
- BuiltinBug *BT_undef;
- llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
+class DereferenceChecker
+ : public Checker< check::Location,
+ EventDispatcher<ImplicitNullDerefEvent> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT_null;
+ mutable llvm::OwningPtr<BuiltinBug> BT_undef;
+
public:
- DereferenceChecker() : BT_null(0), BT_undef(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
- bool isLoad);
-
- std::pair<ExplodedNode * const*, ExplodedNode * const*>
- getImplicitNodes() const {
- return std::make_pair(ImplicitNullDerefNodes.data(),
- ImplicitNullDerefNodes.data() +
- ImplicitNullDerefNodes.size());
- }
- void AddDerefSource(llvm::raw_ostream &os,
- llvm::SmallVectorImpl<SourceRange> &Ranges,
- const Expr *Ex, bool loadedFrom = false);
+ void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
+
+ static void AddDerefSource(llvm::raw_ostream &os,
+ llvm::SmallVectorImpl<SourceRange> &Ranges,
+ const Expr *Ex, bool loadedFrom = false);
};
} // end anonymous namespace
-void ento::RegisterDereferenceChecker(ExprEngine &Eng) {
- Eng.registerCheck(new DereferenceChecker());
-}
-
-std::pair<ExplodedNode * const *, ExplodedNode * const *>
-ento::GetImplicitNullDereferences(ExprEngine &Eng) {
- DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
- if (!checker)
- return std::make_pair((ExplodedNode * const *) 0,
- (ExplodedNode * const *) 0);
- return checker->getImplicitNodes();
-}
-
void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
llvm::SmallVectorImpl<SourceRange> &Ranges,
const Expr *Ex,
@@ -85,13 +65,13 @@ void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
}
}
-void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,
- SVal l, bool isLoad) {
+void DereferenceChecker::checkLocation(SVal l, bool isLoad,
+ CheckerContext &C) const {
// Check for dereference of an undefined value.
if (l.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_undef)
- BT_undef = new BuiltinBug("Dereference of undefined pointer value");
+ BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
@@ -108,6 +88,7 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,
if (!isa<Loc>(location))
return;
+ const Stmt *S = C.getStmt();
const GRState *state = C.getState();
const GRState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->assume(location);
@@ -123,7 +104,7 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,
// We know that 'location' cannot be non-null. This is what
// we call an "explicit" null dereference.
if (!BT_null)
- BT_null = new BuiltinBug("Dereference of null pointer");
+ BT_null.reset(new BuiltinBug("Dereference of null pointer"));
llvm::SmallString<100> buf;
llvm::SmallVector<SourceRange, 2> Ranges;
@@ -195,11 +176,17 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,
// Otherwise, we have the case where the location could either be
// null or not-null. Record the error node as an "implicit" null
// dereference.
- if (ExplodedNode *N = C.generateSink(nullState))
- ImplicitNullDerefNodes.push_back(N);
+ if (ExplodedNode *N = C.generateSink(nullState)) {
+ ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() };
+ dispatchEvent(event);
+ }
}
}
// From this point forward, we know that the location is not null.
C.addTransition(notNullState);
}
+
+void ento::registerDereferenceChecker(CheckerManager &mgr) {
+ mgr.registerChecker<DereferenceChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 20cc90492246..07fb5aa998be 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -12,34 +12,25 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
-class DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
- BuiltinBug *BT;
+class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- DivZeroChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
} // end anonymous namespace
-void ento::RegisterDivZeroChecker(ExprEngine &Eng) {
- Eng.registerCheck(new DivZeroChecker());
-}
-
-void *DivZeroChecker::getTag() {
- static int x;
- return &x;
-}
-
-void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
BinaryOperator::Opcode Op = B->getOpcode();
if (Op != BO_Div &&
Op != BO_Rem &&
@@ -67,7 +58,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
if (stateZero && !stateNotZero) {
if (ExplodedNode *N = C.generateSink(stateZero)) {
if (!BT)
- BT = new BuiltinBug("Division by zero");
+ BT.reset(new BuiltinBug("Division by zero"));
EnhancedBugReport *R =
new EnhancedBugReport(*BT, BT->getDescription(), N);
@@ -84,3 +75,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
// zero denom case for now.
C.addTransition(stateNotZero);
}
+
+void ento::registerDivZeroChecker(CheckerManager &mgr) {
+ mgr.registerChecker<DivZeroChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
deleted file mode 100644
index 990ba1c02b94..000000000000
--- a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-//=-- ExperimentalChecks.h ----------------------------------------*- 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 functions to instantiate and register experimental
-// checks in ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#include "InternalChecks.h"
-#include "ExperimentalChecks.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-
-using namespace clang;
-using namespace ento;
-
-void ento::RegisterExperimentalChecks(ExprEngine &Eng) {
- // These are checks that never belong as internal checks
- // within ExprEngine.
- RegisterMallocChecker(Eng); // ArrayBoundChecker depends on this.
-}
diff --git a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.h b/lib/StaticAnalyzer/Checkers/ExperimentalChecks.h
deleted file mode 100644
index 1f38ad77ebde..000000000000
--- a/lib/StaticAnalyzer/Checkers/ExperimentalChecks.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//=-- ExperimentalChecks.h ----------------------------------------*- 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 functions to instantiate and register experimental
-// checks in ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS
-#define LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS
-
-namespace clang {
-
-namespace ento {
-
-class ExprEngine;
-
-void RegisterAnalyzerStatsChecker(ExprEngine &Eng);
-void RegisterMallocChecker(ExprEngine &Eng);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index d7b27b563784..d699deecd768 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class FixedAddressChecker
- : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ : public Checker< check::PreStmt<BinaryOperator> > {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index 83d9668c48fa..b0c07fc7d264 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -46,7 +46,7 @@
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.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"
@@ -59,14 +59,13 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/ErrorHandling.h"
-#include <deque>
using namespace clang;
using namespace ento;
namespace {
class IdempotentOperationChecker
- : public CheckerV2<check::PreStmt<BinaryOperator>,
+ : public Checker<check::PreStmt<BinaryOperator>,
check::PostStmt<BinaryOperator>,
check::EndAnalysis> {
public:
@@ -336,10 +335,9 @@ void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B,
= cast<StmtPoint>(C.getPredecessor()->getLocation()).getStmt();
// Ignore implicit calls to setters.
- if (isa<ObjCPropertyRefExpr>(predStmt))
+ if (!isa<BinaryOperator>(predStmt))
return;
-
- assert(isa<BinaryOperator>(predStmt));
+
Data.explodedNodes.Add(C.getPredecessor());
}
@@ -532,12 +530,12 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
const CFGBlock *CB,
const CoreEngine &CE) {
- CFGReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis();
+ CFGReverseBlockReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis();
// Test for reachability from any aborted blocks to this block
- typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
- for (AbortedIterator I = CE.blocks_aborted_begin(),
- E = CE.blocks_aborted_end(); I != E; ++I) {
+ typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
+ for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
+ E = CE.blocks_exhausted_end(); I != E; ++I) {
const BlockEdge &BE = I->first;
// The destination block on the BlockEdge is the first block that was not
@@ -551,16 +549,25 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
if (destBlock == CB || CRA->isReachable(destBlock, CB))
return false;
}
+
+ // Test for reachability from blocks we just gave up on.
+ typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
+ for (AbortedIterator I = CE.blocks_aborted_begin(),
+ E = CE.blocks_aborted_end(); I != E; ++I) {
+ const CFGBlock *destBlock = I->first;
+ if (destBlock == CB || CRA->isReachable(destBlock, CB))
+ return false;
+ }
// For the items still on the worklist, see if they are in blocks that
// can eventually reach 'CB'.
class VisitWL : public WorkList::Visitor {
const CFGStmtMap *CBM;
const CFGBlock *TargetBlock;
- CFGReachabilityAnalysis &CRA;
+ CFGReverseBlockReachabilityAnalysis &CRA;
public:
VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock,
- CFGReachabilityAnalysis &cra)
+ CFGReverseBlockReachabilityAnalysis &cra)
: CBM(cbm), TargetBlock(targetBlock), CRA(cra) {}
virtual bool visit(const WorkListUnit &U) {
ProgramPoint P = U.getNode()->getLocation();
@@ -580,7 +587,7 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
if (!B)
return true;
- return CRA.isReachable(B, TargetBlock);
+ return B == TargetBlock || CRA.isReachable(B, TargetBlock);
}
};
VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA);
@@ -641,9 +648,10 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex,
return false;
// Cases requiring custom logic
- case Stmt::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *SE = cast<const SizeOfAlignOfExpr>(Ex);
- if (!SE->isSizeOf())
+ case Stmt::UnaryExprOrTypeTraitExprClass: {
+ const UnaryExprOrTypeTraitExpr *SE =
+ cast<const UnaryExprOrTypeTraitExpr>(Ex);
+ if (SE->getKind() != UETT_SizeOf)
return false;
return SE->getTypeOfArgument()->isVariableArrayType();
}
diff --git a/lib/StaticAnalyzer/Checkers/InternalChecks.h b/lib/StaticAnalyzer/Checkers/InternalChecks.h
deleted file mode 100644
index e7c38ee25d8f..000000000000
--- a/lib/StaticAnalyzer/Checkers/InternalChecks.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//=-- InternalChecks.h- Builtin ExprEngine Checks -------------------*- 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 functions to instantiate and register the "built-in"
-// checks in ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS
-#define LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS
-
-namespace clang {
-
-namespace ento {
-
-class ExprEngine;
-
-// Foundational checks that handle basic semantics.
-void RegisterAdjustedReturnValueChecker(ExprEngine &Eng);
-void RegisterArrayBoundCheckerV2(ExprEngine &Eng);
-void RegisterAttrNonNullChecker(ExprEngine &Eng);
-void RegisterBuiltinFunctionChecker(ExprEngine &Eng);
-void RegisterCallAndMessageChecker(ExprEngine &Eng);
-void RegisterDereferenceChecker(ExprEngine &Eng);
-void RegisterDivZeroChecker(ExprEngine &Eng);
-void RegisterNoReturnFunctionChecker(ExprEngine &Eng);
-void RegisterReturnUndefChecker(ExprEngine &Eng);
-void RegisterUndefBranchChecker(ExprEngine &Eng);
-void RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng);
-void RegisterUndefResultChecker(ExprEngine &Eng);
-void RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng);
-void RegisterUndefinedAssignmentChecker(ExprEngine &Eng);
-void RegisterVLASizeChecker(ExprEngine &Eng);
-
-// API checks.
-void RegisterOSAtomicChecker(ExprEngine &Eng);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
new file mode 100644
index 000000000000..e4e5f54770b3
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
@@ -0,0 +1,582 @@
+//=== IteratorsChecker.cpp - Check for Invalidated Iterators ------*- C++ -*----
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines IteratorsChecker, a number of small checks for conditions
+// leading to invalid iterators being used.
+// FIXME: Currently only supports 'vector' and 'deque'
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/SourceManager.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringSwitch.h"
+
+
+using namespace clang;
+using namespace ento;
+
+// This is the state associated with each iterator which includes both the
+// kind of state and the instance used to initialize it.
+// FIXME: add location where invalidated for better error reporting.
+namespace {
+class RefState {
+ enum Kind { BeginValid, EndValid, Invalid, Undefined, Unknown } K;
+ const void *VR;
+
+public:
+ RefState(Kind k, const void *vr) : K(k), VR(vr) {}
+
+ bool isValid() const { return K == BeginValid || K == EndValid; }
+ bool isInvalid() const { return K == Invalid; }
+ bool isUndefined() const { return K == Undefined; }
+ bool isUnknown() const { return K == Unknown; }
+ const MemRegion *getMemRegion() const {
+ if (K == BeginValid || K == EndValid)
+ return(const MemRegion *)VR;
+ return 0;
+ }
+ const MemberExpr *getMemberExpr() const {
+ if (K == Invalid)
+ return(const MemberExpr *)VR;
+ return 0;
+ }
+
+ bool operator==(const RefState &X) const {
+ return K == X.K && VR == X.VR;
+ }
+
+ static RefState getBeginValid(const MemRegion *vr) {
+ assert(vr);
+ return RefState(BeginValid, vr);
+ }
+ static RefState getEndValid(const MemRegion *vr) {
+ assert(vr);
+ return RefState(EndValid, vr);
+ }
+ static RefState getInvalid( const MemberExpr *ME ) {
+ return RefState(Invalid, ME);
+ }
+ static RefState getUndefined( void ) {
+ return RefState(Undefined, 0);
+ }
+ static RefState getUnknown( void ) {
+ return RefState(Unknown, 0);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ ID.AddPointer(VR);
+ }
+};
+
+enum RefKind { NoKind, VectorKind, VectorIteratorKind };
+
+class IteratorsChecker :
+ public Checker<check::PreStmt<CXXOperatorCallExpr>,
+ check::PreStmt<DeclStmt>,
+ check::PreStmt<CXXMemberCallExpr>,
+ check::PreStmt<CallExpr> >
+ {
+ // Used when parsing iterators and vectors and deques.
+ BuiltinBug *BT_Invalid, *BT_Undefined, *BT_Incompatible;
+
+public:
+ IteratorsChecker() :
+ BT_Invalid(0), BT_Undefined(0), BT_Incompatible(0)
+ {}
+ static void *getTag() { static int tag; return &tag; }
+
+ // Checker entry points.
+ void checkPreStmt(const CXXOperatorCallExpr *OCE,
+ CheckerContext &C) const;
+
+ void checkPreStmt(const DeclStmt *DS,
+ CheckerContext &C) const;
+
+ void checkPreStmt(const CXXMemberCallExpr *MCE,
+ CheckerContext &C) const;
+
+ void checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const;
+
+private:
+ const GRState *handleAssign(const GRState *state, const Expr *lexp,
+ const Expr *rexp, const LocationContext *LC) const;
+ const GRState *handleAssign(const GRState *state, const MemRegion *MR,
+ const Expr *rexp, const LocationContext *LC) const;
+ const GRState *invalidateIterators(const GRState *state, const MemRegion *MR,
+ const MemberExpr *ME) const;
+ void checkExpr(CheckerContext &C, const Expr *E) const;
+ void checkArgs(CheckerContext &C, const CallExpr *CE) const;
+ const MemRegion *getRegion(const GRState *state, const Expr *E,
+ const LocationContext *LC) const;
+ const DeclRefExpr *getDeclRefExpr(const Expr *E) const;
+};
+
+class IteratorState {
+public:
+ typedef llvm::ImmutableMap<const MemRegion *, RefState> EntryMap;
+};
+} //end anonymous namespace
+
+namespace clang {
+ namespace ento {
+ template <>
+ struct GRStateTrait<IteratorState>
+ : public GRStatePartialTrait<IteratorState::EntryMap> {
+ static void *GDMIndex() { return IteratorsChecker::getTag(); }
+ };
+ }
+}
+
+void ento::registerIteratorsChecker(CheckerManager &mgr) {
+ mgr.registerChecker<IteratorsChecker>();
+}
+
+// ===============================================
+// Utility functions used by visitor functions
+// ===============================================
+
+// check a templated type for std::vector or std::deque
+static RefKind getTemplateKind(const NamedDecl *td) {
+ const DeclContext *dc = td->getDeclContext();
+ const NamespaceDecl *nameSpace = dyn_cast<NamespaceDecl>(dc);
+ if (!nameSpace || !isa<TranslationUnitDecl>(nameSpace->getDeclContext())
+ || nameSpace->getName() != "std")
+ return NoKind;
+
+ llvm::StringRef name = td->getName();
+ return llvm::StringSwitch<RefKind>(name)
+ .Cases("vector", "deque", VectorKind)
+ .Default(NoKind);
+}
+
+static RefKind getTemplateKind(const DeclContext *dc) {
+ if (const ClassTemplateSpecializationDecl *td =
+ dyn_cast<ClassTemplateSpecializationDecl>(dc))
+ return getTemplateKind(cast<NamedDecl>(td));
+ return NoKind;
+}
+
+static RefKind getTemplateKind(const TypedefType *tdt) {
+ const TypedefNameDecl *td = tdt->getDecl();
+ RefKind parentKind = getTemplateKind(td->getDeclContext());
+ if (parentKind == VectorKind) {
+ return llvm::StringSwitch<RefKind>(td->getName())
+ .Cases("iterator",
+ "const_iterator",
+ "reverse_iterator", VectorIteratorKind)
+ .Default(NoKind);
+ }
+ return NoKind;
+}
+
+static RefKind getTemplateKind(const TemplateSpecializationType *tsp) {
+ const TemplateName &tname = tsp->getTemplateName();
+ TemplateDecl *td = tname.getAsTemplateDecl();
+ if (!td)
+ return NoKind;
+ return getTemplateKind(td);
+}
+
+static RefKind getTemplateKind(QualType T) {
+ if (const TemplateSpecializationType *tsp =
+ T->getAs<TemplateSpecializationType>()) {
+ return getTemplateKind(tsp);
+ }
+ if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) {
+ QualType namedType = ET->getNamedType();
+ if (const TypedefType *tdt = namedType->getAs<TypedefType>())
+ return getTemplateKind(tdt);
+ if (const TemplateSpecializationType *tsp =
+ namedType->getAs<TemplateSpecializationType>()) {
+ return getTemplateKind(tsp);
+ }
+ }
+ return NoKind;
+}
+
+// Iterate through our map and invalidate any iterators that were
+// initialized fromt the specified instance MemRegion.
+const GRState *IteratorsChecker::invalidateIterators(const GRState *state,
+ const MemRegion *MR, const MemberExpr *ME) const {
+ IteratorState::EntryMap Map = state->get<IteratorState>();
+ if (Map.isEmpty())
+ return state;
+
+ // Loop over the entries in the current state.
+ // The key doesn't change, so the map iterators won't change.
+ for (IteratorState::EntryMap::iterator I = Map.begin(), E = Map.end();
+ I != E; ++I) {
+ RefState RS = I.getData();
+ if (RS.getMemRegion() == MR)
+ state = state->set<IteratorState>(I.getKey(), RefState::getInvalid(ME));
+ }
+
+ return state;
+}
+
+// Handle assigning to an iterator where we don't have the LValue MemRegion.
+const GRState *IteratorsChecker::handleAssign(const GRState *state,
+ const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
+ // Skip the cast if present.
+ if (isa<ImplicitCastExpr>(lexp))
+ lexp = dyn_cast<ImplicitCastExpr>(lexp)->getSubExpr();
+ SVal sv = state->getSVal(lexp);
+ const MemRegion *MR = sv.getAsRegion();
+ if (!MR)
+ return state;
+ RefKind kind = getTemplateKind(lexp->getType());
+
+ // If assigning to a vector, invalidate any iterators currently associated.
+ if (kind == VectorKind)
+ return invalidateIterators(state, MR, 0);
+
+ // Make sure that we are assigning to an iterator.
+ if (getTemplateKind(lexp->getType()) != VectorIteratorKind)
+ return state;
+ return handleAssign(state, MR, rexp, LC);
+}
+
+// handle assigning to an iterator
+const GRState *IteratorsChecker::handleAssign(const GRState *state,
+ const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
+ // Assume unknown until we find something definite.
+ state = state->set<IteratorState>(MR, RefState::getUnknown());
+ if (isa<ImplicitCastExpr>(rexp))
+ rexp = dyn_cast<ImplicitCastExpr>(rexp)->getSubExpr();
+ // Need to handle three cases: MemberCall, copy, copy with addition.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) {
+ // Handle MemberCall.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee())) {
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
+ if (!DRE)
+ return state;
+ // Verify that the type is std::vector<T>.
+ if (getTemplateKind(DRE->getType()) != VectorKind)
+ return state;
+ // Now get the MemRegion associated with the instance.
+ const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
+ if (!VD)
+ return state;
+ const MemRegion *IMR = state->getRegion(VD, LC);
+ if (!IMR)
+ return state;
+ // Finally, see if it is one of the calls that will create
+ // a valid iterator and mark it if so, else mark as Unknown.
+ llvm::StringRef mName = ME->getMemberDecl()->getName();
+
+ if (llvm::StringSwitch<bool>(mName)
+ .Cases("begin", "insert", "erase", true).Default(false)) {
+ return state->set<IteratorState>(MR, RefState::getBeginValid(IMR));
+ }
+ if (mName == "end")
+ return state->set<IteratorState>(MR, RefState::getEndValid(IMR));
+
+ return state->set<IteratorState>(MR, RefState::getUnknown());
+ }
+ }
+ // Handle straight copy from another iterator.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rexp)) {
+ if (getTemplateKind(DRE->getType()) != VectorIteratorKind)
+ return state;
+ // Now get the MemRegion associated with the instance.
+ const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
+ if (!VD)
+ return state;
+ const MemRegion *IMR = state->getRegion(VD, LC);
+ if (!IMR)
+ return state;
+ // Get the RefState of the iterator being copied.
+ const RefState *RS = state->get<IteratorState>(IMR);
+ if (!RS)
+ return state;
+ // Use it to set the state of the LValue.
+ return state->set<IteratorState>(MR, *RS);
+ }
+ // If we have operator+ or operator- ...
+ if (const CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(rexp)) {
+ OverloadedOperatorKind Kind = OCE->getOperator();
+ if (Kind == OO_Plus || Kind == OO_Minus) {
+ // Check left side of tree for a valid value.
+ state = handleAssign( state, MR, OCE->getArg(0), LC);
+ const RefState *RS = state->get<IteratorState>(MR);
+ // If found, return it.
+ if (!RS->isUnknown())
+ return state;
+ // Otherwise return what we find in the right side.
+ return handleAssign(state, MR, OCE->getArg(1), LC);
+ }
+ }
+ // Fall through if nothing matched.
+ return state;
+}
+
+// Iterate through the arguments looking for an Invalid or Undefined iterator.
+void IteratorsChecker::checkArgs(CheckerContext &C, const CallExpr *CE) const {
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
+ checkExpr(C, *I);
+ }
+}
+
+// Get the DeclRefExpr associated with the expression.
+const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const {
+ // If it is a CXXConstructExpr, need to get the subexpression.
+ if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) {
+ if (CE->getNumArgs()== 1) {
+ CXXConstructorDecl *CD = CE->getConstructor();
+ if (CD->isTrivial())
+ E = CE->getArg(0);
+ }
+ }
+ if (isa<ImplicitCastExpr>(E))
+ E = dyn_cast<ImplicitCastExpr>(E)->getSubExpr();
+ // If it isn't one of our types, don't do anything.
+ if (getTemplateKind(E->getType()) != VectorIteratorKind)
+ return NULL;
+ return dyn_cast<DeclRefExpr>(E);
+}
+
+// Get the MemRegion associated with the expresssion.
+const MemRegion *IteratorsChecker::getRegion(const GRState *state,
+ const Expr *E, const LocationContext *LC) const {
+ const DeclRefExpr *DRE = getDeclRefExpr(E);
+ if (!DRE)
+ return NULL;
+ const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
+ if (!VD)
+ return NULL;
+ // return the MemRegion associated with the iterator
+ return state->getRegion(VD, LC);
+}
+
+// Check the expression and if it is an iterator, generate a diagnostic
+// if the iterator is not valid.
+// FIXME: this method can generate new nodes, and subsequent logic should
+// use those nodes. We also cannot create multiple nodes at one ProgramPoint
+// with the same tag.
+void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
+ const GRState *state = C.getState();
+ const MemRegion *MR = getRegion(state, E,
+ C.getPredecessor()->getLocationContext());
+ if (!MR)
+ return;
+
+ // Get the state associated with the iterator.
+ const RefState *RS = state->get<IteratorState>(MR);
+ if (!RS)
+ return;
+ if (RS->isInvalid()) {
+ if (ExplodedNode *N = C.generateNode()) {
+ if (!BT_Invalid)
+ // FIXME: We are eluding constness here.
+ const_cast<IteratorsChecker*>(this)->BT_Invalid = new BuiltinBug("");
+
+ std::string msg;
+ const MemberExpr *ME = RS->getMemberExpr();
+ if (ME) {
+ std::string name = ME->getMemberNameInfo().getAsString();
+ msg = "Attempt to use an iterator made invalid by call to '" +
+ name + "'";
+ }
+ else {
+ msg = "Attempt to use an iterator made invalid by copying another "
+ "container to its container";
+ }
+
+ EnhancedBugReport *R = new EnhancedBugReport(*BT_Invalid, msg, N);
+ R->addRange(getDeclRefExpr(E)->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+ else if (RS->isUndefined()) {
+ if (ExplodedNode *N = C.generateNode()) {
+ if (!BT_Undefined)
+ // FIXME: We are eluding constness here.
+ const_cast<IteratorsChecker*>(this)->BT_Undefined =
+ new BuiltinBug("Use of iterator that is not defined");
+
+ EnhancedBugReport *R = new EnhancedBugReport(*BT_Undefined,
+ BT_Undefined->getDescription(), N);
+ R->addRange(getDeclRefExpr(E)->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+}
+
+// ===============================================
+// Path analysis visitor functions
+// ===============================================
+
+// For a generic Call, just check the args for bad iterators.
+void IteratorsChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const{
+
+ // FIXME: These checks are to currently work around a bug
+ // in CheckerManager.
+ if (isa<CXXOperatorCallExpr>(CE))
+ return;
+ if (isa<CXXMemberCallExpr>(CE))
+ return;
+
+ checkArgs(C, CE);
+}
+
+// Handle operator calls. First, if it is operator=, check the argument,
+// and handle assigning and set target state appropriately. Otherwise, for
+// other operators, check the args for bad iterators and handle comparisons.
+void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
+ CheckerContext &C) const
+{
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ const GRState *state = C.getState();
+ OverloadedOperatorKind Kind = OCE->getOperator();
+ if (Kind == OO_Equal) {
+ checkExpr(C, OCE->getArg(1));
+ state = handleAssign(state, OCE->getArg(0), OCE->getArg(1), LC);
+ C.addTransition(state);
+ return;
+ }
+ else {
+ checkArgs(C, OCE);
+ // If it is a compare and both are iterators, ensure that they are for
+ // the same container.
+ if (Kind == OO_EqualEqual || Kind == OO_ExclaimEqual ||
+ Kind == OO_Less || Kind == OO_LessEqual ||
+ Kind == OO_Greater || Kind == OO_GreaterEqual) {
+ const MemRegion *MR0, *MR1;
+ MR0 = getRegion(state, OCE->getArg(0), LC);
+ if (!MR0)
+ return;
+ MR1 = getRegion(state, OCE->getArg(1), LC);
+ if (!MR1)
+ return;
+ const RefState *RS0, *RS1;
+ RS0 = state->get<IteratorState>(MR0);
+ if (!RS0)
+ return;
+ RS1 = state->get<IteratorState>(MR1);
+ if (!RS1)
+ return;
+ if (RS0->getMemRegion() != RS1->getMemRegion()) {
+ if (ExplodedNode *N = C.generateNode()) {
+ if (!BT_Incompatible)
+ const_cast<IteratorsChecker*>(this)->BT_Incompatible =
+ new BuiltinBug(
+ "Cannot compare iterators from different containers");
+
+ EnhancedBugReport *R = new EnhancedBugReport(*BT_Incompatible,
+ BT_Incompatible->getDescription(), N);
+ R->addRange(OCE->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+ }
+ }
+}
+
+// Need to handle DeclStmts to pick up initializing of iterators and to mark
+// uninitialized ones as Undefined.
+void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
+ CheckerContext &C) const {
+ const Decl* D = *DS->decl_begin();
+ const VarDecl* VD = dyn_cast<VarDecl>(D);
+ // Only care about iterators.
+ if (getTemplateKind(VD->getType()) != VectorIteratorKind)
+ return;
+
+ // Get the MemRegion associated with the iterator and mark it as Undefined.
+ const GRState *state = C.getState();
+ Loc VarLoc = state->getLValue(VD, C.getPredecessor()->getLocationContext());
+ const MemRegion *MR = VarLoc.getAsRegion();
+ if (!MR)
+ return;
+ state = state->set<IteratorState>(MR, RefState::getUndefined());
+
+ // if there is an initializer, handle marking Valid if a proper initializer
+ const Expr* InitEx = VD->getInit();
+ if (InitEx) {
+ // FIXME: This is too syntactic. Since 'InitEx' will be analyzed first
+ // it should resolve to an SVal that we can check for validity
+ // *semantically* instead of walking through the AST.
+ if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) {
+ if (CE->getNumArgs() == 1) {
+ const Expr *E = CE->getArg(0);
+ if (isa<ImplicitCastExpr>(E))
+ InitEx = dyn_cast<ImplicitCastExpr>(E)->getSubExpr();
+ state = handleAssign(state, MR, InitEx,
+ C.getPredecessor()->getLocationContext());
+ }
+ }
+ }
+ C.addTransition(state);
+}
+
+
+namespace { struct CalledReserved {}; }
+namespace clang { namespace ento {
+template<> struct GRStateTrait<CalledReserved>
+ : public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
+ static void *GDMIndex() { static int index = 0; return &index; }
+};
+}}
+
+// on a member call, first check the args for any bad iterators
+// then, check to see if it is a call to a function that will invalidate
+// the iterators
+void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE,
+ CheckerContext &C) const {
+ // Check the arguments.
+ checkArgs(C, MCE);
+ const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee());
+ if (!ME)
+ return;
+ // Make sure we have the right kind of container.
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
+ if (!DRE || getTemplateKind(DRE->getType()) != VectorKind)
+ return;
+ SVal tsv = C.getState()->getSVal(DRE);
+ // Get the MemRegion associated with the container instance.
+ const MemRegion *MR = tsv.getAsRegion();
+ if (!MR)
+ return;
+ // If we are calling a function that invalidates iterators, mark them
+ // appropriately by finding matching instances.
+ const GRState *state = C.getState();
+ llvm::StringRef mName = ME->getMemberDecl()->getName();
+ if (llvm::StringSwitch<bool>(mName)
+ .Cases("insert", "reserve", "push_back", true)
+ .Cases("erase", "pop_back", "clear", "resize", true)
+ .Default(false)) {
+ // If there was a 'reserve' call, assume iterators are good.
+ if (!state->contains<CalledReserved>(MR))
+ state = invalidateIterators(state, MR, ME);
+ }
+ // Keep track of instances that have called 'reserve'
+ // note: do this after we invalidate any iterators by calling
+ // 'reserve' itself.
+ if (mName == "reserve")
+ state = state->add<CalledReserved>(MR);
+
+ if (state != C.getState())
+ C.addTransition(state);
+}
+
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 9e3adc804f67..3d1b5e2d1051 100644
--- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -13,8 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
@@ -57,7 +56,7 @@ static bool IsStdString(QualType T) {
if (!TT)
return false;
- const TypedefDecl *TD = TT->getDecl();
+ const TypedefNameDecl *TD = TT->getDecl();
if (!InNamespace(TD, "std"))
return false;
@@ -289,7 +288,7 @@ void ASTFieldVisitor::ReportError(QualType T) {
//===----------------------------------------------------------------------===//
namespace {
-class LLVMConventionsChecker : public CheckerV2<
+class LLVMConventionsChecker : public Checker<
check::ASTDecl<CXXRecordDecl>,
check::ASTCodeBody > {
public:
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index d70c65ae3073..12ce86613ddc 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -16,7 +16,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -30,7 +30,7 @@ using namespace clang;
using namespace ento;
namespace {
-class MacOSXAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
enum SubChecks {
DispatchOnce = 0,
DispatchOnceF,
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 794740ab7203..91002158c57f 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "ExperimentalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -62,55 +64,52 @@ public:
class RegionState {};
-class MallocChecker : public CheckerVisitor<MallocChecker> {
- BuiltinBug *BT_DoubleFree;
- BuiltinBug *BT_Leak;
- BuiltinBug *BT_UseFree;
- BuiltinBug *BT_UseRelinquished;
- BuiltinBug *BT_BadFree;
- IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
+class MallocChecker : public Checker<eval::Call, check::DeadSymbols, check::EndPath, check::PreStmt<ReturnStmt>, check::Location,
+ check::Bind, eval::Assume> {
+ mutable llvm::OwningPtr<BuiltinBug> BT_DoubleFree;
+ mutable llvm::OwningPtr<BuiltinBug> BT_Leak;
+ mutable llvm::OwningPtr<BuiltinBug> BT_UseFree;
+ mutable llvm::OwningPtr<BuiltinBug> BT_UseRelinquished;
+ mutable llvm::OwningPtr<BuiltinBug> BT_BadFree;
+ mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
public:
- MallocChecker()
- : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_UseRelinquished(0),
- BT_BadFree(0),
- II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
- static void *getTag();
- bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
- void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
- const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption,
- bool *respondsToCallback);
- void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad);
- virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
- SVal location, SVal val);
+ MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
+
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+ void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+ const GRState *evalAssume(const GRState *state, SVal Cond,
+ bool Assumption) const;
+ void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
+ void checkBind(SVal location, SVal val, CheckerContext &C) const;
private:
- void MallocMem(CheckerContext &C, const CallExpr *CE);
- void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att);
- const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
- const Expr *SizeEx, SVal Init,
- const GRState *state) {
+ static void MallocMem(CheckerContext &C, const CallExpr *CE);
+ static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
+ const OwnershipAttr* Att);
+ static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+ const Expr *SizeEx, SVal Init,
+ const GRState *state) {
return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
}
- const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
- SVal SizeEx, SVal Init,
- const GRState *state);
+ static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+ SVal SizeEx, SVal Init,
+ const GRState *state);
- void FreeMem(CheckerContext &C, const CallExpr *CE);
+ void FreeMem(CheckerContext &C, const CallExpr *CE) const;
void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att);
+ const OwnershipAttr* Att) const;
const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state, unsigned Num, bool Hold);
+ const GRState *state, unsigned Num, bool Hold) const;
- void ReallocMem(CheckerContext &C, const CallExpr *CE);
- void CallocMem(CheckerContext &C, const CallExpr *CE);
+ void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
+ static void CallocMem(CheckerContext &C, const CallExpr *CE);
- bool SummarizeValue(llvm::raw_ostream& os, SVal V);
- bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
- void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range);
+ static bool SummarizeValue(llvm::raw_ostream& os, SVal V);
+ static bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
+ void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
};
} // end anonymous namespace
@@ -121,21 +120,12 @@ namespace ento {
template <>
struct GRStateTrait<RegionState>
: public GRStatePartialTrait<RegionStateTy> {
- static void *GDMIndex() { return MallocChecker::getTag(); }
+ static void *GDMIndex() { static int x; return &x; }
};
}
}
-void ento::RegisterMallocChecker(ExprEngine &Eng) {
- Eng.registerCheck(new MallocChecker());
-}
-
-void *MallocChecker::getTag() {
- static int x;
- return &x;
-}
-
-bool MallocChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -256,7 +246,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
}
-void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
+void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false);
if (state)
@@ -264,7 +254,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
}
void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att) {
+ const OwnershipAttr* Att) const {
if (Att->getModule() != "malloc")
return;
@@ -279,7 +269,7 @@ void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
const GRState *state, unsigned Num,
- bool Hold) {
+ bool Hold) const {
const Expr *ArgExpr = CE->getArg(Num);
SVal ArgVal = state->getSVal(ArgExpr);
@@ -357,9 +347,9 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
if (RS->isReleased()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_DoubleFree)
- BT_DoubleFree
- = new BuiltinBug("Double free",
- "Try to free a memory block that has been released");
+ BT_DoubleFree.reset(
+ new BuiltinBug("Double free",
+ "Try to free a memory block that has been released"));
// FIXME: should find where it's freed last time.
BugReport *R = new BugReport(*BT_DoubleFree,
BT_DoubleFree->getDescription(), N);
@@ -463,10 +453,10 @@ bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os,
}
void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
- SourceRange range) {
+ SourceRange range) const {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_BadFree)
- BT_BadFree = new BuiltinBug("Bad free");
+ BT_BadFree.reset(new BuiltinBug("Bad free"));
llvm::SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -500,7 +490,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
}
}
-void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
+void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
const GRState *state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
DefinedOrUnknownSVal arg0Val
@@ -511,8 +501,24 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
DefinedOrUnknownSVal PtrEQ =
svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull());
- // If the ptr is NULL, the call is equivalent to malloc(size).
- if (const GRState *stateEqual = state->assume(PtrEQ, true)) {
+ // Get the size argument. If there is no size arg then give up.
+ const Expr *Arg1 = CE->getArg(1);
+ if (!Arg1)
+ return;
+
+ // Get the value of the size argument.
+ DefinedOrUnknownSVal Arg1Val =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Arg1));
+
+ // Compare the size argument to 0.
+ DefinedOrUnknownSVal SizeZero =
+ svalBuilder.evalEQ(state, Arg1Val,
+ svalBuilder.makeIntValWithPtrWidth(0, false));
+
+ // If the ptr is NULL and the size is not 0, the call is equivalent to
+ // malloc(size).
+ const GRState *stateEqual = state->assume(PtrEQ, true);
+ if (stateEqual && state->assume(SizeZero, false)) {
// Hack: set the NULL symbolic region to released to suppress false warning.
// In the future we should add more states for allocated regions, e.g.,
// CheckedNull, CheckedNonNull.
@@ -527,17 +533,17 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
}
if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) {
- const Expr *Arg1 = CE->getArg(1);
- DefinedOrUnknownSVal Arg1Val =
- cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
- DefinedOrUnknownSVal SizeZero =
- svalBuilder.evalEQ(stateNotEqual, Arg1Val,
- svalBuilder.makeIntValWithPtrWidth(0, false));
-
+ // If the size is 0, free the memory.
if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
- if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false))
- C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+ if (const GRState *stateFree =
+ FreeMemAux(C, CE, stateSizeZero, 0, false)) {
+
+ // Add the state transition to set input pointer argument to be free.
+ C.addTransition(stateFree);
+ // Bind the return value to UndefinedVal because it is now free.
+ C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+ }
if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
0, false)) {
@@ -562,7 +568,8 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
}
-void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
+void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const
{
if (!SymReaper.hasDeadSymbols())
return;
@@ -576,8 +583,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
if (I->second.isAllocated()) {
if (ExplodedNode *N = C.generateNode()) {
if (!BT_Leak)
- BT_Leak = new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak.");
+ BT_Leak.reset(new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak."));
// FIXME: where it is allocated.
BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
C.EmitReport(R);
@@ -591,8 +598,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
C.generateNode(state->set<RegionState>(RS));
}
-void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
+void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) const {
const GRState *state = B.getState();
RegionStateTy M = state->get<RegionState>();
@@ -602,8 +609,8 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
ExplodedNode *N = B.generateNode(state);
if (N) {
if (!BT_Leak)
- BT_Leak = new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak.");
+ BT_Leak.reset(new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak."));
BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
Eng.getBugReporter().EmitReport(R);
}
@@ -611,7 +618,7 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
}
}
-void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
const Expr *retExpr = S->getRetValue();
if (!retExpr)
return;
@@ -634,14 +641,14 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
}
const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
- bool Assumption,
- bool * /* respondsToCallback */) {
+ bool Assumption) const {
// If a symblic region is assumed to NULL, set its state to AllocateFailed.
// FIXME: should also check symbols assumed to non-null.
RegionStateTy RS = state->get<RegionState>();
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+ // If the symbol is assumed to NULL, this will return an APSInt*.
if (state->getSymVal(I.getKey()))
state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed());
}
@@ -650,16 +657,15 @@ const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
}
// Check if the location is a freed symbolic region.
-void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
- bool isLoad) {
+void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const {
SymbolRef Sym = l.getLocSymbolInBase();
if (Sym) {
const RefState *RS = C.getState()->get<RegionState>(Sym);
if (RS && RS->isReleased()) {
if (ExplodedNode *N = C.generateNode()) {
if (!BT_UseFree)
- BT_UseFree = new BuiltinBug("Use dynamically allocated memory after"
- " it is freed.");
+ BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory "
+ "after it is freed."));
BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
N);
@@ -669,10 +675,7 @@ void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
}
}
-void MallocChecker::PreVisitBind(CheckerContext &C,
- const Stmt *StoreE,
- SVal location,
- SVal val) {
+void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const {
// The PreVisitBind implements the same algorithm as already used by the
// Objective C ownership checker: if the pointer escaped from this scope by
// assignment, let it go. However, assigning to fields of a stack-storage
@@ -721,7 +724,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C,
// We no longer own this pointer.
notNullState =
notNullState->set<RegionState>(Sym,
- RefState::getRelinquished(StoreE));
+ RefState::getRelinquished(C.getStmt()));
}
while (false);
}
@@ -729,3 +732,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C,
}
}
}
+
+void ento::registerMallocChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MallocChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index fed6a99c89a2..f11db6458cc0 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -16,7 +16,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.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"
@@ -29,7 +29,7 @@ using namespace ento;
namespace {
class NSAutoreleasePoolChecker
- : public CheckerV2<check::PreObjCMessage> {
+ : public Checker<check::PreObjCMessage> {
mutable Selector releaseS;
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 7a1b9787754d..63a591729944 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -1,4 +1,4 @@
-//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- C++ -*-==//
+//=- NSErrorChecker.cpp - Coding conventions for uses of NSError -*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -15,11 +15,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#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/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
-#include "BasicObjCFoundationChecks.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
@@ -27,142 +28,263 @@
using namespace clang;
using namespace ento;
-namespace {
-class NSErrorChecker : public BugType {
- const Decl &CodeDecl;
- const bool isNSErrorWarning;
- IdentifierInfo * const II;
- ExprEngine &Eng;
+static bool IsNSError(QualType T, IdentifierInfo *II);
+static bool IsCFError(QualType T, IdentifierInfo *II);
- void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
+//===----------------------------------------------------------------------===//
+// NSErrorMethodChecker
+//===----------------------------------------------------------------------===//
- void CheckSignature(const FunctionDecl& MD, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
+namespace {
+class NSErrorMethodChecker
+ : public Checker< check::ASTDecl<ObjCMethodDecl> > {
+ mutable IdentifierInfo *II;
- bool CheckNSErrorArgument(QualType ArgTy);
- bool CheckCFErrorArgument(QualType ArgTy);
+public:
+ NSErrorMethodChecker() : II(0) { }
- void CheckParamDeref(const VarDecl *V, const LocationContext *LC,
- const GRState *state, BugReporter& BR);
+ void checkASTDecl(const ObjCMethodDecl *D,
+ AnalysisManager &mgr, BugReporter &BR) const;
+};
+}
- void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl);
+void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
+ AnalysisManager &mgr,
+ BugReporter &BR) const {
+ if (!D->isThisDeclarationADefinition())
+ return;
+ if (!D->getResultType()->isVoidType())
+ return;
-public:
- NSErrorChecker(const Decl &D, bool isNSError, ExprEngine& eng)
- : BugType(isNSError ? "NSError** null dereference"
- : "CFErrorRef* null dereference",
- "Coding conventions (Apple)"),
- CodeDecl(D),
- isNSErrorWarning(isNSError),
- II(&eng.getContext().Idents.get(isNSErrorWarning ? "NSError":"CFErrorRef")),
- Eng(eng) {}
-
- void FlushReports(BugReporter& BR);
-};
+ if (!II)
+ II = &D->getASTContext().Idents.get("NSError");
-} // end anonymous namespace
+ bool hasNSError = false;
+ for (ObjCMethodDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I) {
+ if (IsNSError((*I)->getType(), II)) {
+ hasNSError = true;
+ break;
+ }
+ }
-void ento::RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng,
- const Decl &D) {
- BR.Register(new NSErrorChecker(D, true, Eng));
- BR.Register(new NSErrorChecker(D, false, Eng));
+ if (hasNSError) {
+ const char *err = "Method accepting NSError** "
+ "should have a non-void return value to indicate whether or not an "
+ "error occurred";
+ BR.EmitBasicReport("Bad return type when passing NSError**",
+ "Coding conventions (Apple)", err, D->getLocation());
+ }
}
-void NSErrorChecker::FlushReports(BugReporter& BR) {
- // Get the analysis engine and the exploded analysis graph.
- ExplodedGraph& G = Eng.getGraph();
+//===----------------------------------------------------------------------===//
+// CFErrorFunctionChecker
+//===----------------------------------------------------------------------===//
- // Get the ASTContext, which is useful for querying type information.
- ASTContext &Ctx = BR.getContext();
+namespace {
+class CFErrorFunctionChecker
+ : public Checker< check::ASTDecl<FunctionDecl> > {
+ mutable IdentifierInfo *II;
- QualType ResultTy;
- llvm::SmallVector<VarDecl*, 5> ErrorParams;
+public:
+ CFErrorFunctionChecker() : II(0) { }
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl))
- CheckSignature(*MD, ResultTy, ErrorParams);
- else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl))
- CheckSignature(*FD, ResultTy, ErrorParams);
- else
- return;
+ void checkASTDecl(const FunctionDecl *D,
+ AnalysisManager &mgr, BugReporter &BR) const;
+};
+}
- if (ErrorParams.empty())
+void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
+ AnalysisManager &mgr,
+ BugReporter &BR) const {
+ if (!D->isThisDeclarationADefinition())
return;
+ if (!D->getResultType()->isVoidType())
+ return;
+
+ if (!II)
+ II = &D->getASTContext().Idents.get("CFErrorRef");
- if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl);
+ bool hasCFError = false;
+ for (FunctionDecl::param_const_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I) {
+ if (IsCFError((*I)->getType(), II)) {
+ hasCFError = true;
+ break;
+ }
+ }
- for (ExplodedGraph::roots_iterator RI=G.roots_begin(), RE=G.roots_end();
- RI!=RE; ++RI) {
- // Scan the parameters for an implicit null dereference.
- for (llvm::SmallVectorImpl<VarDecl*>::iterator I=ErrorParams.begin(),
- E=ErrorParams.end(); I!=E; ++I)
- CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR);
+ if (hasCFError) {
+ const char *err = "Function accepting CFErrorRef* "
+ "should have a non-void return value to indicate whether or not an "
+ "error occurred";
+ BR.EmitBasicReport("Bad return type when passing CFErrorRef*",
+ "Coding conventions (Apple)", err, D->getLocation());
}
}
-void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
+//===----------------------------------------------------------------------===//
+// NSOrCFErrorDerefChecker
+//===----------------------------------------------------------------------===//
- if (isa<ObjCMethodDecl>(CodeDecl))
- os << "Method";
- else
- os << "Function";
+namespace {
- os << " accepting ";
- os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*");
- os << " should have a non-void return value to indicate whether or not an "
- "error occurred";
+class NSErrorDerefBug : public BugType {
+public:
+ NSErrorDerefBug() : BugType("NSError** null dereference",
+ "Coding conventions (Apple)") {}
+};
+
+class CFErrorDerefBug : public BugType {
+public:
+ CFErrorDerefBug() : BugType("CFErrorRef* null dereference",
+ "Coding conventions (Apple)") {}
+};
- BR.EmitBasicReport(isNSErrorWarning
- ? "Bad return type when passing NSError**"
- : "Bad return type when passing CFError*",
- getCategory(), os.str(),
- CodeDecl.getLocation());
}
-void
-NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
+namespace {
+class NSOrCFErrorDerefChecker
+ : public Checker< check::Location,
+ check::Event<ImplicitNullDerefEvent> > {
+ mutable IdentifierInfo *NSErrorII, *CFErrorII;
+public:
+ bool ShouldCheckNSError, ShouldCheckCFError;
+ NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0),
+ ShouldCheckNSError(0), ShouldCheckCFError(0) { }
+
+ void checkLocation(SVal loc, bool isLoad, CheckerContext &C) const;
+ void checkEvent(ImplicitNullDerefEvent event) const;
+};
+}
- ResultTy = M.getResultType();
+namespace { struct NSErrorOut {}; }
+namespace { struct CFErrorOut {}; }
+
+typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag;
+
+namespace clang {
+namespace ento {
+ template <>
+ struct GRStateTrait<NSErrorOut> : public GRStatePartialTrait<ErrorOutFlag> {
+ static void *GDMIndex() { static int index = 0; return &index; }
+ };
+ template <>
+ struct GRStateTrait<CFErrorOut> : public GRStatePartialTrait<ErrorOutFlag> {
+ static void *GDMIndex() { static int index = 0; return &index; }
+ };
+}
+}
- for (ObjCMethodDecl::param_iterator I=M.param_begin(),
- E=M.param_end(); I!=E; ++I) {
+template <typename T>
+static bool hasFlag(SVal val, const GRState *state) {
+ if (SymbolRef sym = val.getAsSymbol())
+ if (const unsigned *attachedFlags = state->get<T>(sym))
+ return *attachedFlags;
+ return false;
+}
- QualType T = (*I)->getType();
+template <typename T>
+static void setFlag(const GRState *state, SVal val, CheckerContext &C) {
+ // We tag the symbol that the SVal wraps.
+ if (SymbolRef sym = val.getAsSymbol())
+ C.addTransition(state->set<T>(sym, true));
+}
- if (isNSErrorWarning) {
- if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
- }
- else if (CheckCFErrorArgument(T))
- ErrorParams.push_back(*I);
+static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
+ const StackFrameContext *
+ SFC = C.getPredecessor()->getLocationContext()->getCurrentStackFrame();
+ if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(&val)) {
+ const MemRegion* R = X->getRegion();
+ if (const VarRegion *VR = R->getAs<VarRegion>())
+ if (const StackArgumentsSpaceRegion *
+ stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
+ if (stackReg->getStackFrame() == SFC)
+ return VR->getValueType();
}
+
+ return QualType();
}
-void
-NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
+void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
+ CheckerContext &C) const {
+ if (!isLoad)
+ return;
+ if (loc.isUndef() || !isa<Loc>(loc))
+ return;
- ResultTy = F.getResultType();
+ ASTContext &Ctx = C.getASTContext();
+ const GRState *state = C.getState();
- for (FunctionDecl::param_const_iterator I = F.param_begin(),
- E = F.param_end(); I != E; ++I) {
+ // If we are loading from NSError**/CFErrorRef* parameter, mark the resulting
+ // SVal so that we can later check it when handling the
+ // ImplicitNullDerefEvent event.
+ // FIXME: Cumbersome! Maybe add hook at construction of SVals at start of
+ // function ?
- QualType T = (*I)->getType();
+ QualType parmT = parameterTypeFromSVal(loc, C);
+ if (parmT.isNull())
+ return;
- if (isNSErrorWarning) {
- if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
- }
- else if (CheckCFErrorArgument(T))
- ErrorParams.push_back(*I);
+ if (!NSErrorII)
+ NSErrorII = &Ctx.Idents.get("NSError");
+ if (!CFErrorII)
+ CFErrorII = &Ctx.Idents.get("CFErrorRef");
+
+ if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) {
+ setFlag<NSErrorOut>(state, state->getSVal(cast<Loc>(loc)), C);
+ return;
+ }
+
+ if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) {
+ setFlag<CFErrorOut>(state, state->getSVal(cast<Loc>(loc)), C);
+ return;
}
}
+void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
+ if (event.IsLoad)
+ return;
+
+ SVal loc = event.Location;
+ const GRState *state = event.SinkNode->getState();
+ BugReporter &BR = *event.BR;
+
+ bool isNSError = hasFlag<NSErrorOut>(loc, state);
+ bool isCFError = false;
+ if (!isNSError)
+ isCFError = hasFlag<CFErrorOut>(loc, state);
+
+ if (!(isNSError || isCFError))
+ return;
-bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) {
+ // Storing to possible null NSError/CFErrorRef out parameter.
- const PointerType* PPT = ArgTy->getAs<PointerType>();
+ // Emit an error.
+ std::string err;
+ llvm::raw_string_ostream os(err);
+ os << "Potential null dereference. According to coding standards ";
+
+ if (isNSError)
+ os << "in 'Creating and Returning NSError Objects' the parameter '";
+ else
+ os << "documented in CoreFoundation/CFError.h the parameter '";
+
+ os << "' may be null.";
+
+ BugType *bug = 0;
+ if (isNSError)
+ bug = new NSErrorDerefBug();
+ else
+ bug = new CFErrorDerefBug();
+ EnhancedBugReport *report = new EnhancedBugReport(*bug, os.str(),
+ event.SinkNode);
+ BR.EmitReport(report);
+}
+
+static bool IsNSError(QualType T, IdentifierInfo *II) {
+
+ const PointerType* PPT = T->getAs<PointerType>();
if (!PPT)
return false;
@@ -181,9 +303,8 @@ bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) {
return false;
}
-bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) {
-
- const PointerType* PPT = ArgTy->getAs<PointerType>();
+static bool IsCFError(QualType T, IdentifierInfo *II) {
+ const PointerType* PPT = T->getAs<PointerType>();
if (!PPT) return false;
const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>();
@@ -192,47 +313,16 @@ bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) {
return TT->getDecl()->getIdentifier() == II;
}
-void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
- const LocationContext *LC,
- const GRState *rootState,
- BugReporter& BR) {
-
- SVal ParamL = rootState->getLValue(Param, LC);
- const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>();
- assert (ParamR && "Parameters always have VarRegions.");
- SVal ParamSVal = rootState->getSVal(ParamR);
-
- // FIXME: For now assume that ParamSVal is symbolic. We need to generalize
- // this later.
- SymbolRef ParamSym = ParamSVal.getAsLocSymbol();
- if (!ParamSym)
- return;
+void ento::registerNSErrorChecker(CheckerManager &mgr) {
+ mgr.registerChecker<NSErrorMethodChecker>();
+ NSOrCFErrorDerefChecker *
+ checker = mgr.registerChecker<NSOrCFErrorDerefChecker>();
+ checker->ShouldCheckNSError = true;
+}
- // Iterate over the implicit-null dereferences.
- ExplodedNode *const* I, *const* E;
- llvm::tie(I, E) = GetImplicitNullDereferences(Eng);
- for ( ; I != E; ++I) {
- const GRState *state = (*I)->getState();
- SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt());
- if (location.getAsSymbol() != ParamSym)
- continue;
-
- // Emit an error.
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- os << "Potential null dereference. According to coding standards ";
-
- if (isNSErrorWarning)
- os << "in 'Creating and Returning NSError Objects' the parameter '";
- else
- os << "documented in CoreFoundation/CFError.h the parameter '";
-
- os << Param << "' may be null.";
-
- BugReport *report = new BugReport(*this, os.str(), *I);
- // FIXME: Notable symbols are now part of the report. We should
- // add support for notable symbols in BugReport.
- // BR.addNotableSymbol(SV->getSymbol());
- BR.EmitReport(report);
- }
+void ento::registerCFErrorChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CFErrorFunctionChecker>();
+ NSOrCFErrorDerefChecker *
+ checker = mgr.registerChecker<NSOrCFErrorDerefChecker>();
+ checker->ShouldCheckCFError = true;
}
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 40040eada7b0..2d0af9c978dc 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -12,8 +12,10 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -21,20 +23,15 @@ using namespace ento;
namespace {
-class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> {
+class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr> > {
public:
- static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
};
}
-void ento::RegisterNoReturnFunctionChecker(ExprEngine &Eng) {
- Eng.registerCheck(new NoReturnFunctionChecker());
-}
-
-void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
+void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
@@ -78,3 +75,7 @@ void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C,
if (BuildSinks)
C.generateSink(CE);
}
+
+void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
+ mgr.registerChecker<NoReturnFunctionChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
index e1126b617b7c..7262bc36404d 100644
--- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
@@ -11,8 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
+#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;
@@ -20,22 +22,17 @@ using namespace ento;
namespace {
-class OSAtomicChecker : public Checker {
+class OSAtomicChecker : public Checker<eval::Call> {
public:
- static void *getTag() { static int tag = 0; return &tag; }
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const;
private:
- bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
+ static bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
};
}
-void ento::RegisterOSAtomicChecker(ExprEngine &Eng) {
- Eng.registerCheck(new OSAtomicChecker());
-}
-
-bool OSAtomicChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE) {
+bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -130,7 +127,12 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
ExplodedNode *N = *I;
const GRState *stateLoad = N->getState();
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
+
+ // 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, true);
+
SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
// FIXME: Issue an error.
@@ -201,3 +203,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
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 77467190db73..a1180492a937 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class ObjCAtSyncChecker
- : public CheckerV2< check::PreStmt<ObjCAtSynchronizedStmt> > {
+ : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
mutable llvm::OwningPtr<BuiltinBug> BT_null;
mutable llvm::OwningPtr<BuiltinBug> BT_undef;
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 5f32bb8f53a2..4c05867631f3 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -16,7 +16,7 @@
// result of an initialization call (e.g. [super init], or [self initWith..])
// before using 'self' or any instance variable.
//
-// To perform the required checking, values are tagged wih flags that indicate
+// To perform the required checking, values are tagged with flags that indicate
// 1) if the object is the one pointed to by 'self', and 2) if the object
// is the result of an initializer (e.g. [super init]).
//
@@ -47,12 +47,11 @@
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/AST/ParentMap.h"
using namespace clang;
@@ -64,7 +63,7 @@ static bool isInitMessage(const ObjCMessage &msg);
static bool isSelfVar(SVal location, CheckerContext &C);
namespace {
-class ObjCSelfInitChecker : public CheckerV2<
+class ObjCSelfInitChecker : public Checker<
check::PostObjCMessage,
check::PostStmt<ObjCIvarRefExpr>,
check::PreStmt<ReturnStmt>,
@@ -347,15 +346,11 @@ static bool isSelfVar(SVal location, CheckerContext &C) {
}
static bool isInitializationMethod(const ObjCMethodDecl *MD) {
- // Init methods with prefix like '-(id)_init' are private and the requirements
- // are less strict so we don't check those.
- return MD->isInstanceMethod() &&
- cocoa::deriveNamingConvention(MD->getSelector(),
- /*ignorePrefix=*/false) == cocoa::InitRule;
+ return MD->getMethodFamily() == OMF_init;
}
static bool isInitMessage(const ObjCMessage &msg) {
- return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
+ return msg.getMethodFamily() == OMF_init;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index 6e92498769f7..d78e5ceb533d 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/ExprObjC.h"
@@ -169,7 +169,7 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
//===----------------------------------------------------------------------===//
namespace {
-class ObjCUnusedIvarsChecker : public CheckerV2<
+class ObjCUnusedIvarsChecker : public Checker<
check::ASTDecl<ObjCImplementationDecl> > {
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 034a2aaef74e..7c21acc5bee7 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -23,7 +23,7 @@ using namespace ento;
namespace {
class PointerArithChecker
- : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ : public Checker< check::PreStmt<BinaryOperator> > {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index bf85b959c9ee..16ede2095eae 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class PointerSubChecker
- : public CheckerV2< check::PreStmt<BinaryOperator> > {
+ : public Checker< check::PreStmt<BinaryOperator> > {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 6c6901f41263..74199bb1f6db 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.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"
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class PthreadLockChecker
- : public CheckerV2< check::PostStmt<CallExpr> > {
+ : public Checker< check::PostStmt<CallExpr> > {
public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 298515609cd0..1729b25a2979 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class ReturnPointerRangeChecker :
- public CheckerV2< check::PreStmt<ReturnStmt> > {
+ public Checker< check::PreStmt<ReturnStmt> > {
mutable llvm::OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 555eaf41282b..7c215b7cf318 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -13,35 +13,26 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
namespace {
class ReturnUndefChecker :
- public CheckerVisitor<ReturnUndefChecker> {
- BuiltinBug *BT;
+ public Checker< check::PreStmt<ReturnStmt> > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
public:
- ReturnUndefChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+ void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
}
-void ento::RegisterReturnUndefChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ReturnUndefChecker());
-}
-
-void *ReturnUndefChecker::getTag() {
- static int x = 0; return &x;
-}
-
-void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
+void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
+ CheckerContext &C) const {
const Expr *RetE = RS->getRetValue();
if (!RetE)
@@ -56,8 +47,8 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
return;
if (!BT)
- BT = new BuiltinBug("Garbage return value",
- "Undefined or garbage value returned to caller");
+ BT.reset(new BuiltinBug("Garbage return value",
+ "Undefined or garbage value returned to caller"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT, BT->getDescription(), N);
@@ -67,3 +58,7 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
C.EmitReport(report);
}
+
+void ento::registerReturnUndefChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ReturnUndefChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 6a9a37d955bf..07de8706df24 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -24,7 +24,7 @@ using namespace clang;
using namespace ento;
namespace {
-class StackAddrEscapeChecker : public CheckerV2< check::PreStmt<ReturnStmt>,
+class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
check::EndPath > {
mutable llvm::OwningPtr<BuiltinBug> BT_stackleak;
mutable llvm::OwningPtr<BuiltinBug> BT_returnstack;
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index d0626b8cef83..711c672c1448 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -56,7 +56,7 @@ struct StreamState {
}
};
-class StreamChecker : public CheckerV2<eval::Call,
+class StreamChecker : public Checker<eval::Call,
check::DeadSymbols,
check::EndPath,
check::PreStmt<ReturnStmt> > {
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 14ae9edc7b7e..1fb181591b42 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -12,17 +12,19 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
using namespace clang;
using namespace ento;
namespace {
-class UndefBranchChecker : public Checker {
- BuiltinBug *BT;
+class UndefBranchChecker : public Checker<check::BranchCondition> {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
struct FindUndefExpr {
GRStateManager& VM;
@@ -48,26 +50,15 @@ class UndefBranchChecker : public Checker {
};
public:
- UndefBranchChecker() : BT(0) {}
- static void *getTag();
- void VisitBranchCondition(BranchNodeBuilder &Builder, ExprEngine &Eng,
- const Stmt *Condition, void *tag);
+ void checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder,
+ ExprEngine &Eng) const;
};
}
-void ento::RegisterUndefBranchChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefBranchChecker());
-}
-
-void *UndefBranchChecker::getTag() {
- static int x;
- return &x;
-}
-
-void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder,
- ExprEngine &Eng,
- const Stmt *Condition, void *tag){
+void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
+ BranchNodeBuilder &Builder,
+ ExprEngine &Eng) const {
const GRState *state = Builder.getState();
SVal X = state->getSVal(Condition);
if (X.isUndef()) {
@@ -75,7 +66,8 @@ void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder,
if (N) {
N->markAsSink();
if (!BT)
- BT = new BuiltinBug("Branch condition evaluates to a garbage value");
+ BT.reset(
+ new BuiltinBug("Branch condition evaluates to a garbage value"));
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
@@ -118,3 +110,7 @@ void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder,
Builder.markInfeasible(false);
}
}
+
+void ento::registerUndefBranchChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UndefBranchChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 6d3c966e6db1..69958d11f717 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -11,8 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#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/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "llvm/Support/raw_ostream.h"
@@ -22,20 +24,14 @@ using namespace ento;
namespace {
class UndefCapturedBlockVarChecker
- : public CheckerVisitor<UndefCapturedBlockVarChecker> {
- BugType *BT;
+ : public Checker< check::PostStmt<BlockExpr> > {
+ mutable llvm::OwningPtr<BugType> BT;
public:
- UndefCapturedBlockVarChecker() : BT(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+ void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
};
} // end anonymous namespace
-void ento::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefCapturedBlockVarChecker());
-}
-
static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
const VarDecl *VD){
if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S))
@@ -54,8 +50,8 @@ static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
}
void
-UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
- const BlockExpr *BE) {
+UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
+ CheckerContext &C) const {
if (!BE->getBlockDecl()->hasCaptures())
return;
@@ -82,7 +78,7 @@ UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
if (state->getSVal(VR).isUndef())
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
- BT = new BuiltinBug("uninitialized variable captured by block");
+ BT.reset(new BuiltinBug("uninitialized variable captured by block"));
// Generate a bug report.
llvm::SmallString<128> buf;
@@ -100,3 +96,7 @@ UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
}
}
}
+
+void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UndefCapturedBlockVarChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 64a3567bc342..7fa3804639d6 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -12,9 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -22,23 +24,17 @@ using namespace ento;
namespace {
class UndefResultChecker
- : public CheckerVisitor<UndefResultChecker> {
+ : public Checker< check::PostStmt<BinaryOperator> > {
- BugType *BT;
+ mutable llvm::OwningPtr<BugType> BT;
public:
- UndefResultChecker() : BT(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+ void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
};
} // end anonymous namespace
-void ento::RegisterUndefResultChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefResultChecker());
-}
-
-void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
+void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
const GRState *state = C.getState();
if (state->getSVal(B).isUndef()) {
// Generate an error node.
@@ -47,7 +43,7 @@ void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C,
return;
if (!BT)
- BT = new BuiltinBug("Result of operation is garbage or undefined");
+ BT.reset(new BuiltinBug("Result of operation is garbage or undefined"));
llvm::SmallString<256> sbuf;
llvm::raw_svector_ostream OS(sbuf);
@@ -85,3 +81,7 @@ void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C,
C.EmitReport(report);
}
}
+
+void ento::registerUndefResultChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UndefResultChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index ff0344802d90..e51ab20d2f30 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -12,39 +12,32 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class UndefinedArraySubscriptChecker
- : public CheckerVisitor<UndefinedArraySubscriptChecker> {
- BugType *BT;
+ : public Checker< check::PreStmt<ArraySubscriptExpr> > {
+ mutable llvm::OwningPtr<BugType> BT;
+
public:
- UndefinedArraySubscriptChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PreVisitArraySubscriptExpr(CheckerContext &C,
- const ArraySubscriptExpr *A);
+ void checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const;
};
} // end anonymous namespace
-void ento::RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefinedArraySubscriptChecker());
-}
-
void
-UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C,
- const ArraySubscriptExpr *A) {
+UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
+ CheckerContext &C) const {
if (C.getState()->getSVal(A->getIdx()).isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
- BT = new BuiltinBug("Array subscript is undefined");
+ BT.reset(new BuiltinBug("Array subscript is undefined"));
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
@@ -55,3 +48,7 @@ UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C,
}
}
}
+
+void ento::registerUndefinedArraySubscriptChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UndefinedArraySubscriptChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index e53cbba41cbc..28806e3db917 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -7,43 +7,32 @@
//
//===----------------------------------------------------------------------===//
//
-// This defines UndefinedAssginmentChecker, a builtin check in ExprEngine that
+// This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
// checks for assigning undefined values.
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
using namespace clang;
using namespace ento;
namespace {
class UndefinedAssignmentChecker
- : public CheckerVisitor<UndefinedAssignmentChecker> {
- BugType *BT;
+ : public Checker<check::Bind> {
+ mutable llvm::OwningPtr<BugType> BT;
+
public:
- UndefinedAssignmentChecker() : BT(0) {}
- static void *getTag();
- virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
- SVal location, SVal val);
+ void checkBind(SVal location, SVal val, CheckerContext &C) const;
};
}
-void ento::RegisterUndefinedAssignmentChecker(ExprEngine &Eng){
- Eng.registerCheck(new UndefinedAssignmentChecker());
-}
-
-void *UndefinedAssignmentChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
- const Stmt *StoreE,
- SVal location,
- SVal val) {
+void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
+ CheckerContext &C) const {
if (!val.isUndef())
return;
@@ -55,11 +44,12 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
const char *str = "Assigned value is garbage or undefined";
if (!BT)
- BT = new BuiltinBug(str);
+ BT.reset(new BuiltinBug(str));
// Generate a report for this bug.
const Expr *ex = 0;
+ const Stmt *StoreE = C.getStmt();
while (StoreE) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
if (B->isCompoundAssignmentOp()) {
@@ -92,3 +82,6 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
C.EmitReport(R);
}
+void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UndefinedAssignmentChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index be4fbf60eb2e..48d7c367a96d 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -27,7 +27,7 @@ using namespace ento;
using llvm::Optional;
namespace {
-class UnixAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > {
+class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
enum SubChecks {
OpenFn = 0,
PthreadOnceFn = 1,
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 1bc487a49c1e..b540bce98170 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/CheckerV2.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
@@ -34,7 +34,7 @@ using namespace clang;
using namespace ento;
namespace {
-class UnreachableCodeChecker : public CheckerV2<check::EndAnalysis> {
+class UnreachableCodeChecker : public Checker<check::EndAnalysis> {
public:
void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
ExprEngine &Eng) const;
@@ -112,8 +112,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
// such as llvm_unreachable.
if (!CB->empty()) {
CFGElement First = CB->front();
- if (CFGStmt S = First.getAs<CFGStmt>()) {
- if (const CallExpr *CE = dyn_cast<CallExpr>(S.getStmt())) {
+ if (const CFGStmt *S = First.getAs<CFGStmt>()) {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
continue;
}
@@ -164,8 +164,8 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
// Find the Stmt* in a CFGBlock for reporting a warning
const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
- if (CFGStmt S = I->getAs<CFGStmt>())
- return S;
+ if (const CFGStmt *S = I->getAs<CFGStmt>())
+ return S->getStmt();
}
if (const Stmt *S = CB->getTerminator())
return S;
@@ -204,7 +204,7 @@ bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
// Run each of the checks on the conditions
if (containsMacro(cond) || containsEnum(cond)
|| containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
- || containsStmt<SizeOfAlignOfExpr>(cond))
+ || containsStmt<UnaryExprOrTypeTraitExpr>(cond))
return true;
return false;
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index ba46e177f822..875dce2e994a 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -14,32 +14,27 @@
//
//===----------------------------------------------------------------------===//
-#include "InternalChecks.h"
-#include "clang/AST/CharUnits.h"
+#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/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/AST/CharUnits.h"
using namespace clang;
using namespace ento;
namespace {
-class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
- BugType *BT_zero;
- BugType *BT_undef;
+class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > {
+ mutable llvm::OwningPtr<BugType> BT_zero;
+ mutable llvm::OwningPtr<BugType> BT_undef;
public:
- VLASizeChecker() : BT_zero(0), BT_undef(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
+ void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
};
} // end anonymous namespace
-void ento::RegisterVLASizeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new VLASizeChecker());
-}
-
-void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
if (!DS->isSingleDecl())
return;
@@ -64,8 +59,8 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
return;
if (!BT_undef)
- BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
- "garbage value as its size");
+ BT_undef.reset(new BuiltinBug("Declared variable-length array (VLA) "
+ "uses a garbage value as its size"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
@@ -89,8 +84,8 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
if (stateZero && !stateNotZero) {
ExplodedNode* N = C.generateSink(stateZero);
if (!BT_zero)
- BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
- "size");
+ BT_zero.reset(new BuiltinBug("Declared variable-length array (VLA) has "
+ "zero size"));
EnhancedBugReport *report =
new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
@@ -136,3 +131,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
// Remember our assumptions!
C.addTransition(state);
}
+
+void ento::registerVLASizeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<VLASizeChecker>();
+}
diff --git a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
index e80cf9b4a331..901190d901dd 100644
--- a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
+++ b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
@@ -60,7 +60,7 @@ void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
}
void AggExprVisitor::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
- Eng.VisitCXXMemberCallExpr(E, Pred, DstSet);
+ Eng.Visit(E, Pred, DstSet);
}
void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest,
diff --git a/lib/StaticAnalyzer/Core/BasicStore.cpp b/lib/StaticAnalyzer/Core/BasicStore.cpp
index 98365e7f4e62..4faa84ca2660 100644
--- a/lib/StaticAnalyzer/Core/BasicStore.cpp
+++ b/lib/StaticAnalyzer/Core/BasicStore.cpp
@@ -429,12 +429,15 @@ StoreRef BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
}
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(InitLoc->getDecl())) {
- // For C++ methods add symbolic region for 'this' in initial stack frame.
- QualType ThisT = MD->getThisType(StateMgr.getContext());
- MemRegionManager &RegMgr = svalBuilder.getRegionManager();
- const CXXThisRegion *ThisR = RegMgr.getCXXThisRegion(ThisT, InitLoc);
- SVal ThisV = svalBuilder.getRegionValueSymbolVal(ThisR);
- St = Bind(St.getStore(), svalBuilder.makeLoc(ThisR), ThisV);
+ // For C++ non-static member variables, add a symbolic region for 'this' in
+ // the initial stack frame.
+ if (MD->isInstance()) {
+ QualType ThisT = MD->getThisType(StateMgr.getContext());
+ MemRegionManager &RegMgr = svalBuilder.getRegionManager();
+ const CXXThisRegion *ThisR = RegMgr.getCXXThisRegion(ThisT, InitLoc);
+ SVal ThisV = svalBuilder.getRegionValueSymbolVal(ThisR);
+ St = Bind(St.getStore(), svalBuilder.makeLoc(ThisR), ThisV);
+ }
}
return St;
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 6315d83d894d..ae8a04ce439f 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
using namespace clang;
using namespace ento;
@@ -25,8 +26,9 @@ void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
}
void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID,
- const void *store,const TypedRegion *region) {
- ID.AddPointer(store);
+ const StoreRef &store,
+ const TypedRegion *region) {
+ ID.AddPointer(store.getStore());
ID.AddPointer(region);
}
@@ -124,7 +126,7 @@ BasicValueFactory::getCompoundValData(QualType T,
}
const LazyCompoundValData*
-BasicValueFactory::getLazyCompoundValData(const void *store,
+BasicValueFactory::getLazyCompoundValData(const StoreRef &store,
const TypedRegion *region) {
llvm::FoldingSetNodeID ID;
LazyCompoundValData::Profile(ID, store, region);
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 672982a3c025..8b5d383ed07f 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -432,7 +432,7 @@ public:
else if (const DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
// FIXME: Eventually CFGs won't have DeclStmts. Right now we
// assume that each DeclStmt has a single Decl. This invariant
- // holds by contruction in the CFG.
+ // holds by construction in the CFG.
VD = dyn_cast<VarDecl>(*DS->decl_begin());
}
@@ -859,7 +859,8 @@ class EdgeBuilder {
default:
break;
case Stmt::ParenExprClass:
- S = cast<ParenExpr>(S)->IgnoreParens();
+ case Stmt::GenericSelectionExprClass:
+ S = cast<Expr>(S)->IgnoreParens();
firstCharOnly = true;
continue;
case Stmt::BinaryConditionalOperatorClass:
@@ -1170,13 +1171,14 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
}
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
- if (CFGStmt S = BE->getFirstElement().getAs<CFGStmt>()) {
- if (IsControlFlowExpr(S)) {
+ if (const CFGStmt *S = BE->getFirstElement().getAs<CFGStmt>()) {
+ const Stmt *stmt = S->getStmt();
+ if (IsControlFlowExpr(stmt)) {
// Add the proper context for '&&', '||', and '?'.
- EB.addContext(S);
+ EB.addContext(stmt);
}
else
- EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+ EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
}
break;
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index b3721d7659fe..d9b1ce825cea 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -12,7 +12,11 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
@@ -20,7 +24,6 @@
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
@@ -1198,7 +1201,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
// Effects on the parameters.
unsigned parm_idx = 0;
for (FunctionDecl::param_const_iterator pi = FD->param_begin(),
- pe = FD->param_end(); pi != pe; ++pi) {
+ pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi;
if (pd->getAttr<NSConsumedAttr>()) {
if (!GCEnabled)
@@ -2428,7 +2431,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
SymbolRef sym, ExprEngine& Eng)
: CFRefReport(D, tf, n, sym) {
- // Most bug reports are cached at the location where they occured.
+ // Most bug reports are cached at the location where they occurred.
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path. To do this, we need to find
// the allocation site of a piece of tracked memory, which we do via a
@@ -2526,6 +2529,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
RegionsToInvalidate.push_back(region);
}
+ // Invalidate all instance variables for the callee of a C++ method call.
+ // FIXME: We should be able to do better with inter-procedural analysis.
+ // FIXME: we can probably do better for const versus non-const methods.
+ if (callOrMsg.isCXXCall()) {
+ if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion())
+ RegionsToInvalidate.push_back(callee);
+ }
+
for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
SymbolRef Sym = V.getAsLocSymbol();
@@ -2678,11 +2689,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
- QualType T = callOrMsg.getResultType(Eng.getContext());
- if (Loc::isLocType(T) || (T->isIntegerType() && T->isScalarType())) {
+ // Use the result type from callOrMsg as it automatically adjusts
+ // for methods/functions that return references.
+ QualType resultTy = callOrMsg.getResultType(Eng.getContext());
+ if (Loc::isLocType(resultTy) ||
+ (resultTy->isIntegerType() && resultTy->isScalarType())) {
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
- SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, T, Count);
+ SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, resultTy, Count);
state = state->BindExpr(Ex, X, false);
}
@@ -2709,9 +2723,12 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count);
- QualType RetT = GetReturnType(Ex, svalBuilder.getContext());
+
+ // Use the result type from callOrMsg as it automatically adjusts
+ // for methods/functions that return references.
+ QualType resultTy = callOrMsg.getResultType(Eng.getContext());
state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
- RetT));
+ resultTy));
state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false);
// FIXME: Add a flag to the checker where allocations are assumed to
@@ -2764,11 +2781,17 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst,
if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
Summ = Summaries.getPersistentStopSummary();
}
- else {
- const FunctionDecl* FD = L.getAsFunctionDecl();
- Summ = !FD ? Summaries.getDefaultSummary() :
- Summaries.getSummary(FD);
+ else if (const FunctionDecl* FD = L.getAsFunctionDecl()) {
+ Summ = Summaries.getSummary(FD);
+ }
+ else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
+ if (const CXXMethodDecl *MD = me->getMethodDecl())
+ Summ = Summaries.getSummary(MD);
+ else
+ Summ = Summaries.getDefaultSummary();
}
+ else
+ Summ = Summaries.getDefaultSummary();
assert(Summ);
evalSummary(Dst, Eng, Builder, CE,
@@ -3395,19 +3418,15 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
namespace {
class RetainReleaseChecker
- : public CheckerVisitor<RetainReleaseChecker> {
- CFRefCount *TF;
+ : public Checker< check::PostStmt<BlockExpr> > {
public:
- RetainReleaseChecker(CFRefCount *tf) : TF(tf) {}
- static void* getTag() { static int x = 0; return &x; }
-
- void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+ void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
};
} // end anonymous namespace
-void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C,
- const BlockExpr *BE) {
+void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE,
+ CheckerContext &C) const {
// Scan the BlockDecRefExprs for any object the retain/release checker
// may be tracking.
@@ -3510,7 +3529,9 @@ void CFRefCount::RegisterChecks(ExprEngine& Eng) {
// Register the RetainReleaseChecker with the ExprEngine object.
// Functionality in CFRefCount will be migrated to RetainReleaseChecker
// over time.
- Eng.registerCheck(new RetainReleaseChecker(this));
+ // FIXME: HACK! Remove TransferFuncs and turn all of CFRefCount into fully
+ // using the checker mechanism.
+ Eng.getCheckerManager().registerChecker<RetainReleaseChecker>();
}
TransferFuncs* ento::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index 14c636cf761a..089a5cc39037 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -8,18 +8,19 @@ add_clang_library(clangStaticAnalyzerCore
BasicConstraintManager.cpp
BasicStore.cpp
BasicValueFactory.cpp
+ BlockCounter.cpp
BugReporter.cpp
BugReporterVisitors.cpp
CFRefCount.cpp
- Checker.cpp
+ CXXExprEngine.cpp
+ CheckerContext.cpp
CheckerHelpers.cpp
CheckerManager.cpp
+ CoreEngine.cpp
Environment.cpp
ExplodedGraph.cpp
+ ExprEngine.cpp
FlatStore.cpp
- BlockCounter.cpp
- CXXExprEngine.cpp
- CoreEngine.cpp
GRState.cpp
HTMLDiagnostics.cpp
MemRegion.cpp
diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
index 56dfe8cb04a9..54cbca08b981 100644
--- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/DeclCXX.h"
@@ -61,6 +62,34 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
}
}
+void ExprEngine::evalCallee(const CallExpr *callExpr,
+ const ExplodedNodeSet &src,
+ ExplodedNodeSet &dest) {
+
+ const Expr *callee = 0;
+
+ switch (callExpr->getStmtClass()) {
+ case Stmt::CXXMemberCallExprClass: {
+ // Evaluate the implicit object argument that is the recipient of the
+ // call.
+ callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument();
+
+ // FIXME: handle member pointers.
+ if (!callee)
+ return;
+
+ break;
+ }
+ default: {
+ callee = callExpr->getCallee()->IgnoreParens();
+ break;
+ }
+ }
+
+ for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i)
+ Visit(callee, *i, dest);
+}
+
const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
const StackFrameContext *SFC) {
const Type *T = D->getTypeForDecl();
@@ -95,50 +124,121 @@ void ExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred,
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
- const MemRegion *Dest,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- if (!Dest)
- Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
- Pred->getLocationContext());
-
- if (E->isElidable()) {
- VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
- return;
- }
+ const MemRegion *Dest,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &destNodes) {
const CXXConstructorDecl *CD = E->getConstructor();
assert(CD);
-
+
+#if 0
if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
// FIXME: invalidate the object.
return;
-
+#endif
// Evaluate other arguments.
ExplodedNodeSet argsEvaluated;
const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
- // The callee stack frame context used to create the 'this' parameter region.
- const StackFrameContext *SFC = AMgr.getStackFrame(CD,
- Pred->getLocationContext(),
- E, Builder->getBlock(),
- Builder->getIndex());
- const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(),
- SFC);
-
- CallEnter Loc(E, SFC, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
- NE = argsEvaluated.end(); NI != NE; ++NI) {
- const GRState *state = GetState(*NI);
- // Setup 'this' region, so that the ctor is evaluated on the object pointed
- // by 'Dest'.
- state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- if (N)
- Dst.Add(N);
+#if 0
+ // Is the constructor elidable?
+ if (E->isElidable()) {
+ VisitAggExpr(E->getArg(0), destNodes, Pred, Dst);
+ // FIXME: this is here to force propagation if VisitAggExpr doesn't
+ if (destNodes.empty())
+ destNodes.Add(Pred);
+ return;
+ }
+#endif
+
+ // Perform the previsit of the constructor.
+ ExplodedNodeSet destPreVisit;
+ getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E,
+ *this);
+
+ // Evaluate the constructor. Currently we don't now allow checker-specific
+ // implementations of specific constructors (as we do with ordinary
+ // function calls. We can re-evaluate this in the future.
+
+#if 0
+ // Inlining currently isn't fully implemented.
+
+ if (AMgr.shouldInlineCall()) {
+ if (!Dest)
+ Dest =
+ svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
+ Pred->getLocationContext());
+
+ // The callee stack frame context used to create the 'this'
+ // parameter region.
+ const StackFrameContext *SFC =
+ AMgr.getStackFrame(CD, Pred->getLocationContext(),
+ E, Builder->getBlock(), Builder->getIndex());
+
+ // Create the 'this' region.
+ const CXXThisRegion *ThisR =
+ getCXXThisRegion(E->getConstructor()->getParent(), SFC);
+
+ CallEnter Loc(E, SFC, Pred->getLocationContext());
+
+
+ for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
+ NE = argsEvaluated.end(); NI != NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ // Setup 'this' region, so that the ctor is evaluated on the object pointed
+ // by 'Dest'.
+ state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
+ if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI))
+ destNodes.Add(N);
+ }
+ }
+#endif
+
+ // Default semantics: invalidate all regions passed as arguments.
+ llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate;
+
+ // FIXME: We can have collisions on the conjured symbol if the
+ // expression *I also creates conjured symbols. We probably want
+ // to identify conjured symbols by an expression pair: the enclosing
+ // expression (the context) and the expression itself. This should
+ // disambiguate conjured symbols.
+ unsigned blockCount = Builder->getCurrentBlockCount();
+
+ // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
+ // global variables.
+ ExplodedNodeSet destCall;
+
+ for (ExplodedNodeSet::iterator
+ i = destPreVisit.begin(), e = destPreVisit.end();
+ i != e; ++i)
+ {
+ ExplodedNode *Pred = *i;
+ const GRState *state = GetState(Pred);
+
+ // Accumulate list of regions that are invalidated.
+ for (CXXConstructExpr::const_arg_iterator
+ ai = E->arg_begin(), ae = E->arg_end();
+ ai != ae; ++ai)
+ {
+ SVal val = state->getSVal(*ai);
+ if (const MemRegion *region = val.getAsRegion())
+ regionsToInvalidate.push_back(region);
+ }
+
+ // Invalidate the regions.
+ state = state->invalidateRegions(regionsToInvalidate.data(),
+ regionsToInvalidate.data() +
+ regionsToInvalidate.size(),
+ E, blockCount, 0,
+ /* invalidateGlobals = */ true);
+
+ Builder->MakeNode(destCall, E, Pred, state);
}
+
+ // Do the post visit.
+ getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);
}
void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
@@ -165,105 +265,25 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
Dst.Add(N);
}
-void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- // Get the method type.
- const FunctionProtoType *FnType =
- MCE->getCallee()->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Method type not available");
-
- // Evaluate explicit arguments with a worklist.
- ExplodedNodeSet argsEvaluated;
- evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated);
-
- // Evaluate the implicit object argument.
- ExplodedNodeSet AllargsEvaluated;
- const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
- if (!ME)
- return;
- Expr *ObjArgExpr = ME->getBase();
- for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
- E = argsEvaluated.end(); I != E; ++I) {
- Visit(ObjArgExpr, *I, AllargsEvaluated);
- }
-
- // Now evaluate the call itself.
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
- assert(MD && "not a CXXMethodDecl?");
- evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst);
-}
-
-void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(C->getCalleeDecl());
- if (!MD) {
- // If the operator doesn't represent a method call treat as regural call.
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
- return;
- }
-
- // Determine the type of function we're calling (if available).
- const FunctionProtoType *Proto = NULL;
- QualType FnType = C->getCallee()->IgnoreParens()->getType();
- if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
- Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
-
- // Evaluate arguments treating the first one (object method is called on)
- // as alvalue.
- ExplodedNodeSet argsEvaluated;
- evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true);
-
- // Now evaluate the call itself.
- evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst);
-}
-
-void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
- const Expr *ThisExpr, ExplodedNode *Pred,
- ExplodedNodeSet &Src, ExplodedNodeSet &Dst) {
- // Allow checkers to pre-visit the member call.
- ExplodedNodeSet PreVisitChecks;
- CheckerVisit(MCE, PreVisitChecks, Src, PreVisitStmtCallback);
-
- if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) {
- // FIXME: conservative method call evaluation.
- CheckerVisit(MCE, Dst, PreVisitChecks, PostVisitStmtCallback);
- return;
- }
-
- const StackFrameContext *SFC = AMgr.getStackFrame(MD,
- Pred->getLocationContext(),
- MCE,
- Builder->getBlock(),
- Builder->getIndex());
- const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
- CallEnter Loc(MCE, SFC, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(),
- E = PreVisitChecks.end(); I != E; ++I) {
- // Set up 'this' region.
- const GRState *state = GetState(*I);
- state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr));
- Dst.Add(Builder->generateNode(Loc, state, *I));
- }
-}
-
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- if (CNE->isArray()) {
- // FIXME: allocating an array has not been handled.
- return;
- }
-
- unsigned Count = Builder->getCurrentBlockCount();
+
+ unsigned blockCount = Builder->getCurrentBlockCount();
DefinedOrUnknownSVal symVal =
- svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), Count);
- const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
-
+ svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount);
+ const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
-
const ElementRegion *EleReg =
- getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
+ getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
+
+ if (CNE->isArray()) {
+ // FIXME: allocating an array requires simulating the constructors.
+ // For now, just return a symbolicated region.
+ const GRState *state = GetState(Pred);
+ state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
+ MakeNode(Dst, CNE, Pred, state);
+ return;
+ }
// Evaluate constructor arguments.
const FunctionProtoType *FnType = NULL;
@@ -277,11 +297,39 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// Initialize the object region and bind the 'new' expression.
for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
E = argsEvaluated.end(); I != E; ++I) {
+
const GRState *state = GetState(*I);
+
+ // Accumulate list of regions that are invalidated.
+ // FIXME: Eventually we should unify the logic for constructor
+ // processing in one place.
+ llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate;
+ for (CXXNewExpr::const_arg_iterator
+ ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end();
+ ai != ae; ++ai)
+ {
+ SVal val = state->getSVal(*ai);
+ if (const MemRegion *region = val.getAsRegion())
+ regionsToInvalidate.push_back(region);
+ }
if (ObjTy->isRecordType()) {
- state = state->invalidateRegion(EleReg, CNE, Count);
+ regionsToInvalidate.push_back(EleReg);
+ // Invalidate the regions.
+ state = state->invalidateRegions(regionsToInvalidate.data(),
+ regionsToInvalidate.data() +
+ regionsToInvalidate.size(),
+ CNE, blockCount, 0,
+ /* invalidateGlobals = */ true);
+
} else {
+ // Invalidate the regions.
+ state = state->invalidateRegions(regionsToInvalidate.data(),
+ regionsToInvalidate.data() +
+ regionsToInvalidate.size(),
+ CNE, blockCount, 0,
+ /* invalidateGlobals = */ true);
+
if (CNE->hasInitializer()) {
SVal V = state->getSVal(*CNE->constructor_arg_begin());
state = state->bindLoc(loc::MemRegionVal(EleReg), V);
diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index a014eec76bd4..f6fb8f256c01 100644
--- a/lib/StaticAnalyzer/Core/Checker.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -1,4 +1,4 @@
-//== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=//
+//== CheckerContext.cpp - Context info for path-sensitive checkers-----------=//
//
// The LLVM Compiler Infrastructure
//
@@ -7,17 +7,15 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines Checker and CheckerVisitor, classes used for creating
-// domain-specific checks.
+// This file defines CheckerContext that provides contextual info for
+// path-sensitive checkers.
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
using namespace clang;
using namespace ento;
-Checker::~Checker() {}
-
CheckerContext::~CheckerContext() {
// Do we need to autotransition? 'Dst' can get populated in a variety of
// ways, including 'addTransition()' adding the predecessor node to Dst
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 75d331a131a8..4a2549091cb4 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -20,6 +20,32 @@
using namespace clang;
using namespace ento;
+bool CheckerManager::hasPathSensitiveCheckers() const {
+ return !StmtCheckers.empty() ||
+ !PreObjCMessageCheckers.empty() ||
+ !PostObjCMessageCheckers.empty() ||
+ !LocationCheckers.empty() ||
+ !BindCheckers.empty() ||
+ !EndAnalysisCheckers.empty() ||
+ !EndPathCheckers.empty() ||
+ !BranchConditionCheckers.empty() ||
+ !LiveSymbolsCheckers.empty() ||
+ !DeadSymbolsCheckers.empty() ||
+ !RegionChangesCheckers.empty() ||
+ !EvalAssumeCheckers.empty() ||
+ !EvalCallCheckers.empty();
+}
+
+void CheckerManager::finishedCheckerRegistration() {
+#ifndef NDEBUG
+ // Make sure that for every event that has listeners, there is at least
+ // one dispatcher registered for it.
+ for (llvm::DenseMap<EventTag, EventInfo>::iterator
+ I = Events.begin(), E = Events.end(); I != E; ++I)
+ assert(I->second.HasDispatcher && "No dispatcher registered for an event");
+#endif
+}
+
//===----------------------------------------------------------------------===//
// Functions for running checkers for AST traversing..
//===----------------------------------------------------------------------===//
@@ -205,6 +231,40 @@ void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
expandGraphWithCheckers(C, Dst, Src);
}
+namespace {
+ struct CheckBindContext {
+ typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy;
+ const CheckersTy &Checkers;
+ SVal Loc;
+ SVal Val;
+ const Stmt *S;
+ ExprEngine &Eng;
+
+ 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)
+ : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckBindFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ ProgramPoint::PreStmtKind, 0, S);
+ checkFn(Loc, Val, C);
+ }
+ };
+}
+
+/// \brief Run checkers for binding of a value to a location.
+void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ SVal location, SVal val,
+ const Stmt *S, ExprEngine &Eng) {
+ CheckBindContext C(BindCheckers, location, val, S, Eng);
+ expandGraphWithCheckers(C, Dst, Src);
+}
+
void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
BugReporter &BR,
ExprEngine &Eng) {
@@ -222,6 +282,16 @@ void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B,
}
}
+/// \brief Run checkers for branch condition.
+void CheckerManager::runCheckersForBranchCondition(const Stmt *condition,
+ BranchNodeBuilder &B,
+ ExprEngine &Eng) {
+ for (unsigned i = 0, e = BranchConditionCheckers.size(); i != e; ++i) {
+ CheckBranchConditionFunc fn = BranchConditionCheckers[i];
+ fn(condition, B, Eng);
+ }
+}
+
/// \brief Run checkers for live symbols.
void CheckerManager::runCheckersForLiveSymbols(const GRState *state,
SymbolReaper &SymReaper) {
@@ -287,6 +357,20 @@ CheckerManager::runCheckersForRegionChanges(const GRState *state,
return state;
}
+/// \brief Run checkers for handling assumptions on symbolic values.
+const GRState *
+CheckerManager::runCheckersForEvalAssume(const GRState *state,
+ SVal Cond, bool Assumption) {
+ for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
+ // If any checker declares the state infeasible (or if it starts that way),
+ // bail out.
+ if (!state)
+ return NULL;
+ state = EvalAssumeCheckers[i](state, Cond, Assumption);
+ }
+ return state;
+}
+
/// \brief Run checkers for evaluating a call.
/// Only one checker will evaluate the call.
void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
@@ -371,6 +455,10 @@ void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
LocationCheckers.push_back(checkfn);
}
+void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
+ BindCheckers.push_back(checkfn);
+}
+
void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
EndAnalysisCheckers.push_back(checkfn);
}
@@ -379,6 +467,11 @@ void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) {
EndPathCheckers.push_back(checkfn);
}
+void CheckerManager::_registerForBranchCondition(
+ CheckBranchConditionFunc checkfn) {
+ BranchConditionCheckers.push_back(checkfn);
+}
+
void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
LiveSymbolsCheckers.push_back(checkfn);
}
@@ -393,6 +486,10 @@ void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
RegionChangesCheckers.push_back(info);
}
+void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
+ EvalAssumeCheckers.push_back(checkfn);
+}
+
void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
EvalCallCheckers.push_back(checkfn);
}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 08a2068c0106..34cd6e8884a0 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -19,8 +19,6 @@
#include "clang/AST/Expr.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
-#include <vector>
-#include <queue>
using llvm::cast;
using llvm::isa;
@@ -310,7 +308,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
for (llvm::SmallVectorImpl<ExplodedNode*>::const_iterator
I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end();
I != E; ++I) {
- blocksAborted.push_back(std::make_pair(L, *I));
+ blocksExhausted.push_back(std::make_pair(L, *I));
}
}
@@ -602,6 +600,25 @@ StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
return NULL;
}
+// This function generate a new ExplodedNode but not a new branch(block edge).
+ExplodedNode* BranchNodeBuilder::generateNode(const Stmt* Condition,
+ const GRState* State) {
+ bool IsNew;
+
+ ExplodedNode* Succ
+ = Eng.G->getNode(PostCondition(Condition, Pred->getLocationContext()), State,
+ &IsNew);
+
+ Succ->addPredecessor(Pred, *Eng.G);
+
+ Pred = Succ;
+
+ if (IsNew)
+ return Succ;
+
+ return NULL;
+}
+
ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State,
bool branch) {
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 1bffa3022e43..a00f9dc10b68 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -27,7 +27,17 @@ SVal Environment::lookupExpr(const Stmt* E) const {
return UnknownVal();
}
-SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const {
+SVal Environment::getSVal(const Stmt *E, 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(E);
+ }
+
for (;;) {
switch (E->getStmtClass()) {
case Stmt::AddrLabelExprClass:
@@ -41,6 +51,10 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const {
// ParenExprs are no-ops.
E = cast<ParenExpr>(E)->getSubExpr();
continue;
+ case Stmt::GenericSelectionExprClass:
+ // GenericSelectionExprs are no-ops.
+ E = cast<GenericSelectionExpr>(E)->getResultExpr();
+ continue;
case Stmt::CharacterLiteralClass: {
const CharacterLiteral* C = cast<CharacterLiteral>(E);
return svalBuilder.makeIntVal(C->getValue(), C->getType());
@@ -60,6 +74,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const {
else
return svalBuilder.makeIntVal(cast<IntegerLiteral>(E));
}
+ // For special C0xx nullptr case, make a null pointer SVal.
+ case Stmt::CXXNullPtrLiteralExprClass:
+ return svalBuilder.makeNull();
case Stmt::ImplicitCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::CStyleCastExprClass: {
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 2a8364d4117f..fa16fead9f1d 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -374,7 +374,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
WL2.push_back(*I);
}
- // Finally, explictly mark all nodes without any successors as sinks.
+ // Finally, explicitly mark all nodes without any successors as sinks.
if (N->isSink())
NewN->markAsSink();
}
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index c1b1e656989b..657420d06f06 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -13,15 +13,11 @@
//
//===----------------------------------------------------------------------===//
-// FIXME: Restructure checker registration.
-#include "InternalChecks.h"
-
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
@@ -63,278 +59,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
}
//===----------------------------------------------------------------------===//
-// Checker worklist routines.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
- ExplodedNodeSet &Src, CallbackKind Kind) {
-
- // Determine if we already have a cached 'CheckersOrdered' vector
- // specifically tailored for the provided <CallbackKind, Stmt kind>. This
- // can reduce the number of checkers actually called.
- CheckersOrdered *CO = &Checkers;
- llvm::OwningPtr<CheckersOrdered> NewCO;
-
- // The cache key is made up of the and the callback kind (pre- or post-visit)
- // and the statement kind.
- CallbackTag K = GetCallbackTag(Kind, S->getStmtClass());
-
- CheckersOrdered *& CO_Ref = COCache[K];
-
- if (!CO_Ref) {
- // If we have no previously cached CheckersOrdered vector for this
- // statement kind, then create one.
- NewCO.reset(new CheckersOrdered);
- }
- else {
- // Use the already cached set.
- CO = CO_Ref;
- }
-
- if (CO->empty()) {
- // If there are no checkers, just delegate to the checker manager.
- getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
- Dst, Src, S, *this);
- return;
- }
-
- ExplodedNodeSet CheckersV1Dst;
- ExplodedNodeSet Tmp;
- ExplodedNodeSet *PrevSet = &Src;
- unsigned checkersEvaluated = 0;
-
- for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) {
- // If all nodes are sunk, bail out early.
- if (PrevSet->empty())
- break;
- ExplodedNodeSet *CurrSet = 0;
- if (I+1 == E)
- CurrSet = &CheckersV1Dst;
- else {
- CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
- }
- void *tag = I->first;
- Checker *checker = I->second;
- bool respondsToCallback = true;
-
- for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI) {
-
- checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag,
- Kind == PreVisitStmtCallback, respondsToCallback);
-
- }
-
- PrevSet = CurrSet;
-
- if (NewCO.get()) {
- ++checkersEvaluated;
- if (respondsToCallback)
- NewCO->push_back(*I);
- }
- }
-
- // If we built NewCO, check if we called all the checkers. This is important
- // so that we know that we accurately determined the entire set of checkers
- // that responds to this callback. Note that 'checkersEvaluated' might
- // not be the same as Checkers.size() if one of the Checkers generates
- // a sink node.
- if (NewCO.get() && checkersEvaluated == Checkers.size())
- CO_Ref = NewCO.take();
-
- // Don't autotransition. The CheckerContext objects should do this
- // automatically.
-
- getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
- Dst, CheckersV1Dst, S, *this);
-}
-
-void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
- ExplodedNodeSet &Dst,
- ExplodedNodeSet &Src,
- bool isPrevisit) {
-
- if (Checkers.empty()) {
- getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, Src, msg,
- *this);
- return;
- }
-
- ExplodedNodeSet CheckersV1Dst;
- ExplodedNodeSet Tmp;
- ExplodedNodeSet *PrevSet = &Src;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
- {
- ExplodedNodeSet *CurrSet = 0;
- if (I+1 == E)
- CurrSet = &CheckersV1Dst;
- else {
- CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
- }
-
- void *tag = I->first;
- Checker *checker = I->second;
-
- for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg,
- *NI, tag, isPrevisit);
-
- // Update which NodeSet is the current one.
- PrevSet = CurrSet;
- }
-
- getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, CheckersV1Dst,
- msg, *this);
-}
-
-void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
- ExplodedNodeSet &Dst,
- const GRState *state,
- ExplodedNode *Pred) {
- bool evaluated = false;
- ExplodedNodeSet DstTmp;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
- void *tag = I->first;
- Checker *checker = I->second;
-
- if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state,
- tag)) {
- evaluated = true;
- break;
- } else
- // The checker didn't evaluate the expr. Restore the Dst.
- DstTmp.clear();
- }
-
- if (evaluated)
- Dst.insert(DstTmp);
- else
- Dst.insert(Pred);
-}
-
-// CheckerEvalCall returns true if one of the checkers processed the node.
-// This may return void when all call evaluation logic goes to some checker
-// in the future.
-bool ExprEngine::CheckerEvalCall(const CallExpr *CE,
- ExplodedNodeSet &Dst,
- ExplodedNode *Pred) {
- bool evaluated = false;
- ExplodedNodeSet DstTmp;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
- void *tag = I->first;
- Checker *checker = I->second;
-
- if (checker->GR_evalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) {
- evaluated = true;
- break;
- } else
- // The checker didn't evaluate the expr. Restore the DstTmp set.
- DstTmp.clear();
- }
-
- if (evaluated) {
- Dst.insert(DstTmp);
- return evaluated;
- }
-
- class DefaultEval : public GraphExpander {
- bool &Evaluated;
- public:
- DefaultEval(bool &evaluated) : Evaluated(evaluated) { }
- virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- Evaluated = false;
- Dst.insert(Pred);
- }
- };
-
- evaluated = true;
- DefaultEval defaultEval(evaluated);
- getCheckerManager().runCheckersForEvalCall(Dst, Pred, CE, *this,
- &defaultEval);
- return evaluated;
-}
-
-// FIXME: This is largely copy-paste from CheckerVisit(). Need to
-// unify.
-void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
- ExplodedNodeSet &Src, SVal location,
- SVal val, bool isPrevisit) {
-
- if (Checkers.empty()) {
- Dst.insert(Src);
- return;
- }
-
- ExplodedNodeSet Tmp;
- ExplodedNodeSet *PrevSet = &Src;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
- {
- ExplodedNodeSet *CurrSet = 0;
- if (I+1 == E)
- CurrSet = &Dst;
- else {
- CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
- }
-
- void *tag = I->first;
- Checker *checker = I->second;
-
- for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE,
- *NI, tag, location, val, isPrevisit);
-
- // Update which NodeSet is the current one.
- PrevSet = CurrSet;
- }
-
- // Don't autotransition. The CheckerContext objects should do this
- // automatically.
-}
-//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
-static void RegisterInternalChecks(ExprEngine &Eng) {
- // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
- // are different than what probably many checks will do since they don't
- // create BugReports on-the-fly but instead wait until ExprEngine finishes
- // analyzing a function. Generation of BugReport objects is done via a call
- // to 'FlushReports' from BugReporter.
- // The following checks do not need to have their associated BugTypes
- // explicitly registered with the BugReporter. If they issue any BugReports,
- // their associated BugType will get registered with the BugReporter
- // automatically. Note that the check itself is owned by the ExprEngine
- // object.
- RegisterAdjustedReturnValueChecker(Eng);
- // CallAndMessageChecker should be registered before AttrNonNullChecker,
- // where we assume arguments are not undefined.
- RegisterCallAndMessageChecker(Eng);
- RegisterAttrNonNullChecker(Eng);
- RegisterDereferenceChecker(Eng);
- RegisterVLASizeChecker(Eng);
- RegisterDivZeroChecker(Eng);
- RegisterReturnUndefChecker(Eng);
- RegisterUndefinedArraySubscriptChecker(Eng);
- RegisterUndefinedAssignmentChecker(Eng);
- RegisterUndefBranchChecker(Eng);
- RegisterUndefCapturedBlockVarChecker(Eng);
- RegisterUndefResultChecker(Eng);
-
- // This is not a checker yet.
- RegisterNoReturnFunctionChecker(Eng);
- RegisterBuiltinFunctionChecker(Eng);
- RegisterOSAtomicChecker(Eng);
-}
-
ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
: AMgr(mgr),
Engine(*this),
@@ -349,8 +76,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", getContext())),
BR(mgr, *this), TF(tf) {
- // Register internal checks.
- RegisterInternalChecks(*this);
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
@@ -365,14 +90,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
ExprEngine::~ExprEngine() {
BR.FlushReports();
delete [] NSExceptionInstanceRaiseSelectors;
-
- // Delete the set of checkers.
- for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
- delete I->second;
-
- for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end();
- I!=E;++I)
- delete I->second;
}
//===----------------------------------------------------------------------===//
@@ -447,51 +164,7 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
/// logic for handling assumptions on symbolic values.
const GRState *ExprEngine::processAssume(const GRState *state, SVal cond,
bool assumption) {
- // Determine if we already have a cached 'CheckersOrdered' vector
- // specifically tailored for processing assumptions. This
- // can reduce the number of checkers actually called.
- CheckersOrdered *CO = &Checkers;
- llvm::OwningPtr<CheckersOrdered> NewCO;
-
- CallbackTag K = GetCallbackTag(processAssumeCallback);
- CheckersOrdered *& CO_Ref = COCache[K];
-
- if (!CO_Ref) {
- // If we have no previously cached CheckersOrdered vector for this
- // statement kind, then create one.
- NewCO.reset(new CheckersOrdered);
- }
- else {
- // Use the already cached set.
- CO = CO_Ref;
- }
-
- if (!CO->empty()) {
- // Let the checkers have a crack at the assume before the transfer functions
- // get their turn.
- for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) {
-
- // If any checker declares the state infeasible (or if it starts that
- // way), bail out.
- if (!state)
- return NULL;
-
- Checker *C = I->second;
- bool respondsToCallback = true;
-
- state = C->evalAssume(state, cond, assumption, &respondsToCallback);
-
- // Check if we're building the cache of checkers that care about
- // assumptions.
- if (NewCO.get() && respondsToCallback)
- NewCO->push_back(*I);
- }
-
- // If we got through all the checkers, and we built a list of those that
- // care about assumptions, save it.
- if (NewCO.get())
- CO_Ref = NewCO.take();
- }
+ state = getCheckerManager().runCheckersForEvalAssume(state, cond, assumption);
// If the state is infeasible at this point, bail out.
if (!state)
@@ -501,18 +174,6 @@ const GRState *ExprEngine::processAssume(const GRState *state, SVal cond,
}
bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) {
- CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
- CheckersOrdered *CO = COCache[K];
-
- if (!CO)
- CO = &Checkers;
-
- for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
- Checker *C = I->second;
- if (C->wantsRegionChangeUpdate(state))
- return true;
- }
-
return getCheckerManager().wantsRegionChangeUpdate(state);
}
@@ -520,78 +181,30 @@ const GRState *
ExprEngine::processRegionChanges(const GRState *state,
const MemRegion * const *Begin,
const MemRegion * const *End) {
- // FIXME: Most of this method is copy-pasted from processAssume.
-
- // Determine if we already have a cached 'CheckersOrdered' vector
- // specifically tailored for processing region changes. This
- // can reduce the number of checkers actually called.
- CheckersOrdered *CO = &Checkers;
- llvm::OwningPtr<CheckersOrdered> NewCO;
-
- CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
- CheckersOrdered *& CO_Ref = COCache[K];
-
- if (!CO_Ref) {
- // If we have no previously cached CheckersOrdered vector for this
- // callback, then create one.
- NewCO.reset(new CheckersOrdered);
- }
- else {
- // Use the already cached set.
- CO = CO_Ref;
- }
-
- // If there are no checkers, just delegate to the checker manager.
- if (CO->empty())
- return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
-
- for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
- // If any checker declares the state infeasible (or if it starts that way),
- // bail out.
- if (!state)
- return NULL;
-
- Checker *C = I->second;
- bool respondsToCallback = true;
-
- state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback);
-
- // See if we're building a cache of checkers that care about region changes.
- if (NewCO.get() && respondsToCallback)
- NewCO->push_back(*I);
- }
-
- // If we got through all the checkers, and we built a list of those that
- // care about region changes, save it.
- if (NewCO.get())
- CO_Ref = NewCO.take();
-
return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
}
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
- for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
- I != E; ++I) {
- I->second->VisitEndAnalysis(G, BR, *this);
- }
getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
void ExprEngine::processCFGElement(const CFGElement E,
StmtNodeBuilder& builder) {
switch (E.getKind()) {
- case CFGElement::Statement:
- ProcessStmt(E.getAs<CFGStmt>(), builder);
- break;
- case CFGElement::Initializer:
- ProcessInitializer(E.getAs<CFGInitializer>(), builder);
- break;
- case CFGElement::ImplicitDtor:
- ProcessImplicitDtor(E.getAs<CFGImplicitDtor>(), builder);
- break;
- default:
- // Suppress compiler warning.
- llvm_unreachable("Unexpected CFGElement kind.");
+ case CFGElement::Invalid:
+ llvm_unreachable("Unexpected CFGElement kind.");
+ case CFGElement::Statement:
+ ProcessStmt(E.getAs<CFGStmt>()->getStmt(), builder);
+ return;
+ case CFGElement::Initializer:
+ ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), builder);
+ return;
+ case CFGElement::AutomaticObjectDtor:
+ case CFGElement::BaseDtor:
+ case CFGElement::MemberDtor:
+ case CFGElement::TemporaryDtor:
+ ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), builder);
+ return;
}
}
@@ -615,13 +228,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
if (AMgr.shouldPurgeDead()) {
const GRState *St = EntryNode->getState();
-
- for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
- I != E; ++I) {
- Checker *checker = I->second;
- checker->MarkLiveSymbols(St, SymReaper);
- }
-
getCheckerManager().runCheckersForLiveSymbols(St, SymReaper);
const StackFrameContext *SFC = LC->getCurrentStackFrame();
@@ -647,33 +253,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
CleanedState, SymReaper);
- ExplodedNodeSet checkersV1Tmp;
- if (Checkers.empty())
- checkersV1Tmp.insert(Tmp2);
- else {
- ExplodedNodeSet Tmp3;
- ExplodedNodeSet *SrcSet = &Tmp2;
- for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
- I != E; ++I) {
- ExplodedNodeSet *DstSet = 0;
- if (I+1 == E)
- DstSet = &checkersV1Tmp;
- else {
- DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
- DstSet->clear();
- }
-
- void *tag = I->first;
- Checker *checker = I->second;
- for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
- NI != NE; ++NI)
- checker->GR_evalDeadSymbols(*DstSet, *Builder, *this, currentStmt,
- *NI, SymReaper, tag);
- SrcSet = DstSet;
- }
- }
-
- getCheckerManager().runCheckersForDeadSymbols(Tmp, checkersV1Tmp,
+ getCheckerManager().runCheckersForDeadSymbols(Tmp, Tmp2,
SymReaper, currentStmt, *this);
if (!Builder->BuildSinks && !Builder->hasGeneratedNode)
@@ -767,7 +347,7 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
StmtNodeBuilder &builder) {
Builder = &builder;
- switch (D.getDtorKind()) {
+ switch (D.getKind()) {
case CFGElement::AutomaticObjectDtor:
ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), builder);
break;
@@ -842,10 +422,8 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
// C++ stuff we don't support yet.
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXCatchStmtClass:
- case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
- case Stmt::ExprWithCleanupsClass:
- case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::CXXForRangeStmtClass:
case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXThrowExprClass:
@@ -857,20 +435,35 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::UnaryTypeTraitExprClass:
case Stmt::BinaryTypeTraitExprClass:
+ case Stmt::ArrayTypeTraitExprClass:
+ case Stmt::ExpressionTraitExprClass:
case Stmt::UnresolvedLookupExprClass:
case Stmt::UnresolvedMemberExprClass:
case Stmt::CXXNoexceptExprClass:
case Stmt::PackExpansionExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
+ case Stmt::SEHTryStmtClass:
+ case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHFinallyStmtClass:
{
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;
- MakeNode(Dst, S, Pred, GetState(Pred));
+ const ExplodedNode *node = MakeNode(Dst, S, Pred, GetState(Pred));
+ Engine.addAbortedBlock(node, Builder->getBlock());
break;
}
-
+
+ // We don't handle default arguments either yet, but we can fake it
+ // for now by just skipping them.
+ case Stmt::CXXDefaultArgExprClass: {
+ Dst.Add(Pred);
+ break;
+ }
+
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
+ case Stmt::GenericSelectionExprClass:
+ llvm_unreachable("GenericSelectionExprs already handled.");
// Cases that should never be evaluated simply because they shouldn't
// appear in the CFG.
case Stmt::BreakStmtClass:
@@ -879,11 +472,15 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::ContinueStmtClass:
case Stmt::DefaultStmtClass:
case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
case Stmt::GotoStmtClass:
+ case Stmt::IfStmtClass:
case Stmt::IndirectGotoStmtClass:
case Stmt::LabelStmtClass:
case Stmt::NoStmtClass:
case Stmt::NullStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::WhileStmtClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
break;
@@ -927,8 +524,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::IntegerLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::ExprWithCleanupsClass:
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
break;
@@ -974,9 +573,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
- case Stmt::CallExprClass: {
- const CallExpr* C = cast<CallExpr>(S);
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+ case Stmt::CallExprClass:
+ case Stmt::CXXOperatorCallExprClass:
+ case Stmt::CXXMemberCallExprClass: {
+ VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
break;
}
@@ -988,18 +588,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
- case Stmt::CXXMemberCallExprClass: {
- const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
- VisitCXXMemberCallExpr(MCE, Pred, Dst);
- break;
- }
-
- case Stmt::CXXOperatorCallExprClass: {
- const CXXOperatorCallExpr *C = cast<CXXOperatorCallExpr>(S);
- VisitCXXOperatorCallExpr(C, Pred, Dst);
- break;
- }
-
case Stmt::CXXNewExprClass: {
const CXXNewExpr *NE = cast<CXXNewExpr>(S);
VisitCXXNewExpr(NE, Pred, Dst);
@@ -1050,12 +638,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
break;
- case Stmt::ForStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
-
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CXXStaticCastExprClass:
@@ -1068,12 +650,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
break;
}
- case Stmt::IfStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
-
case Stmt::InitListExprClass:
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
break;
@@ -1110,8 +686,9 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
break;
- case Stmt::SizeOfAlignOfExprClass:
- VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
+ Pred, Dst);
break;
case Stmt::StmtExprClass: {
@@ -1142,12 +719,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
return;
}
- case Stmt::SwitchStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
-
case Stmt::UnaryOperatorClass: {
const UnaryOperator *U = cast<UnaryOperator>(S);
if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) {
@@ -1159,12 +730,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
VisitUnaryOperator(U, Pred, Dst);
break;
}
-
- case Stmt::WhileStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
}
}
@@ -1313,11 +878,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
Condition->getLocStart(),
"Error evaluating branch");
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
- void *tag = I->first;
- Checker *checker = I->second;
- checker->VisitBranchCondition(builder, *this, Condition, tag);
- }
+ getCheckerManager().runCheckersForBranchCondition(Condition, builder, *this);
// If the branch condition is undefined, return;
if (!builder.isFeasible(true) && !builder.isFeasible(false))
@@ -1326,7 +887,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
const GRState* PrevState = builder.getState();
SVal X = PrevState->getSVal(Condition);
- if (X.isUnknown()) {
+ if (X.isUnknownOrUndef()) {
// Give it a chance to recover from unknown.
if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
if (Ex->getType()->isIntegerType()) {
@@ -1344,7 +905,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term,
}
}
// If the condition is still unknown, give up.
- if (X.isUnknown()) {
+ if (X.isUnknownOrUndef()) {
builder.generateNode(MarkBranch(PrevState, Term, true), true);
builder.generateNode(MarkBranch(PrevState, Term, false), false);
return;
@@ -1441,12 +1002,6 @@ void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L,
void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
getTF().evalEndPath(*this, builder);
StateMgr.EndPath(builder.getState());
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
- void *tag = I->first;
- Checker *checker = I->second;
- EndOfFunctionNodeBuilder B = builder.withCheckerTag(tag);
- checker->evalEndPath(B, tag, *this);
- }
getCheckerManager().runCheckersForEndPath(builder, *this);
}
@@ -1473,6 +1028,10 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
bool defaultIsFeasible = I == EI;
for ( ; I != EI; ++I) {
+ // Successor may be pruned out during CFG construction.
+ if (!I.getBlock())
+ continue;
+
const CaseStmt* Case = I.getCase();
// Evaluate the LHS of the case value.
@@ -1666,7 +1225,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ProgramPoint::PostLValueKind);
// Post-visit the BlockExpr.
- CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback);
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
}
void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
@@ -1723,7 +1282,7 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A,
ExplodedNodeSet Tmp2;
Visit(Idx, *I1, Tmp2); // Evaluate the index.
ExplodedNodeSet Tmp3;
- CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback);
+ getCheckerManager().runCheckersForPreStmt(Tmp3, Tmp2, A, *this);
for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) {
const GRState* state = GetState(*I2);
@@ -1784,7 +1343,8 @@ void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE,
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet, Src;
Src.Add(Pred);
- CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true);
+ getCheckerManager().runCheckersForBind(CheckedSet, Src, location, Val, StoreE,
+ *this);
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
@@ -1862,7 +1422,8 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
if (Tmp.empty())
return;
- assert(!location.isUndef());
+ if (location.isUndef())
+ return;
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
ProgramPoint::PostStoreKind);
@@ -1922,7 +1483,8 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
if (Tmp.empty())
return;
- assert(!location.isUndef());
+ if (location.isUndef())
+ return;
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
@@ -1955,57 +1517,36 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
return;
}
- if (Checkers.empty()) {
- ExplodedNodeSet Src;
- if (Builder->GetState(Pred) == state) {
- Src.Add(Pred);
- } else {
- // Associate this new state with an ExplodedNode.
- Src.Add(Builder->generateNode(S, state, Pred));
- }
- getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
- *this);
- return;
- }
-
ExplodedNodeSet Src;
- Src.Add(Pred);
- ExplodedNodeSet CheckersV1Dst;
- ExplodedNodeSet Tmp;
- ExplodedNodeSet *PrevSet = &Src;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
- {
- ExplodedNodeSet *CurrSet = 0;
- if (I+1 == E)
- CurrSet = &CheckersV1Dst;
- else {
- CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
- }
-
- void *tag = I->first;
- Checker *checker = I->second;
-
- for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI) {
- // Use the 'state' argument only when the predecessor node is the
- // same as Pred. This allows us to catch updates to the state.
- checker->GR_visitLocation(*CurrSet, *Builder, *this, S, *NI,
- *NI == Pred ? state : GetState(*NI),
- location, tag, isLoad);
- }
-
- // Update which NodeSet is the current one.
- PrevSet = CurrSet;
+ if (Builder->GetState(Pred) == state) {
+ Src.Add(Pred);
+ } else {
+ // Associate this new state with an ExplodedNode.
+ // FIXME: If I pass null tag, the graph is incorrect, e.g for
+ // int *p;
+ // p = 0;
+ // *p = 0xDEADBEEF;
+ // "p = 0" is not noted as "Null pointer value stored to 'p'" but
+ // instead "int *p" is noted as
+ // "Variable 'p' initialized to a null pointer value"
+ ExplodedNode *N = Builder->generateNode(S, state, Pred, this);
+ Src.Add(N ? N : Pred);
}
-
- getCheckerManager().runCheckersForLocation(Dst, CheckersV1Dst, location,
- isLoad, S, *this);
+ getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
+ *this);
}
bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
ExplodedNode *Pred) {
+ return false;
+
+ // Inlining isn't correct right now because we:
+ // (a) don't generate CallExit nodes.
+ // (b) we need a way to postpone doing post-visits of CallExprs until
+ // the CallExit. This means we need CallExits for the non-inline
+ // cases as well.
+
+#if 0
const GRState *state = GetState(Pred);
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
@@ -2014,6 +1555,29 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
if (!FD)
return false;
+ // Specially handle CXXMethods.
+ const CXXMethodDecl *methodDecl = 0;
+
+ switch (CE->getStmtClass()) {
+ default: break;
+ case Stmt::CXXOperatorCallExprClass: {
+ const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE);
+ methodDecl =
+ llvm::dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl());
+ break;
+ }
+ case Stmt::CXXMemberCallExprClass: {
+ const CXXMemberCallExpr *memberCall = cast<CXXMemberCallExpr>(CE);
+ const MemberExpr *memberExpr =
+ cast<MemberExpr>(memberCall->getCallee()->IgnoreParens());
+ methodDecl = cast<CXXMethodDecl>(memberExpr->getMemberDecl());
+ break;
+ }
+ }
+
+
+
+
// Check if the function definition is in the same translation unit.
if (FD->hasBody(FD)) {
const StackFrameContext *stackFrame =
@@ -2041,14 +1605,15 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
Dst.Add(N);
return true;
}
+
+ // Generate the CallExit node.
return false;
+#endif
}
-void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
- CallExpr::const_arg_iterator AI,
- CallExpr::const_arg_iterator AE,
- ExplodedNodeSet& Dst) {
+void ExprEngine::VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
+ ExplodedNodeSet& dst) {
// Determine the type of function we're calling (if available).
const FunctionProtoType *Proto = NULL;
@@ -2056,72 +1621,78 @@ void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
- // Evaluate the arguments.
- ExplodedNodeSet ArgsEvaluated;
- evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated);
-
- // Now process the call itself.
- ExplodedNodeSet DstTmp;
- const Expr* Callee = CE->getCallee()->IgnoreParens();
-
- for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
- NE=ArgsEvaluated.end(); NI != NE; ++NI) {
- // Evaluate the callee.
- ExplodedNodeSet DstTmp2;
- Visit(Callee, *NI, DstTmp2);
- // Perform the previsit of the CallExpr, storing the results in DstTmp.
- CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback);
+ // Should the first argument be evaluated as an lvalue?
+ bool firstArgumentAsLvalue = false;
+ switch (CE->getStmtClass()) {
+ case Stmt::CXXOperatorCallExprClass:
+ firstArgumentAsLvalue = true;
+ break;
+ default:
+ break;
}
+
+ // Evaluate the arguments.
+ ExplodedNodeSet dstArgsEvaluated;
+ evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, dstArgsEvaluated,
+ firstArgumentAsLvalue);
+
+ // Evaluate the callee.
+ ExplodedNodeSet dstCalleeEvaluated;
+ evalCallee(CE, dstArgsEvaluated, dstCalleeEvaluated);
+
+ // Perform the previsit of the CallExpr.
+ ExplodedNodeSet dstPreVisit;
+ getCheckerManager().runCheckersForPreStmt(dstPreVisit, dstCalleeEvaluated,
+ CE, *this);
+
+ // Now evaluate the call itself.
+ class DefaultEval : public GraphExpander {
+ ExprEngine &Eng;
+ const CallExpr *CE;
+ public:
+
+ DefaultEval(ExprEngine &eng, const CallExpr *ce)
+ : Eng(eng), CE(ce) {}
+ virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ // Should we inline the call?
+ if (Eng.getAnalysisManager().shouldInlineCall() &&
+ Eng.InlineCall(Dst, CE, Pred)) {
+ return;
+ }
- // Finally, evaluate the function call. We try each of the checkers
- // to see if the can evaluate the function call.
- ExplodedNodeSet DstTmp3;
-
- for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
- DI != DE; ++DI) {
+ StmtNodeBuilder &Builder = Eng.getBuilder();
+ assert(&Builder && "StmtNodeBuilder must be defined.");
- const GRState* state = GetState(*DI);
- SVal L = state->getSVal(Callee);
+ // Dispatch to the plug-in transfer function.
+ unsigned oldSize = Dst.size();
+ SaveOr OldHasGen(Builder.hasGeneratedNode);
- // FIXME: Add support for symbolic function calls (calls involving
- // function pointer values that are symbolic).
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- ExplodedNodeSet DstChecker;
+ // Dispatch to transfer function logic to handle the call itself.
+ const Expr* Callee = CE->getCallee()->IgnoreParens();
+ const GRState* state = Eng.GetState(Pred);
+ SVal L = state->getSVal(Callee);
+ Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred);
- // If the callee is processed by a checker, skip the rest logic.
- if (CheckerEvalCall(CE, DstChecker, *DI))
- DstTmp3.insert(DstChecker);
- else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) {
- // Callee is inlined. We shouldn't do post call checking.
- return;
- }
- else {
- for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
- DE_Checker = DstChecker.end();
- DI_Checker != DE_Checker; ++DI_Checker) {
-
- // Dispatch to the plug-in transfer function.
- unsigned oldSize = DstTmp3.size();
- SaveOr OldHasGen(Builder->hasGeneratedNode);
- Pred = *DI_Checker;
-
- // Dispatch to transfer function logic to handle the call itself.
- // FIXME: Allow us to chain together transfer functions.
- assert(Builder && "StmtNodeBuilder must be defined.");
- getTF().evalCall(DstTmp3, *this, *Builder, CE, L, Pred);
-
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && DstTmp3.size() == oldSize &&
- !Builder->hasGeneratedNode)
- MakeNode(DstTmp3, CE, Pred, state);
- }
+ // Handle the case where no nodes where generated. Auto-generate that
+ // contains the updated state if we aren't generating sinks.
+ if (!Builder.BuildSinks && Dst.size() == oldSize &&
+ !Builder.hasGeneratedNode)
+ Eng.MakeNode(Dst, CE, Pred, state);
}
- }
+ };
+
+ // Finally, evaluate the function call. We try each of the checkers
+ // to see if the can evaluate the function call.
+ ExplodedNodeSet dstCallEvaluated;
+ DefaultEval defEval(*this, CE);
+ getCheckerManager().runCheckersForEvalCall(dstCallEvaluated,
+ dstPreVisit,
+ CE, *this, &defEval);
// Finally, perform the post-condition check of the CallExpr and store
// the created nodes in 'Dst'.
- CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback);
+ getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
+ *this);
}
//===----------------------------------------------------------------------===//
@@ -2213,7 +1784,7 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
// Pre-visit the ObjCAtSynchronizedStmt.
ExplodedNodeSet Tmp;
Tmp.Add(Pred);
- CheckerVisit(S, Dst, Tmp, PreVisitStmtCallback);
+ getCheckerManager().runCheckersForPreStmt(Dst, Tmp, S, *this);
}
//===----------------------------------------------------------------------===//
@@ -2244,7 +1815,7 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex,
// Perform the post-condition check of the ObjCIvarRefExpr and store
// the created nodes in 'Dst'.
- CheckerVisit(Ex, Dst, dstIvar, PostVisitStmtCallback);
+ getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
}
//===----------------------------------------------------------------------===//
@@ -2414,7 +1985,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
// Handle the previsits checks.
ExplodedNodeSet DstPrevisit;
- CheckerVisitObjCMessage(msg, DstPrevisit, Src, /*isPreVisit=*/true);
+ getCheckerManager().runCheckersForPreObjCMessage(DstPrevisit, Src, msg,*this);
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
@@ -2430,33 +2001,34 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
if (const Expr *Receiver = msg.getInstanceReceiver()) {
const GRState *state = GetState(Pred);
-
- // Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal =
- cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-
- const GRState *notNilState, *nilState;
- llvm::tie(notNilState, nilState) = state->assume(receiverVal);
-
- // There are three cases: can be nil or non-nil, must be nil, must be
- // non-nil. We handle must be nil, and merge the rest two into non-nil.
- if (nilState && !notNilState) {
- CheckerEvalNilReceiver(msg, dstEval, nilState, Pred);
- continue;
+ SVal recVal = state->getSVal(Receiver);
+ if (!recVal.isUndef()) {
+ // Bifurcate the state into nil and non-nil ones.
+ DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+
+ const GRState *notNilState, *nilState;
+ llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+
+ // There are three cases: can be nil or non-nil, must be nil, must be
+ // non-nil. We ignore must be nil, and merge the rest two into non-nil.
+ if (nilState && !notNilState) {
+ dstEval.insert(Pred);
+ continue;
+ }
+
+ // Check if the "raise" message was sent.
+ assert(notNilState);
+ if (msg.getSelector() == RaiseSel)
+ RaisesException = true;
+
+ // Check if we raise an exception. For now treat these as sinks.
+ // Eventually we will want to handle exceptions properly.
+ if (RaisesException)
+ Builder->BuildSinks = true;
+
+ // Dispatch to plug-in transfer function.
+ evalObjCMessage(dstEval, msg, Pred, notNilState);
}
-
- // Check if the "raise" message was sent.
- assert(notNilState);
- if (msg.getSelector() == RaiseSel)
- RaisesException = true;
-
- // Check if we raise an exception. For now treat these as sinks.
- // Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
- // Dispatch to plug-in transfer function.
- evalObjCMessage(dstEval, msg, Pred, notNilState);
}
else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
IdentifierInfo* ClsName = Iface->getIdentifier();
@@ -2516,7 +2088,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
- CheckerVisitObjCMessage(msg, Dst, dstEval, /*isPreVisit=*/false);
+ getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
}
//===----------------------------------------------------------------------===//
@@ -2529,7 +2101,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
ExplodedNodeSet S1;
Visit(Ex, Pred, S1);
ExplodedNodeSet S2;
- CheckerVisit(CastE, S2, S1, PreVisitStmtCallback);
+ getCheckerManager().runCheckersForPreStmt(S2, S1, CastE, *this);
if (CastE->getCastKind() == CK_LValueToRValue ||
CastE->getCastKind() == CK_GetObjCProperty) {
@@ -2547,106 +2119,95 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
-
-#if 0
- // If we are evaluating the cast in an lvalue context, we implicitly want
- // the cast to evaluate to a location.
- if (asLValue) {
- ASTContext &Ctx = getContext();
- T = Ctx.getPointerType(Ctx.getCanonicalType(T));
- ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy));
- }
-#endif
-
- switch (CastE->getCastKind()) {
- case CK_ToVoid:
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
- Dst.Add(*I);
- return;
-
- case CK_LValueToRValue:
- case CK_NoOp:
- case CK_FunctionToPointerDecay:
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- // Copy the SVal of Ex to CastE.
- ExplodedNode *N = *I;
- const GRState *state = GetState(N);
- SVal V = state->getSVal(Ex);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, N, state);
- }
- return;
- case CK_GetObjCProperty:
- case CK_Dependent:
- case CK_ArrayToPointerDecay:
- case CK_BitCast:
- case CK_LValueBitCast:
- case CK_IntegralCast:
- case CK_NullToPointer:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_AnyPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
-
- case CK_ObjCObjectLValueCast: {
- // Delegate to SValBuilder to process.
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- ExplodedNode* N = *I;
- const GRState* state = GetState(N);
- SVal V = state->getSVal(Ex);
- V = svalBuilder.evalCast(V, T, ExTy);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, N, state);
- }
- return;
- }
+ for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
+ Pred = *I;
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase:
- // For DerivedToBase cast, delegate to the store manager.
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- ExplodedNode *node = *I;
- const GRState *state = GetState(node);
- SVal val = state->getSVal(Ex);
- val = getStoreManager().evalDerivedToBase(val, T);
- state = state->BindExpr(CastE, val);
- MakeNode(Dst, CastE, node, state);
+ switch (CastE->getCastKind()) {
+ case CK_ToVoid:
+ Dst.Add(Pred);
+ continue;
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ case CK_FunctionToPointerDecay: {
+ // Copy the SVal of Ex to CastE.
+ const GRState *state = GetState(Pred);
+ SVal V = state->getSVal(Ex);
+ state = state->BindExpr(CastE, V);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
+ case CK_GetObjCProperty:
+ case CK_Dependent:
+ case CK_ArrayToPointerDecay:
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_IntegralCast:
+ case CK_NullToPointer:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_PointerToBoolean:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexToBoolean:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralComplexToBoolean:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast: {
+ // Delegate to SValBuilder to process.
+ const GRState* state = GetState(Pred);
+ SVal V = state->getSVal(Ex);
+ V = svalBuilder.evalCast(V, T, ExTy);
+ state = state->BindExpr(CastE, V);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ // For DerivedToBase cast, delegate to the store manager.
+ const GRState *state = GetState(Pred);
+ SVal val = state->getSVal(Ex);
+ val = getStoreManager().evalDerivedToBase(val, T);
+ state = state->BindExpr(CastE, val);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
+ // Various C++ casts that are not handled yet.
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_BaseToDerived:
+ case CK_NullToMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_UserDefinedConversion:
+ case CK_ConstructorConversion:
+ case CK_VectorSplat:
+ case CK_MemberPointerToBoolean: {
+ // Recover some path-sensitivty by conjuring a new value.
+ QualType resultType = CastE->getType();
+ if (CastE->isLValue())
+ resultType = getContext().getPointerType(resultType);
+
+ SVal result =
+ svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType,
+ Builder->getCurrentBlockCount());
+
+ const GRState *state = GetState(Pred)->BindExpr(CastE, result);
+ MakeNode(Dst, CastE, Pred, state);
+ continue;
+ }
}
- return;
-
- // Various C++ casts that are not handled yet.
- case CK_Dynamic:
- case CK_ToUnion:
- case CK_BaseToDerived:
- case CK_NullToMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_UserDefinedConversion:
- case CK_ConstructorConversion:
- case CK_VectorSplat:
- case CK_MemberPointerToBoolean: {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- MakeNode(Dst, CastE, Pred, GetState(Pred));
- return;
- }
}
}
@@ -2702,7 +2263,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
Tmp.Add(Pred);
ExplodedNodeSet Tmp2;
- CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback);
+ getCheckerManager().runCheckersForPreStmt(Tmp2, Tmp, DS, *this);
for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
ExplodedNode *N = *I;
@@ -2741,33 +2302,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
}
}
-void ExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S,
- ExplodedNode *Pred, ExplodedNodeSet& Dst) {
-
- const Expr* InitEx = VD->getInit();
- ExplodedNodeSet Tmp;
- Visit(InitEx, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ExplodedNode *N = *I;
- const GRState *state = GetState(N);
-
- const LocationContext *LC = N->getLocationContext();
- SVal InitVal = state->getSVal(InitEx);
-
- // Recover some path-sensitivity if a scalar value evaluated to
- // UnknownVal.
- if (InitVal.isUnknown() ||
- !getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
- Builder->getCurrentBlockCount());
- }
-
- evalBind(Dst, S, N, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
- }
-}
-
namespace {
// This class is used by VisitInitListExpr as an item in a worklist
// for processing the values contained in an InitListExpr.
@@ -2861,19 +2395,15 @@ void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
assert(0 && "unprocessed InitListExpr type");
}
-/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type).
-void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex,
+/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof(type).
+void ExprEngine::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr* Ex,
ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
QualType T = Ex->getTypeOfArgument();
- CharUnits amt;
- if (Ex->isSizeOf()) {
- if (T == getContext().VoidTy) {
- // sizeof(void) == 1 byte.
- amt = CharUnits::One();
- }
- else if (!T->isConstantSizeType()) {
+ if (Ex->getKind() == UETT_SizeOf) {
+ if (!T->isIncompleteType() && !T->isConstantSizeType()) {
assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
// FIXME: Add support for VLA type arguments, not just VLA expressions.
@@ -2914,13 +2444,11 @@ void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex,
Dst.Add(Pred);
return;
}
- else {
- // All other cases.
- amt = getContext().getTypeSizeInChars(T);
- }
}
- else // Get alignment of the type.
- amt = getContext().getTypeAlignInChars(T);
+
+ Expr::EvalResult Result;
+ Ex->Evaluate(Result, getContext());
+ CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue());
MakeNode(Dst, Ex, Pred,
GetState(Pred)->BindExpr(Ex,
@@ -3263,7 +2791,7 @@ void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
}
ExplodedNodeSet CheckedSet;
- CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback);
+ getCheckerManager().runCheckersForPreStmt(CheckedSet, Src, RS, *this);
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I != E; ++I) {
@@ -3305,7 +2833,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
Visit(RHS, *I1, Tmp2);
ExplodedNodeSet CheckedSet;
- CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback);
+ getCheckerManager().runCheckersForPreStmt(CheckedSet, Tmp2, B, *this);
// With both the LHS and RHS evaluated, process the operation itself.
@@ -3432,16 +2960,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
}
}
- CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback);
-}
-
-//===----------------------------------------------------------------------===//
-// Checker registration/lookup.
-//===----------------------------------------------------------------------===//
-
-Checker *ExprEngine::lookupChecker(void *tag) const {
- CheckerMap::const_iterator I = CheckerM.find(tag);
- return (I == CheckerM.end()) ? NULL : Checkers[I->second].second;
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp3, B, *this);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/FlatStore.cpp b/lib/StaticAnalyzer/Core/FlatStore.cpp
index 99a5eadaca20..7bdca6b7f17d 100644
--- a/lib/StaticAnalyzer/Core/FlatStore.cpp
+++ b/lib/StaticAnalyzer/Core/FlatStore.cpp
@@ -90,6 +90,19 @@ StoreManager *ento::CreateFlatStoreManager(GRStateManager &StMgr) {
}
SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) {
+ // For access to concrete addresses, return UnknownVal. Checks
+ // for null dereferences (and similar errors) are done by checkers, not
+ // the Store.
+ // FIXME: We can consider lazily symbolicating such memory, but we really
+ // should defer this when we can reason easily about symbolicating arrays
+ // of bytes.
+ if (isa<loc::ConcreteInt>(L)) {
+ return UnknownVal();
+ }
+ if (!isa<loc::MemRegionVal>(L)) {
+ return UnknownVal();
+ }
+
const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
RegionInterval RI = RegionToInterval(R);
// FIXME: FlatStore should handle regions with unknown intervals.
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index 2e370d62e440..c005819c9c96 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -37,6 +37,35 @@ Selector ObjCMessage::getSelector() const {
return propE->getGetterSelector();
}
+ObjCMethodFamily ObjCMessage::getMethodFamily() const {
+ assert(isValid() && "This ObjCMessage is uninitialized!");
+ // Case 1. Explicit message send.
+ if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+ return msgE->getMethodFamily();
+
+ const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+
+ // Case 2. Reference to implicit property.
+ if (propE->isImplicitProperty()) {
+ if (isPropertySetter())
+ return propE->getImplicitPropertySetter()->getMethodFamily();
+ else
+ return propE->getImplicitPropertyGetter()->getMethodFamily();
+ }
+
+ // Case 3. Reference to explicit property.
+ const ObjCPropertyDecl *prop = propE->getExplicitProperty();
+ if (isPropertySetter()) {
+ if (prop->getSetterMethodDecl())
+ return prop->getSetterMethodDecl()->getMethodFamily();
+ return prop->getSetterName().getMethodFamily();
+ } else {
+ if (prop->getGetterMethodDecl())
+ return prop->getGetterMethodDecl()->getMethodFamily();
+ return prop->getGetterName().getMethodFamily();
+ }
+}
+
const ObjCMethodDecl *ObjCMessage::getMethodDecl() const {
assert(isValid() && "This ObjCMessage is uninitialized!");
if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
@@ -80,13 +109,27 @@ const Expr *ObjCMessage::getArgExpr(unsigned i) const {
}
QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
+ QualType resultTy;
+ bool isLVal = false;
+
if (CallE) {
+ isLVal = CallE->isLValue();
const Expr *Callee = CallE->getCallee();
if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl())
- return FD->getResultType();
- return CallE->getType();
+ resultTy = FD->getResultType();
+ else
+ resultTy = CallE->getType();
+ }
+ else {
+ isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) &&
+ Msg.getOriginExpr()->isLValue();
+ resultTy = Msg.getResultType(ctx);
}
- return Msg.getResultType(ctx);
+
+ if (isLVal)
+ resultTy = ctx.getPointerType(resultTy);
+
+ return resultTy;
}
SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
@@ -97,3 +140,10 @@ SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
return Msg.getArgSVal(i, State);
return UnknownVal();
}
+
+SVal CallOrObjCMessage::getCXXCallee() const {
+ assert(isCXXCall());
+ const Expr *callee =
+ cast<CXXMemberCallExpr>(CallE)->getImplicitObjectArgument();
+ return State->getSVal(callee);
+}
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 19e0e1257215..4522f976e648 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -337,6 +337,9 @@ public: // Part of public interface to class.
SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R,
QualType Ty, const MemRegion *superR);
+
+ SVal RetrieveLazyBinding(const MemRegion *lazyBindingRegion,
+ Store lazyBindingStore);
/// Retrieve the values in a struct and return a CompoundVal, used when doing
/// struct copy:
@@ -355,7 +358,8 @@ public: // Part of public interface to class.
/// Get the state and region whose binding this region R corresponds to.
std::pair<Store, const MemRegion*>
- GetLazyBinding(RegionBindings B, const MemRegion *R);
+ GetLazyBinding(RegionBindings B, const MemRegion *R,
+ const MemRegion *originalRegion);
StoreRef CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
const TypedRegion *R);
@@ -684,11 +688,11 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
QualType T = TR->getValueType();
// Invalidate the binding.
- if (T->isStructureType()) {
+ 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, Ctx.IntTy,
- Count);
+ DefinedOrUnknownSVal V =
+ svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -976,15 +980,20 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
std::pair<Store, const MemRegion *>
-RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
- if (Optional<SVal> OV = getDirectBinding(B, R))
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
- return std::make_pair(V->getStore(), V->getRegion());
-
+RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R,
+ const MemRegion *originalRegion) {
+
+ if (originalRegion != R) {
+ if (Optional<SVal> OV = getDefaultBinding(B, R)) {
+ if (const nonloc::LazyCompoundVal *V =
+ dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
+ return std::make_pair(V->getStore(), V->getRegion());
+ }
+ }
+
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, ER->getSuperRegion());
+ GetLazyBinding(B, ER->getSuperRegion(), originalRegion);
if (X.second)
return std::make_pair(X.first,
@@ -992,7 +1001,7 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
}
else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, FR->getSuperRegion());
+ GetLazyBinding(B, FR->getSuperRegion(), originalRegion);
if (X.second)
return std::make_pair(X.first,
@@ -1003,12 +1012,13 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
else if (const CXXBaseObjectRegion *baseReg =
dyn_cast<CXXBaseObjectRegion>(R)) {
const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, baseReg->getSuperRegion());
+ GetLazyBinding(B, baseReg->getSuperRegion(), originalRegion);
if (X.second)
return std::make_pair(X.first,
MRMgr.getCXXBaseObjectRegionWithSuper(baseReg, X.second));
}
+
// The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
// possible for a valid lazy binding.
return std::make_pair((Store) 0, (const MemRegion *) 0);
@@ -1098,14 +1108,19 @@ RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B,
QualType Ty) {
if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
- if (SymbolRef parentSym = D->getAsSymbol())
+ const SVal &val = D.getValue();
+ if (SymbolRef parentSym = val.getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
- if (D->isZeroConstant())
+ if (val.isZeroConstant())
return svalBuilder.makeZeroVal(Ty);
- if (D->isUnknownOrUndef())
- return *D;
+ if (val.isUnknownOrUndef())
+ return val;
+
+ // Lazy bindings are handled later.
+ if (isa<nonloc::LazyCompoundVal>(val))
+ return Optional<SVal>();
assert(0 && "Unknown default value");
}
@@ -1113,6 +1128,15 @@ RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B,
return Optional<SVal>();
}
+SVal RegionStoreManager::RetrieveLazyBinding(const MemRegion *lazyBindingRegion,
+ Store lazyBindingStore) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
+ return RetrieveElement(lazyBindingStore, ER);
+
+ return RetrieveField(lazyBindingStore,
+ cast<FieldRegion>(lazyBindingRegion));
+}
+
SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
const TypedRegion *R,
QualType Ty,
@@ -1140,14 +1164,10 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
// Lazy binding?
Store lazyBindingStore = NULL;
const MemRegion *lazyBindingRegion = NULL;
- llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R);
+ llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R, R);
- if (lazyBindingRegion) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
- return RetrieveElement(lazyBindingStore, ER);
- return RetrieveField(lazyBindingStore,
- cast<FieldRegion>(lazyBindingRegion));
- }
+ if (lazyBindingRegion)
+ return RetrieveLazyBinding(lazyBindingRegion, lazyBindingStore);
if (R->hasStackNonParametersStorage()) {
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
@@ -1250,12 +1270,12 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType();
assert(T->isStructureOrClassType());
- return svalBuilder.makeLazyCompoundVal(store, R);
+ return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
}
SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) {
assert(Ctx.getAsConstantArrayType(R->getValueType()));
- return svalBuilder.makeLazyCompoundVal(store, R);
+ return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
}
//===----------------------------------------------------------------------===//
@@ -1378,7 +1398,8 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedRegion* R,
// Treat the string as a lazy compound value.
nonloc::LazyCompoundVal LCV =
- cast<nonloc::LazyCompoundVal>(svalBuilder.makeLazyCompoundVal(store, S));
+ cast<nonloc::LazyCompoundVal>(svalBuilder.
+ makeLazyCompoundVal(StoreRef(store, *this), S));
return CopyLazyBindings(LCV, store, R);
}
@@ -1529,7 +1550,7 @@ StoreRef RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
// Now copy the bindings. This amounts to just binding 'V' to 'R'. This
// results in a zero-copy algorithm.
- return StoreRef(addBinding(B, R, BindingKey::Direct,
+ return StoreRef(addBinding(B, R, BindingKey::Default,
V).getRootWithoutRetain(), *this);
}
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index b0fd497e5719..71f2b4abb9c3 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -25,12 +25,12 @@ using namespace ento;
// Basic SVal creation.
//===----------------------------------------------------------------------===//
-DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType T) {
- if (Loc::isLocType(T))
+DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) {
+ if (Loc::isLocType(type))
return makeNull();
- if (T->isIntegerType())
- return makeIntVal(0, T);
+ if (type->isIntegerType())
+ return makeIntVal(0, type);
// FIXME: Handle floats.
// FIXME: Handle structs.
@@ -39,44 +39,44 @@ DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType T) {
NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
- const llvm::APSInt& v, QualType T) {
+ const llvm::APSInt& rhs, QualType type) {
// The Environment ensures we always get a persistent APSInt in
// BasicValueFactory, so we don't need to get the APSInt from
// BasicValueFactory again.
- assert(!Loc::isLocType(T));
- return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, v, T));
+ assert(!Loc::isLocType(type));
+ return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, rhs, type));
}
NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
- const SymExpr *rhs, QualType T) {
+ const SymExpr *rhs, QualType type) {
assert(SymMgr.getType(lhs) == SymMgr.getType(rhs));
- assert(!Loc::isLocType(T));
- return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, T));
+ assert(!Loc::isLocType(type));
+ return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, type));
}
-SVal SValBuilder::convertToArrayIndex(SVal V) {
- if (V.isUnknownOrUndef())
- return V;
+SVal SValBuilder::convertToArrayIndex(SVal val) {
+ if (val.isUnknownOrUndef())
+ return val;
// Common case: we have an appropriately sized integer.
- if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&V)) {
+ if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&val)) {
const llvm::APSInt& I = CI->getValue();
if (I.getBitWidth() == ArrayIndexWidth && I.isSigned())
- return V;
+ return val;
}
- return evalCastNL(cast<NonLoc>(V), ArrayIndexTy);
+ return evalCastFromNonLoc(cast<NonLoc>(val), ArrayIndexTy);
}
DefinedOrUnknownSVal
-SValBuilder::getRegionValueSymbolVal(const TypedRegion* R) {
- QualType T = R->getValueType();
+SValBuilder::getRegionValueSymbolVal(const TypedRegion* region) {
+ QualType T = region->getValueType();
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
- SymbolRef sym = SymMgr.getRegionValueSymbol(R);
+ SymbolRef sym = SymMgr.getRegionValueSymbol(region);
if (Loc::isLocType(T))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -84,15 +84,15 @@ SValBuilder::getRegionValueSymbolVal(const TypedRegion* R) {
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag,
- const Expr *E,
- unsigned Count) {
- QualType T = E->getType();
+DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ unsigned count) {
+ QualType T = expr->getType();
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(E, Count, SymbolTag);
+ SymbolRef sym = SymMgr.getConjuredSymbol(expr, count, symbolTag);
if (Loc::isLocType(T))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -100,31 +100,32 @@ DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag,
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag,
- const Expr *E,
- QualType T,
- unsigned Count) {
+DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ QualType type,
+ unsigned count) {
- if (!SymbolManager::canSymbolicate(T))
+ if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count, SymbolTag);
+ SymbolRef sym = SymMgr.getConjuredSymbol(expr, type, count, symbolTag);
- if (Loc::isLocType(T))
+ if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
return nonloc::SymbolVal(sym);
}
-DefinedSVal SValBuilder::getMetadataSymbolVal(const void *SymbolTag,
- const MemRegion *MR,
- const Expr *E, QualType T,
- unsigned Count) {
- assert(SymbolManager::canSymbolicate(T) && "Invalid metadata symbol type");
+DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag,
+ const MemRegion *region,
+ const Expr *expr, QualType type,
+ unsigned count) {
+ assert(SymbolManager::canSymbolicate(type) && "Invalid metadata symbol type");
- SymbolRef sym = SymMgr.getMetadataSymbol(MR, E, T, Count, SymbolTag);
+ SymbolRef sym =
+ SymMgr.getMetadataSymbol(region, expr, type, count, symbolTag);
- if (Loc::isLocType(T))
+ if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
return nonloc::SymbolVal(sym);
@@ -132,13 +133,13 @@ DefinedSVal SValBuilder::getMetadataSymbolVal(const void *SymbolTag,
DefinedOrUnknownSVal
SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
- const TypedRegion *R) {
- QualType T = R->getValueType();
+ const TypedRegion *region) {
+ QualType T = region->getValueType();
if (!SymbolManager::canSymbolicate(T))
return UnknownVal();
- SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, R);
+ SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, region);
if (Loc::isLocType(T))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -146,53 +147,53 @@ SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
return nonloc::SymbolVal(sym);
}
-DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl* FD) {
- return loc::MemRegionVal(MemMgr.getFunctionTextRegion(FD));
+DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl* func) {
+ return loc::MemRegionVal(MemMgr.getFunctionTextRegion(func));
}
-DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *D,
- CanQualType locTy,
- const LocationContext *LC) {
+DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
+ CanQualType locTy,
+ const LocationContext *locContext) {
const BlockTextRegion *BC =
- MemMgr.getBlockTextRegion(D, locTy, LC->getAnalysisContext());
- const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
+ MemMgr.getBlockTextRegion(block, locTy, locContext->getAnalysisContext());
+ const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext);
return loc::MemRegionVal(BD);
}
//===----------------------------------------------------------------------===//
-SVal SValBuilder::evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
- SVal L, SVal R, QualType T) {
+SVal SValBuilder::evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ SVal lhs, SVal rhs, QualType type) {
- if (L.isUndef() || R.isUndef())
+ if (lhs.isUndef() || rhs.isUndef())
return UndefinedVal();
- if (L.isUnknown() || R.isUnknown())
+ if (lhs.isUnknown() || rhs.isUnknown())
return UnknownVal();
- if (isa<Loc>(L)) {
- if (isa<Loc>(R))
- return evalBinOpLL(ST, Op, cast<Loc>(L), cast<Loc>(R), T);
+ if (isa<Loc>(lhs)) {
+ if (isa<Loc>(rhs))
+ return evalBinOpLL(state, op, cast<Loc>(lhs), cast<Loc>(rhs), type);
- return evalBinOpLN(ST, Op, cast<Loc>(L), cast<NonLoc>(R), T);
+ return evalBinOpLN(state, op, cast<Loc>(lhs), cast<NonLoc>(rhs), type);
}
- if (isa<Loc>(R)) {
+ if (isa<Loc>(rhs)) {
// Support pointer arithmetic where the addend is on the left
// and the pointer on the right.
- assert(Op == BO_Add);
+ assert(op == BO_Add);
// Commute the operands.
- return evalBinOpLN(ST, Op, cast<Loc>(R), cast<NonLoc>(L), T);
+ return evalBinOpLN(state, op, cast<Loc>(rhs), cast<NonLoc>(lhs), type);
}
- return evalBinOpNN(ST, Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
+ return evalBinOpNN(state, op, cast<NonLoc>(lhs), cast<NonLoc>(rhs), type);
}
-DefinedOrUnknownSVal SValBuilder::evalEQ(const GRState *ST,
- DefinedOrUnknownSVal L,
- DefinedOrUnknownSVal R) {
- return cast<DefinedOrUnknownSVal>(evalBinOp(ST, BO_EQ, L, R,
+DefinedOrUnknownSVal SValBuilder::evalEQ(const GRState *state,
+ DefinedOrUnknownSVal lhs,
+ DefinedOrUnknownSVal rhs) {
+ return cast<DefinedOrUnknownSVal>(evalBinOp(state, BO_EQ, lhs, rhs,
Context.IntTy));
}
@@ -213,11 +214,11 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// Check for casts from integers to integers.
if (castTy->isIntegerType() && originalTy->isIntegerType())
- return evalCastNL(cast<NonLoc>(val), castTy);
+ return evalCastFromNonLoc(cast<NonLoc>(val), castTy);
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::isLocType(originalTy))
- return evalCastL(cast<Loc>(val), castTy);
+ return evalCastFromLoc(cast<Loc>(val), castTy);
// Check for casts from integers to pointers.
if (Loc::isLocType(castTy) && originalTy->isIntegerType()) {
@@ -256,7 +257,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// need the original decayed type.
// QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
// QualType pointerTy = C.getPointerType(elemTy);
- return evalCastL(cast<Loc>(val), castTy);
+ return evalCastFromLoc(cast<Loc>(val), castTy);
}
// Check for casts from a region to a specific type.
@@ -305,6 +306,6 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
DispatchCast:
// All other cases.
- return isa<Loc>(val) ? evalCastL(cast<Loc>(val), castTy)
- : evalCastNL(cast<NonLoc>(val), castTy);
+ return isa<Loc>(val) ? evalCastFromLoc(cast<Loc>(val), castTy)
+ : evalCastFromNonLoc(cast<NonLoc>(val), castTy);
}
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index e0b61ab58009..1ee694ef8a13 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -15,7 +15,6 @@
#include "SimpleConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
namespace clang {
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 9a46bd6d69a0..5d802511510a 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -20,8 +20,8 @@ using namespace ento;
namespace {
class SimpleSValBuilder : public SValBuilder {
protected:
- virtual SVal evalCastNL(NonLoc val, QualType castTy);
- virtual SVal evalCastL(Loc val, QualType castTy);
+ virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy);
+ virtual SVal evalCastFromLoc(Loc val, QualType castTy);
public:
SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
@@ -57,7 +57,7 @@ SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
-SVal SimpleSValBuilder::evalCastNL(NonLoc val, QualType castTy) {
+SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
bool isLocType = Loc::isLocType(castTy);
@@ -106,7 +106,7 @@ SVal SimpleSValBuilder::evalCastNL(NonLoc val, QualType castTy) {
return makeIntVal(i);
}
-SVal SimpleSValBuilder::evalCastL(Loc val, QualType castTy) {
+SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
// Casts from pointers -> pointers, just return the lval.
//
@@ -255,11 +255,12 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
}
// Idempotent ops (like a*1) can still change the type of an expression.
- // Wrap the LHS up in a NonLoc again and let evalCastNL do the dirty work.
+ // Wrap the LHS up in a NonLoc again and let evalCastFromNonLoc do the
+ // dirty work.
if (isIdempotent) {
if (SymbolRef LHSSym = dyn_cast<SymbolData>(LHS))
- return evalCastNL(nonloc::SymbolVal(LHSSym), resultTy);
- return evalCastNL(nonloc::SymExprVal(LHS), resultTy);
+ return evalCastFromNonLoc(nonloc::SymbolVal(LHSSym), resultTy);
+ return evalCastFromNonLoc(nonloc::SymExprVal(LHS), resultTy);
}
// If we reach this point, the expression cannot be simplified.
@@ -289,7 +290,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
return makeIntVal(0, resultTy);
case BO_Or:
case BO_And:
- return evalCastNL(lhs, resultTy);
+ return evalCastFromNonLoc(lhs, resultTy);
}
while (1) {
@@ -552,7 +553,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
default:
break;
case BO_Sub:
- return evalCastL(lhs, resultTy);
+ return evalCastFromLoc(lhs, resultTy);
case BO_EQ:
case BO_LE:
case BO_LT:
@@ -588,7 +589,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
SVal ResultVal = cast<loc::ConcreteInt>(lhs).evalBinOp(BasicVals, op,
*rInt);
if (Loc *Result = dyn_cast<Loc>(&ResultVal))
- return evalCastL(*Result, resultTy);
+ return evalCastFromLoc(*Result, resultTy);
else
return UnknownVal();
}
@@ -633,7 +634,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
default:
break;
case BO_Sub:
- return evalCastL(lhs, resultTy);
+ return evalCastFromLoc(lhs, resultTy);
case BO_EQ:
case BO_LT:
case BO_LE:
@@ -698,7 +699,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
NonLoc *LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
if (!LeftIndex)
return UnknownVal();
- LeftIndexVal = evalCastNL(*LeftIndex, resultTy);
+ LeftIndexVal = evalCastFromNonLoc(*LeftIndex, resultTy);
LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
if (!LeftIndex)
return UnknownVal();
@@ -708,7 +709,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
NonLoc *RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
if (!RightIndex)
return UnknownVal();
- RightIndexVal = evalCastNL(*RightIndex, resultTy);
+ RightIndexVal = evalCastFromNonLoc(*RightIndex, resultTy);
RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
if (!RightIndex)
return UnknownVal();
@@ -872,7 +873,8 @@ SVal SimpleSValBuilder::evalBinOpLN(const GRState *state,
QualType elementType;
if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) {
- index = evalBinOpNN(state, BO_Add, elemReg->getIndex(), rhs,
+ assert(op == BO_Add || op == BO_Sub);
+ index = evalBinOpNN(state, op, elemReg->getIndex(), rhs,
getArrayIndexType());
superR = elemReg->getSuperRegion();
elementType = elemReg->getElementType();
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 722517097c73..b936738009ec 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -230,9 +230,9 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
}
if (const Loc *L = dyn_cast<Loc>(&V))
- return svalBuilder.evalCastL(*L, castTy);
+ return svalBuilder.evalCastFromLoc(*L, castTy);
else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
- return svalBuilder.evalCastNL(*NL, castTy);
+ return svalBuilder.evalCastFromNonLoc(*NL, castTy);
return V;
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index e3e7ee957a6f..fe6e1fd6bbd2 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -17,8 +17,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -30,12 +28,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h"
-// FIXME: Restructure checker registration.
-#include "../Checkers/ClangSACheckers.h"
-#include "../Checkers/ExperimentalChecks.h"
-#include "../Checkers/InternalChecks.h"
-#include "../Checkers/BasicObjCFoundationChecks.h"
-
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/AnalyzerOptions.h"
@@ -70,20 +62,6 @@ namespace {
class AnalysisConsumer : public ASTConsumer {
public:
- typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
- typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
- TranslationUnitDecl &TU);
-
-private:
- typedef std::vector<CodeAction> Actions;
- typedef std::vector<TUAction> TUActions;
-
- Actions FunctionActions;
- Actions ObjCMethodActions;
- Actions ObjCImplementationActions;
- Actions CXXMethodActions;
-
-public:
ASTContext* Ctx;
const Preprocessor &PP;
const std::string OutDir;
@@ -163,16 +141,6 @@ public:
}
}
- void addCodeAction(CodeAction action) {
- FunctionActions.push_back(action);
- ObjCMethodActions.push_back(action);
- CXXMethodActions.push_back(action);
- }
-
- void addObjCImplementationAction(CodeAction action) {
- ObjCImplementationActions.push_back(action);
- }
-
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(),
@@ -194,7 +162,7 @@ public:
virtual void HandleTranslationUnit(ASTContext &C);
void HandleDeclContext(ASTContext &C, DeclContext *dc);
- void HandleCode(Decl *D, Actions& actions);
+ void HandleCode(Decl *D);
};
} // end anonymous namespace
@@ -228,23 +196,25 @@ void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
break;
DisplayFunction(FD);
- HandleCode(FD, FunctionActions);
+ HandleCode(FD);
}
break;
}
case Decl::ObjCImplementation: {
ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
- HandleCode(ID, ObjCImplementationActions);
+ HandleCode(ID);
for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
ME = ID->meth_end(); MI != ME; ++MI) {
+ checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
+
if ((*MI)->isThisDeclarationADefinition()) {
if (!Opts.AnalyzeSpecificFunction.empty() &&
Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
break;
DisplayFunction(*MI);
- HandleCode(*MI, ObjCMethodActions);
+ HandleCode(*MI);
}
}
break;
@@ -279,9 +249,12 @@ static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
FindBlocks(DC, WL);
}
-void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) {
+static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D);
+
+void AnalysisConsumer::HandleCode(Decl *D) {
- // Don't run the actions if an error has occured with parsing the file.
+ // Don't run the actions if an error has occurred with parsing the file.
Diagnostic &Diags = PP.getDiagnostics();
if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;
@@ -306,27 +279,17 @@ void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) {
BugReporter BR(*Mgr);
for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
WI != WE; ++WI)
- if ((*WI)->hasBody())
+ if ((*WI)->hasBody()) {
checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
-
- for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
- for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
- WI != WE; ++WI)
- (*I)(*this, *Mgr, *WI);
+ if (checkerMgr->hasPathSensitiveCheckers())
+ ActionObjCMemChecker(*this, *Mgr, *WI);
+ }
}
//===----------------------------------------------------------------------===//
-// Analyses
+// Path-sensitive checking.
//===----------------------------------------------------------------------===//
-static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
- if (CFG* c = mgr.getCFG(D)) {
- CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
- }
-}
-
-
static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D,
TransferFuncs* tf) {
@@ -340,18 +303,6 @@ static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
return;
ExprEngine Eng(mgr, TF.take());
- RegisterNSErrorChecks(Eng.getBugReporter(), Eng, *D);
-
- if (C.Opts.EnableExperimentalChecks)
- RegisterExperimentalChecks(Eng);
-
- if (C.Opts.BufferOverflows)
- RegisterArrayBoundCheckerV2(Eng);
-
- // Enable AnalyzerStatsChecker if it was given as an argument
- if (C.Opts.AnalyzerStats)
- RegisterAnalyzerStatsChecker(Eng);
-
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
if (mgr.shouldVisualizeUbigraph()) {
@@ -414,16 +365,6 @@ ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
const AnalyzerOptions& Opts) {
llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
- for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
- switch (Opts.AnalysisList[i]) {
-#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
- case NAME:\
- C->add ## SCOPE ## Action(&Action ## NAME);\
- break;
-#include "clang/Frontend/Analyses.def"
- default: break;
- }
-
// Last, disable the effects of '-Werror' when using the AnalysisConsumer.
pp.getDiagnostics().setWarningsAsErrors(false);
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index 677e20cd9c0e..d7edc7e599df 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -43,6 +43,8 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
// FIXME: Load CheckerProviders from plugins.
+ checkerMgr->finishedCheckerRegistration();
+
for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) {
if (checkerOpts[i].isUnclaimed())
diags.Report(diag::warn_unkwown_analyzer_checker)
@@ -55,9 +57,6 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
void ento::printCheckerHelp(llvm::raw_ostream &OS) {
OS << "OVERVIEW: Clang Static Analyzer Checkers List\n";
OS << '\n';
- OS << "USAGE: -analyzer-checker <check1,check2,...>\n";
- OS << '\n';
- OS << "CHECKERS:\n";
llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
provider->printHelp(OS);
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
new file mode 100644
index 000000000000..f52cf6c8917f
--- /dev/null
+++ b/lib/Tooling/CMakeLists.txt
@@ -0,0 +1,6 @@
+SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST)
+
+add_clang_library(clangTooling
+ JsonCompileCommandLineDatabase.cpp
+ Tooling.cpp
+ )
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/lib/Tooling/JsonCompileCommandLineDatabase.cpp
new file mode 100644
index 000000000000..7f027cfbead4
--- /dev/null
+++ b/lib/Tooling/JsonCompileCommandLineDatabase.cpp
@@ -0,0 +1,214 @@
+//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements reading a compile command line database, as written
+// out for example by CMake.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JsonCompileCommandLineDatabase.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// A parser for JSON escaped strings of command line arguments with \-escaping
+// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)).
+class CommandLineArgumentParser {
+ public:
+ CommandLineArgumentParser(llvm::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;
+ if (Position == Input.end()) return false;
+ // Remove the JSON escaping first. This is done unconditionally.
+ if (*Position == '\\') ++Position;
+ return Position != Input.end();
+ }
+
+ const llvm::StringRef Input;
+ llvm::StringRef::iterator Position;
+ std::vector<std::string> CommandLine;
+};
+
+} // end namespace
+
+std::vector<std::string> UnescapeJsonCommandLine(
+ llvm::StringRef JsonEscapedCommandLine) {
+ CommandLineArgumentParser parser(JsonEscapedCommandLine);
+ return parser.Parse();
+}
+
+JsonCompileCommandLineParser::JsonCompileCommandLineParser(
+ const llvm::StringRef Input, CompileCommandHandler *CommandHandler)
+ : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {}
+
+bool JsonCompileCommandLineParser::Parse() {
+ NextNonWhitespace();
+ return ParseTranslationUnits();
+}
+
+std::string JsonCompileCommandLineParser::GetErrorMessage() const {
+ return ErrorMessage;
+}
+
+bool JsonCompileCommandLineParser::ParseTranslationUnits() {
+ if (!ConsumeOrError('[', "at start of compile command file")) return false;
+ if (!ParseTranslationUnit(/*First=*/true)) return false;
+ while (Consume(',')) {
+ if (!ParseTranslationUnit(/*First=*/false)) return false;
+ }
+ if (!ConsumeOrError(']', "at end of array")) return false;
+ if (CommandHandler != NULL) {
+ CommandHandler->EndTranslationUnits();
+ }
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) {
+ if (First) {
+ if (!Consume('{')) return true;
+ } else {
+ if (!ConsumeOrError('{', "at start of object")) return false;
+ }
+ if (!Consume('}')) {
+ if (!ParseObjectKeyValuePairs()) return false;
+ if (!ConsumeOrError('}', "at end of object")) return false;
+ }
+ if (CommandHandler != NULL) {
+ CommandHandler->EndTranslationUnit();
+ }
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() {
+ do {
+ llvm::StringRef Key;
+ if (!ParseString(Key)) return false;
+ if (!ConsumeOrError(':', "between name and value")) return false;
+ llvm::StringRef Value;
+ if (!ParseString(Value)) return false;
+ if (CommandHandler != NULL) {
+ CommandHandler->HandleKeyValue(Key, Value);
+ }
+ } while (Consume(','));
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) {
+ if (!ConsumeOrError('"', "at start of string")) return false;
+ llvm::StringRef::iterator First = Position;
+ llvm::StringRef::iterator Last = Position;
+ while (!Consume('"')) {
+ Consume('\\');
+ ++Position;
+ // We need to store Position, as Consume will change Last before leaving
+ // the loop.
+ Last = Position;
+ }
+ String = llvm::StringRef(First, Last - First);
+ return true;
+}
+
+bool JsonCompileCommandLineParser::Consume(char C) {
+ if (Position == Input.end()) return false;
+ if (*Position != C) return false;
+ NextNonWhitespace();
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ConsumeOrError(
+ char C, llvm::StringRef Message) {
+ if (!Consume(C)) {
+ SetExpectError(C, Message);
+ return false;
+ }
+ return true;
+}
+
+void JsonCompileCommandLineParser::SetExpectError(
+ char C, llvm::StringRef Message) {
+ ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) +
+ "' expected " + Message + ".").str();
+}
+
+void JsonCompileCommandLineParser::NextNonWhitespace() {
+ do {
+ ++Position;
+ } while (IsWhitespace());
+}
+
+bool JsonCompileCommandLineParser::IsWhitespace() {
+ if (Position == Input.end()) return false;
+ return (*Position == ' ' || *Position == '\t' ||
+ *Position == '\n' || *Position == '\r');
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.h b/lib/Tooling/JsonCompileCommandLineDatabase.h
new file mode 100644
index 000000000000..9e776d60010d
--- /dev/null
+++ b/lib/Tooling/JsonCompileCommandLineDatabase.h
@@ -0,0 +1,107 @@
+//===--- JsonCompileCommandLineDatabase - Simple JSON database --*- 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 reading a compile command line database, as written
+// out for example by CMake. It only supports the subset of the JSON standard
+// that is needed to parse the CMake output.
+// See http://www.json.org/ for the full standard.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
+#define LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
+
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// \brief Converts a JSON escaped command line to a vector of arguments.
+///
+/// \param JsonEscapedCommandLine The escaped command line as a string. This
+/// is assumed to be escaped as a JSON string (e.g. " and \ are escaped).
+/// In addition, any arguments containing spaces are assumed to be \-escaped
+///
+/// For example, the input (|| denoting non C-escaped strings):
+/// |./call a \"b \\\" c \\\\ \" d|
+/// would yield:
+/// [ |./call|, |a|, |b " c \ |, |d| ].
+std::vector<std::string> UnescapeJsonCommandLine(
+ llvm::StringRef JsonEscapedCommandLine);
+
+/// \brief Interface for users of the JsonCompileCommandLineParser.
+class CompileCommandHandler {
+ public:
+ virtual ~CompileCommandHandler() {}
+
+ /// \brief Called after all translation units are parsed.
+ virtual void EndTranslationUnits() {}
+
+ /// \brief Called at the end of a single translation unit.
+ virtual void EndTranslationUnit() {}
+
+ /// \brief Called for every (Key, Value) pair in a translation unit
+ /// description.
+ virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {}
+};
+
+/// \brief A JSON parser that supports the subset of JSON needed to parse
+/// JSON compile command line databases as written out by CMake.
+///
+/// The supported subset describes a list of compile command lines for
+/// each processed translation unit. The translation units are stored in a
+/// JSON array, where each translation unit is described by a JSON object
+/// containing (Key, Value) pairs for the working directory the compile command
+/// line was executed from, the main C/C++ input file of the translation unit
+/// and the actual compile command line, for example:
+/// [
+/// {
+/// "file":"/file.cpp",
+/// "directory":"/",
+/// "command":"/cc /file.cpp"
+/// }
+/// ]
+class JsonCompileCommandLineParser {
+ public:
+ /// \brief Create a parser on 'Input', calling 'CommandHandler' to handle the
+ /// parsed constructs. 'CommandHandler' may be NULL in order to just check
+ /// the validity of 'Input'.
+ JsonCompileCommandLineParser(const llvm::StringRef Input,
+ CompileCommandHandler *CommandHandler);
+
+ /// \brief Parses the specified input. Returns true if no parsing errors were
+ /// foudn.
+ bool Parse();
+
+ /// \brief Returns an error message if Parse() returned false previously.
+ std::string GetErrorMessage() const;
+
+ private:
+ bool ParseTranslationUnits();
+ bool ParseTranslationUnit(bool First);
+ bool ParseObjectKeyValuePairs();
+ bool ParseString(llvm::StringRef &String);
+ bool Consume(char C);
+ bool ConsumeOrError(char C, llvm::StringRef Message);
+ void NextNonWhitespace();
+ bool IsWhitespace();
+ void SetExpectError(char C, llvm::StringRef Message);
+
+ const llvm::StringRef Input;
+ llvm::StringRef::iterator Position;
+ std::string ErrorMessage;
+ CompileCommandHandler * const CommandHandler;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
diff --git a/lib/Tooling/Makefile b/lib/Tooling/Makefile
new file mode 100644
index 000000000000..501a00c3f4f4
--- /dev/null
+++ b/lib/Tooling/Makefile
@@ -0,0 +1,15 @@
+##===- clang/lib/Tooling/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangTooling
+
+include $(CLANG_LEVEL)/Makefile
+
+
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
new file mode 100644
index 000000000000..c1714a9be715
--- /dev/null
+++ b/lib/Tooling/Tooling.cpp
@@ -0,0 +1,322 @@
+//===--- Tooling.cpp - Running clang standalone tools --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements functions to run clang tools standalone instead
+// of running them as a plugin.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "JsonCompileCommandLineDatabase.h"
+#include <map>
+#include <cstdio>
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// Checks that the input conforms to the argv[] convention as in
+// main(). Namely:
+// - it must contain at least a program path,
+// - argv[0], ..., and argv[argc - 1] mustn't be NULL, and
+// - argv[argc] must be NULL.
+void ValidateArgv(int argc, char* argv[]) {
+ if (argc < 1) {
+ fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc);
+ abort();
+ }
+
+ for (int i = 0; i < argc; ++i) {
+ if (argv[i] == NULL) {
+ fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i);
+ abort();
+ }
+ }
+
+ if (argv[argc] != NULL) {
+ fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n");
+ abort();
+ }
+}
+
+} // end namespace
+
+// FIXME: This file contains structural duplication with other parts of the
+// code that sets up a compiler to run tools on it, and we should refactor
+// it to be based on the same framework.
+
+static clang::Diagnostic* NewTextDiagnostics() {
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
+ new clang::DiagnosticIDs());
+ clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(
+ llvm::errs(), clang::DiagnosticOptions());
+ return new clang::Diagnostic(DiagIDs, DiagClient);
+}
+
+// Exists solely for the purpose of lookup of the main executable.
+static int StaticSymbol;
+
+/// \brief Builds a clang driver initialized for running clang tools.
+static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics,
+ const char* BinaryName) {
+ // This just needs to be some symbol in the binary.
+ void* const SymbolAddr = &StaticSymbol;
+ const llvm::sys::Path ExePath =
+ llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr);
+
+ const std::string DefaultOutputName = "a.out";
+ clang::driver::Driver* CompilerDriver = new clang::driver::Driver(
+ ExePath.str(), llvm::sys::getHostTriple(),
+ DefaultOutputName, false, false, *Diagnostics);
+ CompilerDriver->setTitle("clang_based_tool");
+ return CompilerDriver;
+}
+
+/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
+/// Returns NULL on error.
+static const clang::driver::ArgStringList* GetCC1Arguments(
+ clang::Diagnostic* Diagnostics, clang::driver::Compilation* Compilation) {
+ // We expect to get back exactly one Command job, if we didn't something
+ // failed. Extract that job from the Compilation.
+ const clang::driver::JobList &Jobs = Compilation->getJobs();
+ if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
+ llvm::SmallString<256> error_msg;
+ llvm::raw_svector_ostream error_stream(error_msg);
+ Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
+ Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
+ << error_stream.str();
+ return NULL;
+ }
+
+ // The one job we find should be to invoke clang again.
+ const clang::driver::Command *Cmd =
+ cast<clang::driver::Command>(*Jobs.begin());
+ if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+ Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
+ return NULL;
+ }
+
+ return &Cmd->getArguments();
+}
+
+/// \brief Returns a clang build invocation initialized from the CC1 flags.
+static clang::CompilerInvocation* NewInvocation(
+ clang::Diagnostic* Diagnostics,
+ const clang::driver::ArgStringList& CC1Args) {
+ clang::CompilerInvocation* Invocation = new clang::CompilerInvocation;
+ clang::CompilerInvocation::CreateFromArgs(
+ *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(),
+ *Diagnostics);
+ Invocation->getFrontendOpts().DisableFree = false;
+ return Invocation;
+}
+
+/// \brief Runs the specified clang tool action and returns whether it executed
+/// successfully.
+static bool RunInvocation(const char* BinaryName,
+ clang::driver::Compilation* Compilation,
+ clang::CompilerInvocation* Invocation,
+ const clang::driver::ArgStringList& CC1Args,
+ clang::FrontendAction* ToolAction) {
+ llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction);
+ // Show the invocation, with -v.
+ if (Invocation->getHeaderSearchOpts().Verbose) {
+ llvm::errs() << "clang Invocation:\n";
+ Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true);
+ llvm::errs() << "\n";
+ }
+
+ // Create a compiler instance to handle the actual work.
+ clang::CompilerInstance Compiler;
+ Compiler.setInvocation(Invocation);
+
+ // Create the compilers actual diagnostics engine.
+ Compiler.createDiagnostics(CC1Args.size(),
+ const_cast<char**>(CC1Args.data()));
+ if (!Compiler.hasDiagnostics())
+ return false;
+
+ // Infer the builtin include path if unspecified.
+ if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes &&
+ Compiler.getHeaderSearchOpts().ResourceDir.empty()) {
+ // This just needs to be some symbol in the binary.
+ void* const SymbolAddr = &StaticSymbol;
+ Compiler.getHeaderSearchOpts().ResourceDir =
+ clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr);
+ }
+
+ const bool Success = Compiler.ExecuteAction(*ToolAction);
+ return Success;
+}
+
+/// \brief Converts a string vector representing a Command line into a C
+/// string vector representing the Argv (including the trailing NULL).
+std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) {
+ std::vector<char*> Result(Command->size() + 1);
+ for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) {
+ Result[I] = const_cast<char*>((*Command)[I].c_str());
+ }
+ Result[Command->size()] = NULL;
+ return Result;
+}
+
+bool RunToolWithFlags(
+ clang::FrontendAction* ToolAction, int Args, char* Argv[]) {
+ ValidateArgv(Args, Argv);
+ const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
+ const llvm::OwningPtr<clang::driver::Driver> Driver(
+ NewDriver(Diagnostics.get(), Argv[0]));
+ const llvm::OwningPtr<clang::driver::Compilation> Compilation(
+ Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args)));
+ const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
+ Diagnostics.get(), Compilation.get());
+ if (CC1Args == NULL) {
+ return false;
+ }
+ llvm::OwningPtr<clang::CompilerInvocation> Invocation(
+ NewInvocation(Diagnostics.get(), *CC1Args));
+ return RunInvocation(Argv[0], Compilation.get(), Invocation.take(),
+ *CC1Args, ToolAction);
+}
+
+/// \brief Runs 'ToolAction' on the code specified by 'FileContents'.
+///
+/// \param FileContents A mapping from file name to source code. For each
+/// entry a virtual file mapping will be created when running the tool.
+bool RunToolWithFlagsOnCode(
+ const std::vector<std::string>& CommandLine,
+ const std::map<std::string, std::string>& FileContents,
+ clang::FrontendAction* ToolAction) {
+ const std::vector<char*> Argv = CommandLineToArgv(&CommandLine);
+ const char* const BinaryName = Argv[0];
+
+ const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
+ const llvm::OwningPtr<clang::driver::Driver> Driver(
+ NewDriver(Diagnostics.get(), BinaryName));
+
+ // Since the Input is only virtual, don't check whether it exists.
+ Driver->setCheckInputsExist(false);
+
+ const llvm::OwningPtr<clang::driver::Compilation> Compilation(
+ Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0],
+ Argv.size() - 1)));
+ const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
+ Diagnostics.get(), Compilation.get());
+ if (CC1Args == NULL) {
+ return false;
+ }
+ llvm::OwningPtr<clang::CompilerInvocation> Invocation(
+ NewInvocation(Diagnostics.get(), *CC1Args));
+
+ for (std::map<std::string, std::string>::const_iterator
+ It = FileContents.begin(), End = FileContents.end();
+ It != End; ++It) {
+ // Inject the code as the given file name into the preprocessor options.
+ const llvm::MemoryBuffer* Input =
+ llvm::MemoryBuffer::getMemBuffer(It->second.c_str());
+ Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input);
+ }
+
+ return RunInvocation(BinaryName, Compilation.get(),
+ Invocation.take(), *CC1Args, ToolAction);
+}
+
+bool RunSyntaxOnlyToolOnCode(
+ clang::FrontendAction *ToolAction, llvm::StringRef Code) {
+ const char* const FileName = "input.cc";
+ const char* const CommandLine[] = {
+ "clang-tool", "-fsyntax-only", FileName
+ };
+ std::map<std::string, std::string> FileContents;
+ FileContents[FileName] = Code;
+ return RunToolWithFlagsOnCode(
+ std::vector<std::string>(
+ CommandLine,
+ CommandLine + sizeof(CommandLine)/sizeof(CommandLine[0])),
+ FileContents, ToolAction);
+}
+
+namespace {
+
+// A CompileCommandHandler implementation that finds compile commands for a
+// specific input file.
+//
+// FIXME: Implement early exit when JsonCompileCommandLineParser supports it.
+class FindHandler : public clang::tooling::CompileCommandHandler {
+ public:
+ explicit FindHandler(llvm::StringRef File)
+ : FileToMatch(File), FoundMatchingCommand(false) {}
+
+ virtual void EndTranslationUnits() {
+ if (!FoundMatchingCommand && ErrorMessage.empty()) {
+ ErrorMessage = "ERROR: No matching command found.";
+ }
+ }
+
+ virtual void EndTranslationUnit() {
+ if (File == FileToMatch) {
+ FoundMatchingCommand = true;
+ MatchingCommand.Directory = Directory;
+ MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command);
+ }
+ }
+
+ virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {
+ if (Key == "directory") { Directory = Value; }
+ else if (Key == "file") { File = Value; }
+ else if (Key == "command") { Command = Value; }
+ else {
+ ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str();
+ }
+ }
+
+ const llvm::StringRef FileToMatch;
+ bool FoundMatchingCommand;
+ CompileCommand MatchingCommand;
+ std::string ErrorMessage;
+
+ llvm::StringRef Directory;
+ llvm::StringRef File;
+ llvm::StringRef Command;
+};
+
+} // end namespace
+
+CompileCommand FindCompileArgsInJsonDatabase(
+ llvm::StringRef FileName, llvm::StringRef JsonDatabase,
+ std::string &ErrorMessage) {
+ FindHandler find_handler(FileName);
+ JsonCompileCommandLineParser parser(JsonDatabase, &find_handler);
+ if (!parser.Parse()) {
+ ErrorMessage = parser.GetErrorMessage();
+ return CompileCommand();
+ }
+ return find_handler.MatchingCommand;
+}
+
+} // end namespace tooling
+} // end namespace clang
+
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index 68ee266ecae9..e53d805cbd64 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -2,7 +2,6 @@
set(known_subdirs
"compiler-rt"
- "libcxx"
)
foreach (dir ${known_subdirs})
diff --git a/runtime/Makefile b/runtime/Makefile
index 375f312debd1..784eb66fc540 100644
--- a/runtime/Makefile
+++ b/runtime/Makefile
@@ -1,114 +1,22 @@
-##===- clang/runtime/Makefile ------------------------------*- Makefile -*-===##
-#
+##===- runtime/Makefile ------------------------------------*- Makefile -*-===##
+#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-#
-# This file defines support for building the Clang runtime libraries (which are
-# implemented by compiler-rt) and placing them in the proper locations in the
-# Clang resources directory (i.e., where the driver expects them).
-#
+#
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-include $(CLANG_LEVEL)/Makefile
+include $(CLANG_LEVEL)/../../Makefile.config
-CLANG_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \
- $(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc))
+ifndef NO_RUNTIME_LIBS
-ResourceDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/lib/clang/$(CLANG_VERSION)
-PROJ_resources := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)
-
-ResourceLibDir := $(ResourceDir)/lib
-PROJ_resources_lib := $(PROJ_resources)/lib
-
-# Expect compiler-rt to be in llvm/projects/compiler-rt
-COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
-
-# Additional flags to pass to Clang.
-CLANG_CCFLAGS := -no-integrated-as
-
-ifneq ($(CLANG_NO_RUNTIME),1)
-ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
-
-# Select the compiler-rt configuration to use, and install directory.
-#
-# FIXME: Eventually, we want some kind of configure support for this. We want to
-# build/install runtime libraries for as many targets as clang was configured to
-# support.
-RuntimeDirs :=
-ifeq ($(OS),Darwin)
-RuntimeDirs += darwin
-RuntimeLibrary.darwin.Configs = eprintf 10.4 armv6 cc_kext
+PARALLEL_DIRS := compiler-rt
-# On Darwin, fake Clang into using the iOS assembler (since compiler-rt wants to
-# build ARM bits).
-ifeq ($(OS),Darwin)
-CLANG_CCFLAGS += -ccc-install-dir \
- /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/
endif
-endif
-
-# Rule to build the compiler-rt libraries we need.
-#
-# We build all the libraries in a single shot to avoid recursive make as much as
-# possible.
-BuildRuntimeLibraries:
- $(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
- ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
- ProjObjRoot=$(PROJ_OBJ_DIR) \
- CC="$(ToolDir)/clang $(CLANG_CCFLAGS)" \
- $(RuntimeDirs:%=clang_%)
-.PHONY: BuildRuntimeLibraries
-CleanRuntimeLibraries:
- $(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
- ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
- ProjObjRoot=$(PROJ_OBJ_DIR) \
- clean
-.PHONY: CleanRuntimeLibraries
-
-$(PROJ_resources_lib):
- $(Verb) $(MKDIR) $@
-
-# Expand rules for copying/installing each individual library. We can't use
-# implicit rules here because we need to match against multiple things.
-define RuntimeLibraryTemplate
-$(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a: BuildRuntimeLibraries
- @true
-.PRECIOUS: $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a
-
-# Rule to copy the libraries to their resource directory location.
-$(ResourceLibDir)/$1/libclang_rt.%.a: \
- $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a \
- $(ResourceLibDir)/$1/.dir
- $(Echo) Copying runtime library $1/$$* to build dir
- $(Verb) cp $(PROJ_OBJ_DIR)/clang_$1/$$*/libcompiler_rt.a $$@
-RuntimeLibrary.$1: \
- $(RuntimeLibrary.$1.Configs:%=$(ResourceLibDir)/$1/libclang_rt.%.a)
-.PHONY: RuntimeLibrary.$1
-$(PROJ_resources_lib)/$1: $(PROJ_resources_lib)
- $(Verb) $(MKDIR) $$@
-
-$(PROJ_resources_lib)/$1/libclang_rt.%.a: \
- $(ResourceLibDir)/$1/libclang_rt.%.a | $(PROJ_resources_lib)/$1
- $(Echo) Installing compiler runtime library: $1/$$*
- $(Verb) $(DataInstall) $$< $(PROJ_resources_lib)/$1
-
-# Rule to install runtime libraries.
-RuntimeLibraryInstall.$1: \
- $(RuntimeLibrary.$1.Configs:%=$(PROJ_resources_lib)/$1/libclang_rt.%.a)
-.PHONY: RuntimeLibraryInstall.$1
-endef
-$(foreach lib,$(RuntimeDirs), $(eval $(call RuntimeLibraryTemplate,$(lib))))
+include $(CLANG_LEVEL)/Makefile
-# Hook into the standard Makefile rules.
-all-local:: $(RuntimeDirs:%=RuntimeLibrary.%)
-install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%)
-clean-local:: CleanRuntimeLibraries
+install::
-endif
-endif
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
new file mode 100644
index 000000000000..dcdd4f5ec03f
--- /dev/null
+++ b/runtime/compiler-rt/Makefile
@@ -0,0 +1,114 @@
+##===- clang/runtime/Makefile ------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This file defines support for building the Clang runtime libraries (which are
+# implemented by compiler-rt) and placing them in the proper locations in the
+# Clang resources directory (i.e., where the driver expects them).
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+include $(CLANG_LEVEL)/Makefile
+
+CLANG_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \
+ $(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc))
+
+ResourceDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/lib/clang/$(CLANG_VERSION)
+PROJ_resources := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)
+
+ResourceLibDir := $(ResourceDir)/lib
+PROJ_resources_lib := $(PROJ_resources)/lib
+
+# Expect compiler-rt to be in llvm/projects/compiler-rt
+COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
+
+# Additional flags to pass to Clang.
+CLANG_CCFLAGS := -no-integrated-as
+
+ifneq ($(CLANG_NO_RUNTIME),1)
+ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
+
+# Select the compiler-rt configuration to use, and install directory.
+#
+# FIXME: Eventually, we want some kind of configure support for this. We want to
+# build/install runtime libraries for as many targets as clang was configured to
+# support.
+RuntimeDirs :=
+ifeq ($(OS),Darwin)
+RuntimeDirs += darwin
+RuntimeLibrary.darwin.Configs = eprintf 10.4 ios cc_kext
+
+# On Darwin, fake Clang into using the iOS assembler (since compiler-rt wants to
+# build ARM bits).
+ifeq ($(OS),Darwin)
+CLANG_CCFLAGS += -ccc-install-dir \
+ /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/
+endif
+endif
+
+# Rule to build the compiler-rt libraries we need.
+#
+# We build all the libraries in a single shot to avoid recursive make as much as
+# possible.
+BuildRuntimeLibraries:
+ $(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
+ ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
+ ProjObjRoot=$(PROJ_OBJ_DIR) \
+ CC="$(ToolDir)/clang $(CLANG_CCFLAGS)" \
+ $(RuntimeDirs:%=clang_%)
+.PHONY: BuildRuntimeLibraries
+CleanRuntimeLibraries:
+ $(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
+ ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
+ ProjObjRoot=$(PROJ_OBJ_DIR) \
+ clean
+.PHONY: CleanRuntimeLibraries
+
+$(PROJ_resources_lib):
+ $(Verb) $(MKDIR) $@
+
+# Expand rules for copying/installing each individual library. We can't use
+# implicit rules here because we need to match against multiple things.
+define RuntimeLibraryTemplate
+$(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a: BuildRuntimeLibraries
+ @true
+.PRECIOUS: $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a
+
+# Rule to copy the libraries to their resource directory location.
+$(ResourceLibDir)/$1/libclang_rt.%.a: \
+ $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a \
+ $(ResourceLibDir)/$1/.dir
+ $(Echo) Copying runtime library $1/$$* to build dir
+ $(Verb) cp $(PROJ_OBJ_DIR)/clang_$1/$$*/libcompiler_rt.a $$@
+RuntimeLibrary.$1: \
+ $(RuntimeLibrary.$1.Configs:%=$(ResourceLibDir)/$1/libclang_rt.%.a)
+.PHONY: RuntimeLibrary.$1
+
+$(PROJ_resources_lib)/$1: $(PROJ_resources_lib)
+ $(Verb) $(MKDIR) $$@
+
+$(PROJ_resources_lib)/$1/libclang_rt.%.a: \
+ $(ResourceLibDir)/$1/libclang_rt.%.a | $(PROJ_resources_lib)/$1
+ $(Echo) Installing compiler runtime library: $1/$$*
+ $(Verb) $(DataInstall) $$< $(PROJ_resources_lib)/$1
+
+# Rule to install runtime libraries.
+RuntimeLibraryInstall.$1: \
+ $(RuntimeLibrary.$1.Configs:%=$(PROJ_resources_lib)/$1/libclang_rt.%.a)
+.PHONY: RuntimeLibraryInstall.$1
+endef
+$(foreach lib,$(RuntimeDirs), $(eval $(call RuntimeLibraryTemplate,$(lib))))
+
+# Hook into the standard Makefile rules.
+all-local:: $(RuntimeDirs:%=RuntimeLibrary.%)
+install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%)
+clean-local:: CleanRuntimeLibraries
+
+endif
+endif
diff --git a/runtime/libcxx/Makefile b/runtime/libcxx/Makefile
deleted file mode 100644
index 10d4e9bb8455..000000000000
--- a/runtime/libcxx/Makefile
+++ /dev/null
@@ -1,63 +0,0 @@
-##===- clang/runtime/libcxx/Makefile -----------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-#
-# This file defines support for building the "libc++" C++ standard library as
-# part of a Clang compiler build.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL := ../..
-LEVEL := $(CLANG_LEVEL)/../..
-LIBRARYNAME = c++
-
-LINK_LIBS_IN_SHARED = 1
-SHARED_LIBRARY = 1
-
-# Include LLVM common makefile.
-include $(LEVEL)/Makefile.config
-
-# Expect libcxx to be in llvm/projects/libcxx
-LIBCXX_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/libcxx
-
-# Override the source root to point at the libcxx sources.
-PROJ_MAKEFILE := $(PROJ_SRC_DIR)/Makefile
-PROJ_SRC_DIR := $(LIBCXX_SRC_ROOT)/src
-CPP.Flags := -nostdinc++ -I$(LIBCXX_SRC_ROOT)/include
-CXX.Flags := -std=c++0x
-
-# Include LLVM makefile rules.
-include $(LLVM_SRC_ROOT)/Makefile.rules
-
-# Force building with the just built Clang.
-#
-# FIXME: Do we really want to do this? It is uber slow.
-# CXX := $(ToolDir)/clang
-
-ifeq ($(HOST_OS),Darwin)
- LLVMLibsOptions += -Wl,-compatibility_version,1
-
- # Don't link with default libraries.
- LLVMLibsOptions += -nodefaultlibs
-
- # Reexport libc++abi.
- LLVMLibsOptions += -Wl,-reexport_library,/usr/lib/libc++abi.dylib
-
- # Set dylib internal version number to submission number.
- ifdef LLVM_SUBMIT_VERSION
- LLVMLibsOptions += -Wl,-current_version \
- -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION)
- endif
-
- # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line
- DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
- ifneq ($(DARWIN_VERS),8)
- LLVMLibsOptions += -Wl,-install_name \
- -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
- endif
-endif
diff --git a/test/ASTMerge/var.c b/test/ASTMerge/var.c
index 7f23b9f5d26d..e1dde6abd2ac 100644
--- a/test/ASTMerge/var.c
+++ b/test/ASTMerge/var.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/var1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/var2.c
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s
// CHECK: var2.c:2:9: error: external variable 'x1' declared with incompatible types in different translation units ('double *' vs. 'float **')
// CHECK: var1.c:2:9: note: declared here with type 'float **'
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index a00895586e2e..bd1a4b7967ca 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc -disable-free %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify -fobjc-gc -disable-free %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c
index 4725f90f1a2f..dd57cd9cbfa1 100644
--- a/test/Analysis/CFNumber.c
+++ b/test/Analysis/CFNumber.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=macosx.CFNumber -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=macosx.CFNumber -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=macosx.CFNumber -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=macosx.CFNumber -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
typedef signed long CFIndex;
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/CFRetainRelease_NSAssertionHandler.m b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
index 7ece5c665904..ee52201e6285 100644
--- a/test/Analysis/CFRetainRelease_NSAssertionHandler.m
+++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=basic
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -verify %s -analyzer-constraints=range -analyzer-store=basic
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=region
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -verify %s -analyzer-constraints=range -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=basic -analyzer-store=basic
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=range -analyzer-store=basic
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=basic -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s -analyzer-constraints=range -analyzer-store=region
typedef struct objc_selector *SEL;
typedef signed char BOOL;
diff --git a/test/Analysis/CGColorSpace.c b/test/Analysis/CGColorSpace.c
index 9d554a98f636..ea458404c5dd 100644
--- a/test/Analysis/CGColorSpace.c
+++ b/test/Analysis/CGColorSpace.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify %s
typedef struct CGColorSpace *CGColorSpaceRef;
extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m
index d12ad4eb2e65..3bc7d8f748e1 100644
--- a/test/Analysis/CheckNSError.m
+++ b/test/Analysis/CheckNSError.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=range -verify %s
typedef signed char BOOL;
diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m
index 27fd340dd0b2..e7930d1223b7 100644
--- a/test/Analysis/MissingDealloc.m
+++ b/test/Analysis/MissingDealloc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=cocoa.experimental.Dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.experimental.Dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify
typedef signed char BOOL;
@protocol NSObject
- (BOOL)isEqual:(id)object;
diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m
index 3f356349ad8a..19b72d8f692f 100644
--- a/test/Analysis/NSPanel.m
+++ b/test/Analysis/NSPanel.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index 52664df231c8..6ff4bb1e554f 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,13 +1,13 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
// ==-- FIXME: -analyzer-store=basic fails on this file (false negatives). --==
-// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s &&
-// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
-// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
-// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=cocoa.NilArg -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
@@ -190,6 +190,13 @@ void f13(void) {
CFRelease(ref); // expected-warning{{Reference-counted object is used after it is released}}
}
+@interface MyString : NSString
+@end
+
+void f14(MyString *s) {
+ [s compare:0]; // expected-warning {{Argument to 'MyString' method 'compare:' cannot be nil.}}
+}
+
// Test regular use of -autorelease
@interface TestAutorelease
-(NSString*) getString;
diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m
index 76e265f1ebcb..404448574ea1 100644
--- a/test/Analysis/NSWindow.m
+++ b/test/Analysis/NSWindow.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-checker=core.DeadStores -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-checker=core.DeadStores -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-checker=core.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-checker=core.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-checker=deadcode.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
// These declarations were reduced using Delta-Debugging from Foundation.h
// on Mac OS X. The test cases are below.
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
index f3bfcf53190e..42952ed3a7cc 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
#include <stdarg.h>
diff --git a/test/Analysis/OSAtomic_mac.cpp b/test/Analysis/OSAtomic_mac.cpp
new file mode 100644
index 000000000000..8ad7b3c3da66
--- /dev/null
+++ b/test/Analysis/OSAtomic_mac.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,osx -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+
+// Test handling of OSAtomicCompareAndSwap when C++ inserts "no-op" casts and we
+// do a forced load and binding to the environment on an expression that would regularly
+// not have an environment binding. This previously triggered a crash (<rdar://problem/9339920>).
+// NOTE: It is critical that the function called is OSAtomicCompareAndSwapIntBarrier.
+bool OSAtomicCompareAndSwapIntBarrier( int __oldValue, int __newValue, volatile int *__theValue ) ;
+static int _rdar9339920_x = 0;
+int rdar9339920_aux();
+
+int rdar9339920_test() {
+ int rdar9339920_x = rdar9339920_aux();
+ if (rdar9339920_x != _rdar9339920_x) {
+ if (OSAtomicCompareAndSwapIntBarrier(_rdar9339920_x, rdar9339920_x, &_rdar9339920_x))
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m
index 9362692bd75e..103db486b1c2 100644
--- a/test/Analysis/ObjCProperties.m
+++ b/test/Analysis/ObjCProperties.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range %s -verify
// The point of this test cases is to exercise properties in the static
// analyzer
diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m
index 93dae14ea198..9778e41d9ced 100644
--- a/test/Analysis/ObjCRetSigs.m
+++ b/test/Analysis/ObjCRetSigs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=cocoa.MethodSigs -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify %s
int printf(const char *, ...);
diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m
index 89f36d27749c..b9e9d6b757de 100644
--- a/test/Analysis/PR2599.m
+++ b/test/Analysis/PR2599.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-constraints=basic -analyzer-store=basic -analyzer-check-objc-mem -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-constraints=range -analyzer-store=basic -analyzer-check-objc-mem -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-constraints=basic -analyzer-store=basic -analyzer-check-objc-mem -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-constraints=range -analyzer-store=region -analyzer-check-objc-mem -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=range -analyzer-store=basic -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=range -analyzer-store=region -fobjc-gc -verify %s
typedef const void * CFTypeRef;
typedef const struct __CFString * CFStringRef;
diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m
index c3b21f230807..c07150f0ce2a 100644
--- a/test/Analysis/PR2978.m
+++ b/test/Analysis/PR2978.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=cocoa.experimental.Dealloc %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=osx.cocoa.experimental.Dealloc %s -verify
// Tests for the checker which checks missing/extra ivar 'release' calls
// in dealloc.
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
index 83ae19f4ba8c..23f199311e47 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
//===----------------------------------------------------------------------===//
// Delta-debugging produced forward declarations.
diff --git a/test/Analysis/PR7218.c b/test/Analysis/PR7218.c
index 635e56f053ec..1775e057f4db 100644
--- a/test/Analysis/PR7218.c
+++ b/test/Analysis/PR7218.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
char PR7218(char a) {
char buf[2];
buf[0] = a;
diff --git a/test/Analysis/PR9741.cpp b/test/Analysis/PR9741.cpp
new file mode 100644
index 000000000000..e20e56c9406a
--- /dev/null
+++ b/test/Analysis/PR9741.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -cc1 -std=c++0x -Wuninitialized -verify %s
+
+void f() {
+ int a[] = { 1, 2, 3 };
+ unsigned int u = 0;
+ for (auto x : a)
+ ;
+}
diff --git a/test/Analysis/additive-folding-range-constraints.c b/test/Analysis/additive-folding-range-constraints.c
index a8ca5d2e351d..e342bb453cda 100644
--- a/test/Analysis/additive-folding-range-constraints.c
+++ b/test/Analysis/additive-folding-range-constraints.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -verify -analyzer-constraints=range %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify -analyzer-constraints=range %s
// These are used to trigger warnings.
typedef typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/additive-folding.c b/test/Analysis/additive-folding.c
index 096ffb9a5059..17d9db6ea23a 100644
--- a/test/Analysis/additive-folding.c
+++ b/test/Analysis/additive-folding.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-checker=core.experimental.UnreachableCode -verify -analyzer-constraints=basic %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-checker=core.experimental.UnreachableCode -verify -analyzer-constraints=range %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,unix.experimental.Malloc -verify -analyzer-constraints=basic %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,unix.experimental.Malloc -verify -analyzer-constraints=range %s
// These are used to trigger warnings.
typedef typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/analyzer-stats.c b/test/Analysis/analyzer-stats.c
index 2a2e325acef8..9eeaade793c2 100644
--- a/test/Analysis/analyzer-stats.c
+++ b/test/Analysis/analyzer-stats.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=core.DeadStores -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks -analyzer-stats %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,debug.Stats -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
int foo();
diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c
index 168423e0c2cd..37a6f75b3ca2 100644
--- a/test/Analysis/array-struct-region.c
+++ b/test/Analysis/array-struct-region.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-checks -analyzer-checker=core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-checks -analyzer-checker=core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,deadcode.experimental.UnreachableCode -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,deadcode.experimental.UnreachableCode -analyzer-store=region -analyzer-constraints=range -verify %s
int string_literal_init() {
char a[] = "abc";
diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c
index df9e9786fff3..6b8bb6c5f675 100644
--- a/test/Analysis/array-struct.c
+++ b/test/Analysis/array-struct.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CastToStruct -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CastToStruct -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CastToStruct -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CastToStruct -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental.CastToStruct -analyzer-store=region -analyzer-constraints=range -verify %s
struct s {
int data;
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index 4bcfccd120e2..c877061eb6ae 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s 2>&1 | FileCheck %s
// XPASS: *
class A {
@@ -159,7 +159,7 @@ void test_catch_copy() {
// CHECK: Predecessors (0):
// CHECK: Successors (1): B1
// CHECK: [ B1 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: 3: const A &b = a;
// CHECK: 4: A()
@@ -175,9 +175,9 @@ void test_catch_copy() {
// CHECK: Predecessors (0):
// CHECK: Successors (1): B1
// CHECK: [ B1 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a[2];
-// CHECK: 3:
+// CHECK: 3:
// CHECK: 4: A b[0];
// CHECK: 5: [B1.2].~A() (Implicit destructor)
// CHECK: Predecessors (1): B2
@@ -189,15 +189,15 @@ void test_catch_copy() {
// CHECK: Predecessors (0):
// CHECK: Successors (1): B1
// CHECK: [ B1 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
-// CHECK: 3:
+// CHECK: 3:
// CHECK: 4: A c;
-// CHECK: 5:
+// CHECK: 5:
// CHECK: 6: A d;
// CHECK: 7: [B1.6].~A() (Implicit destructor)
// CHECK: 8: [B1.4].~A() (Implicit destructor)
-// CHECK: 9:
+// CHECK: 9:
// CHECK: 10: A b;
// CHECK: 11: [B1.10].~A() (Implicit destructor)
// CHECK: 12: [B1.2].~A() (Implicit destructor)
@@ -210,7 +210,7 @@ void test_catch_copy() {
// CHECK: Predecessors (0):
// CHECK: Successors (1): B3
// CHECK: [ B1 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B1.2].~A() (Implicit destructor)
// CHECK: 4: [B3.4].~A() (Implicit destructor)
@@ -224,9 +224,9 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B3
// CHECK: Successors (1): B0
// CHECK: [ B3 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
-// CHECK: 3:
+// CHECK: 3:
// CHECK: 4: A b;
// CHECK: 5: UV
// CHECK: T: if [B3.5]
@@ -240,7 +240,7 @@ void test_catch_copy() {
// CHECK: Successors (1): B7
// CHECK: [ B1 ]
// CHECK: l1:
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B1.2].~A() (Implicit destructor)
// CHECK: 4: [B6.2].~A() (Implicit destructor)
@@ -248,7 +248,7 @@ void test_catch_copy() {
// CHECK: Predecessors (2): B2 B3
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A b;
// CHECK: 3: [B2.2].~A() (Implicit destructor)
// CHECK: 4: [B6.4].~A() (Implicit destructor)
@@ -272,16 +272,16 @@ void test_catch_copy() {
// CHECK: Successors (1): B6
// CHECK: [ B6 ]
// CHECK: l0:
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A b;
-// CHECK: 3:
+// CHECK: 3:
// CHECK: 4: A a;
// CHECK: 5: UV
// CHECK: T: if [B6.5]
// CHECK: Predecessors (2): B7 B5
// CHECK: Successors (2): B5 B4
// CHECK: [ B7 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: Predecessors (1): B8
// CHECK: Successors (1): B6
@@ -297,24 +297,23 @@ void test_catch_copy() {
// CHECK: Predecessors (2): B2 B3
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B2.2].~A() (Implicit destructor)
// CHECK: Predecessors (1): B4
// CHECK: Successors (1): B1
// CHECK: [ B3 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B3.2].~A() (Implicit destructor)
// CHECK: Predecessors (1): B4
// CHECK: Successors (1): B1
// CHECK: [ B4 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: 3: a
-// CHECK: 4: if ([B4.6])
-// CHECK:[B3.2]else
-// CHECK:[B2.2] 5: b.operator int()
+// CHECK: 4: A b = a;
+// CHECK: 5: b.operator int()
// CHECK: 6: [B4.5]
// CHECK: T: if [B4.6]
// CHECK: Predecessors (1): B5
@@ -327,14 +326,14 @@ void test_catch_copy() {
// CHECK: Successors (1): B8
// CHECK: [ B1 ]
// CHECK: 1: [B8.4].~A() (Implicit destructor)
-// CHECK: 2:
+// CHECK: 2:
// CHECK: 3: A e;
// CHECK: 4: [B1.3].~A() (Implicit destructor)
// CHECK: 5: [B8.2].~A() (Implicit destructor)
// CHECK: Predecessors (2): B2 B5
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A d;
// CHECK: 3: [B2.2].~A() (Implicit destructor)
// CHECK: 4: [B4.2].~A() (Implicit destructor)
@@ -348,14 +347,14 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B4
// CHECK: Successors (1): B0
// CHECK: [ B4 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: UV
// CHECK: T: if [B4.3]
// CHECK: Predecessors (1): B8
// CHECK: Successors (2): B3 B2
// CHECK: [ B5 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A d;
// CHECK: 3: [B5.2].~A() (Implicit destructor)
// CHECK: 4: [B7.2].~A() (Implicit destructor)
@@ -369,21 +368,17 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B7
// CHECK: Successors (1): B0
// CHECK: [ B7 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: UV
// CHECK: T: if [B7.3]
// CHECK: Predecessors (1): B8
// CHECK: Successors (2): B6 B5
// CHECK: [ B8 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: 3: a
-// CHECK: 4: if ([B8.6]) {
-// CHECK:[B7.2] if ([B7.3])
-// CHECK:[B6.1][B5.2]} else {
-// CHECK:[B4.2] if ([B4.3])
-// CHECK:[B3.1][B2.2]}
+// CHECK: 4: A b = a;
// CHECK: 5: b.operator int()
// CHECK: 6: [B8.5]
// CHECK: T: if [B8.6]
@@ -402,8 +397,8 @@ void test_catch_copy() {
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
// CHECK: 1: a
-// CHECK: 2: while ([B2.4])
-// CHECK:[B4.2] 3: b.operator int()
+// CHECK: 2: A b = a;
+// CHECK: 3: b.operator int()
// CHECK: 4: [B2.3]
// CHECK: T: while [B2.4]
// CHECK: Predecessors (2): B3 B5
@@ -412,14 +407,14 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B4
// CHECK: Successors (1): B2
// CHECK: [ B4 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B4.2].~A() (Implicit destructor)
// CHECK: 4: [B2.2].~A() (Implicit destructor)
// CHECK: Predecessors (1): B2
// CHECK: Successors (1): B3
// CHECK: [ B5 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: Predecessors (1): B6
// CHECK: Successors (1): B2
@@ -431,7 +426,7 @@ void test_catch_copy() {
// CHECK: Successors (1): B11
// CHECK: [ B1 ]
// CHECK: 1: [B2.2].~A() (Implicit destructor)
-// CHECK: 2:
+// CHECK: 2:
// CHECK: 3: A e;
// CHECK: 4: [B1.3].~A() (Implicit destructor)
// CHECK: 5: [B11.2].~A() (Implicit destructor)
@@ -439,14 +434,7 @@ void test_catch_copy() {
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
// CHECK: 1: a
-// CHECK: 2: while ([B2.4])
-// CHECK: {
-// CHECK:[B10.2] if ([B10.3])
-// CHECK: break;
-// CHECK: if ([B8.1])
-// CHECK: continue;
-// CHECK: if ([B6.1])
-// CHECK:[B5.1][B4.2] }
+// CHECK: 2: A b = a;
// CHECK: 3: b.operator int()
// CHECK: 4: [B2.3]
// CHECK: T: while [B2.4]
@@ -456,7 +444,7 @@ void test_catch_copy() {
// CHECK: Predecessors (2): B4 B7
// CHECK: Successors (1): B2
// CHECK: [ B4 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A d;
// CHECK: 3: [B4.2].~A() (Implicit destructor)
// CHECK: 4: [B10.2].~A() (Implicit destructor)
@@ -492,14 +480,14 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B10
// CHECK: Successors (1): B1
// CHECK: [ B10 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: UV
// CHECK: T: if [B10.3]
// CHECK: Predecessors (1): B2
// CHECK: Successors (2): B9 B8
// CHECK: [ B11 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: Predecessors (1): B12
// CHECK: Successors (1): B2
@@ -515,7 +503,7 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B2
// CHECK: Successors (2): B3 B0
// CHECK: [ B2 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: 3: [B2.2].~A() (Implicit destructor)
// CHECK: Predecessors (2): B3 B4
@@ -530,7 +518,7 @@ void test_catch_copy() {
// CHECK: Predecessors (0):
// CHECK: Successors (1): B11
// CHECK: [ B1 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A d;
// CHECK: 3: [B1.2].~A() (Implicit destructor)
// CHECK: 4: [B11.2].~A() (Implicit destructor)
@@ -542,7 +530,7 @@ void test_catch_copy() {
// CHECK: Predecessors (2): B3 B6
// CHECK: Successors (2): B10 B1
// CHECK: [ B3 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B3.2].~A() (Implicit destructor)
// CHECK: 4: [B9.2].~A() (Implicit destructor)
@@ -575,7 +563,7 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B9
// CHECK: Successors (1): B1
// CHECK: [ B9 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A b;
// CHECK: 3: UV
// CHECK: T: if [B9.3]
@@ -585,7 +573,7 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B2
// CHECK: Successors (1): B9
// CHECK: [ B11 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: Predecessors (1): B12
// CHECK: Successors (1): B9
@@ -601,16 +589,16 @@ void test_catch_copy() {
// CHECK: Predecessors (2): B3 B2
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: 3: a
-// CHECK: 4: switch ([B2.5])
-// CHECK:[B3.2] 5: b.operator int()
+// CHECK: 4: A b = a;
+// CHECK: 5: b.operator int()
// CHECK: T: switch [B2.5]
// CHECK: Predecessors (1): B4
// CHECK: Successors (1): B1
// CHECK: [ B3 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B3.2].~A() (Implicit destructor)
// CHECK: Predecessors (0):
@@ -623,26 +611,17 @@ void test_catch_copy() {
// CHECK: Successors (1): B2
// CHECK: [ B1 ]
// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: 2:
+// CHECK: 2:
// CHECK: 3: A g;
// CHECK: 4: [B1.3].~A() (Implicit destructor)
// CHECK: 5: [B2.2].~A() (Implicit destructor)
// CHECK: Predecessors (3): B3 B7 B2
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: 3: a
-// CHECK: 4: switch ([B2.5]) {
-// CHECK: case 0:
-// CHECK: {
-// CHECK:[B8.2] if ([B8.3])
-// CHECK: break;
-// CHECK: if ([B6.1])
-// CHECK:[B5.1][B4.2] }
-// CHECK: case 1:
-// CHECK: break;
-// CHECK:}
+// CHECK: 4: A b = a;
// CHECK: 5: b.operator int()
// CHECK: T: switch [B2.5]
// CHECK: Predecessors (1): B9
@@ -654,7 +633,7 @@ void test_catch_copy() {
// CHECK: Predecessors (2): B2 B4
// CHECK: Successors (1): B1
// CHECK: [ B4 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A f;
// CHECK: 3: [B4.2].~A() (Implicit destructor)
// CHECK: 4: [B8.2].~A() (Implicit destructor)
@@ -679,7 +658,7 @@ void test_catch_copy() {
// CHECK: Successors (1): B1
// CHECK: [ B8 ]
// CHECK: case 0:
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: UV
// CHECK: T: if [B8.3]
@@ -698,8 +677,8 @@ void test_catch_copy() {
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
// CHECK: 1: a
-// CHECK: 2: for (A a; [B2.4];)
-// CHECK:[B4.2] 3: b.operator int()
+// CHECK: 2: A b = a;
+// CHECK: 3: b.operator int()
// CHECK: 4: [B2.3]
// CHECK: T: for (...; [B2.4]; )
// CHECK: Predecessors (2): B3 B5
@@ -709,13 +688,13 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B4
// CHECK: Successors (1): B2
// CHECK: [ B4 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A c;
// CHECK: 3: [B4.2].~A() (Implicit destructor)
// CHECK: Predecessors (1): B2
// CHECK: Successors (1): B3
// CHECK: [ B5 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
// CHECK: Predecessors (1): B6
// CHECK: Successors (1): B2
@@ -728,7 +707,7 @@ void test_catch_copy() {
// CHECK: [ B1 ]
// CHECK: 1: [B2.2].~A() (Implicit destructor)
// CHECK: 2: [B11.4].~A() (Implicit destructor)
-// CHECK: 3:
+// CHECK: 3:
// CHECK: 4: A f;
// CHECK: 5: [B1.4].~A() (Implicit destructor)
// CHECK: 6: [B11.2].~A() (Implicit destructor)
@@ -736,13 +715,7 @@ void test_catch_copy() {
// CHECK: Successors (1): B0
// CHECK: [ B2 ]
// CHECK: 1: b
-// CHECK: 2: for (A b; [B2.4];) {
-// CHECK:[B10.2] if ([B10.3])
-// CHECK: break;
-// CHECK: if ([B8.1])
-// CHECK: continue;
-// CHECK: if ([B6.1])
-// CHECK:[B5.1][B4.2]}
+// CHECK: 2: A c = b;
// CHECK: 3: c.operator int()
// CHECK: 4: [B2.3]
// CHECK: T: for (...; [B2.4]; )
@@ -753,7 +726,7 @@ void test_catch_copy() {
// CHECK: Predecessors (2): B4 B7
// CHECK: Successors (1): B2
// CHECK: [ B4 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A e;
// CHECK: 3: [B4.2].~A() (Implicit destructor)
// CHECK: 4: [B10.2].~A() (Implicit destructor)
@@ -788,16 +761,16 @@ void test_catch_copy() {
// CHECK: Predecessors (1): B10
// CHECK: Successors (1): B1
// CHECK: [ B10 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A d;
// CHECK: 3: UV
// CHECK: T: if [B10.3]
// CHECK: Predecessors (1): B2
// CHECK: Successors (2): B9 B8
// CHECK: [ B11 ]
-// CHECK: 1:
+// CHECK: 1:
// CHECK: 2: A a;
-// CHECK: 3:
+// CHECK: 3:
// CHECK: 4: A b;
// CHECK: Predecessors (1): B12
// CHECK: Successors (1): B2
@@ -833,3 +806,4 @@ void test_catch_copy() {
// CHECK: [ B0 (EXIT) ]
// CHECK: Predecessors (3): B2 B1 B3
// CHECK: Successors (0):
+
diff --git a/test/Analysis/base-init.cpp b/test/Analysis/base-init.cpp
index 800763b25b49..8fd7abcc3778 100644
--- a/test/Analysis/base-init.cpp
+++ b/test/Analysis/base-init.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -analyzer-inline-call -cfg-add-initializers -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-inline-call -cfg-add-initializers -verify %s
+// XFAIL: *
class A {
int x;
diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m
index e18d7cfb7be6..7a604ddb4d91 100644
--- a/test/Analysis/blocks.m
+++ b/test/Analysis/blocks.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index eb235430aac0..1f6839d33703 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core.experimental.CString -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -15,7 +15,7 @@
// Some functions are implemented as builtins. These should be #defined as
// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined.
-// Functions that have variants and are also availabe as builtins should be
+// Functions that have variants and are also available as builtins should be
// declared carefully! See memcpy() for an example.
#ifdef USE_BUILTINS
@@ -129,10 +129,111 @@ void memcpy11() {
void memcpy12() {
char a[4] = {0};
memcpy(0, a, 0); // no-warning
+}
+
+void memcpy13() {
+ char a[4] = {0};
memcpy(a, 0, 0); // no-warning
}
//===----------------------------------------------------------------------===
+// mempcpy()
+//===----------------------------------------------------------------------===
+
+#define mempcpy BUILTIN(mempcpy)
+void *mempcpy(void *restrict s1, const void *restrict s2, size_t n);
+
+void mempcpy0 () {
+ char src[] = {1, 2, 3, 4};
+ char dst[5] = {0};
+
+ mempcpy(dst, src, 4); // no-warning
+
+ if (mempcpy(dst, src, 4) != &dst[4]) {
+ (void)*(char*)0; // no-warning
+ }
+
+ if (dst[0] != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void mempcpy1 () {
+ char src[] = {1, 2, 3, 4};
+ char dst[10];
+
+ mempcpy(dst, src, 5); // expected-warning{{Byte string function accesses out-of-bound array element}}
+}
+
+void mempcpy2 () {
+ char src[] = {1, 2, 3, 4};
+ char dst[1];
+
+ mempcpy(dst, src, 4); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void mempcpy3 () {
+ char src[] = {1, 2, 3, 4};
+ char dst[3];
+
+ mempcpy(dst+1, src+2, 2); // no-warning
+}
+
+void mempcpy4 () {
+ char src[] = {1, 2, 3, 4};
+ char dst[10];
+
+ mempcpy(dst+2, src+2, 3); // expected-warning{{Byte string function accesses out-of-bound array element}}
+}
+
+void mempcpy5() {
+ char src[] = {1, 2, 3, 4};
+ char dst[3];
+
+ mempcpy(dst+2, src+2, 2); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void mempcpy6() {
+ int a[4] = {0};
+ mempcpy(a, a, 8); // expected-warning{{overlapping}}
+}
+
+void mempcpy7() {
+ int a[4] = {0};
+ mempcpy(a+2, a+1, 8); // expected-warning{{overlapping}}
+}
+
+void mempcpy8() {
+ int a[4] = {0};
+ mempcpy(a+1, a+2, 8); // expected-warning{{overlapping}}
+}
+
+void mempcpy9() {
+ int a[4] = {0};
+ mempcpy(a+2, a+1, 4); // no-warning
+ mempcpy(a+1, a+2, 4); // no-warning
+}
+
+void mempcpy10() {
+ char a[4] = {0};
+ mempcpy(0, a, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void mempcpy11() {
+ char a[4] = {0};
+ mempcpy(a, 0, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void mempcpy12() {
+ char a[4] = {0};
+ mempcpy(0, a, 0); // no-warning
+}
+
+void mempcpy13() {
+ char a[4] = {0};
+ mempcpy(a, 0, 0); // no-warning
+}
+
+//===----------------------------------------------------------------------===
// memmove()
//===----------------------------------------------------------------------===
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index 1df30c9e3555..35d97fec675d 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
// Test if the 'storage' region gets properly initialized after it is cast to
// 'struct sockaddr *'.
diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m
index a6f11926818d..d073dff963fc 100644
--- a/test/Analysis/casts.m
+++ b/test/Analysis/casts.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
// Test function pointer casts. Currently we track function addresses using
// loc::FunctionVal. Because casts can be arbitrary, do we need to model
diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c
index 94475bdcdf2d..280676330a46 100644
--- a/test/Analysis/cfref_PR2519.c
+++ b/test/Analysis/cfref_PR2519.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
typedef unsigned char Boolean;
typedef signed long CFIndex;
diff --git a/test/Analysis/cfref_rdar6080742.c b/test/Analysis/cfref_rdar6080742.c
index debc1d8990cc..aceefbe54872 100644
--- a/test/Analysis/cfref_rdar6080742.c
+++ b/test/Analysis/cfref_rdar6080742.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
// This test case was reported in <rdar:problem/6080742>.
// It tests path-sensitivity with respect to '!(cfstring != 0)' (negation of inequality).
diff --git a/test/Analysis/chroot.c b/test/Analysis/chroot.c
index 5b98a7197408..7a584da6c05c 100644
--- a/test/Analysis/chroot.c
+++ b/test/Analysis/chroot.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=unix.experimental.Chroot -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.experimental.Chroot -analyzer-store region -verify %s
extern int chroot(const char* path);
extern int chdir(const char* path);
diff --git a/test/Analysis/complex.c b/test/Analysis/complex.c
index c8bdce015363..b125a502f1df 100644
--- a/test/Analysis/complex.c
+++ b/test/Analysis/complex.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code -ffreestanding %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code -ffreestanding %s
#include <stdint.h>
diff --git a/test/Analysis/concrete-address.c b/test/Analysis/concrete-address.c
index 13afe0cbebd4..a722ab092e2c 100644
--- a/test/Analysis/concrete-address.c
+++ b/test/Analysis/concrete-address.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
void foo() {
int *p = (int*) 0x10000; // Should not crash here.
diff --git a/test/Analysis/conditional-op-missing-lhs.c b/test/Analysis/conditional-op-missing-lhs.c
deleted file mode 100644
index 51d40f2a040e..000000000000
--- a/test/Analysis/conditional-op-missing-lhs.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.DeadStores -warn-uninit-values -verify %s
-
-void f1()
-{
- int i;
-
- int j = i ? : 1; // expected-warning{{use of uninitialized variable}} //expected-warning{{Value stored to 'j' during its initialization is never read}}
-}
-
-void *f2(int *i)
-{
- return i ? : 0;
-}
-
-void *f3(int *i)
-{
- int a;
-
- return &a ? : i;
-}
-
-void f4()
-{
- char c[1 ? : 2];
-}
-
diff --git a/test/Analysis/constant-folding.c b/test/Analysis/constant-folding.c
index 33b48f5164cb..d3cbf9c56479 100644
--- a/test/Analysis/constant-folding.c
+++ b/test/Analysis/constant-folding.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode -Wno-null-dereference -verify %s
// Trigger a warning if the analyzer reaches this point in the control flow.
#define WARN ((void)*(char*)0)
diff --git a/test/Analysis/cxx-crashes.cpp b/test/Analysis/cxx-crashes.cpp
index c9775df7e2d0..17fc74d06f46 100644
--- a/test/Analysis/cxx-crashes.cpp
+++ b/test/Analysis/cxx-crashes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
int f1(char *dst) {
char *p = dst + 4;
@@ -43,3 +43,14 @@ void *f(S* w) {
}
}
+
+namespace {
+
+struct C {
+ void *p;
+ static void f();
+};
+
+void C::f() { }
+
+}
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 39394c6354a4..85ea1ee2cb64 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core.DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core.DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core.DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core.DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core.DeadStores,core.experimental.IdempotentOps -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=basic -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=basic -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
void f1() {
int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}}
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
index 8477b701fa0c..932e94092847 100644
--- a/test/Analysis/dead-stores.cpp
+++ b/test/Analysis/dead-stores.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fexceptions -analyze -analyzer-checker=core.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fexceptions -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -analyzer-checker=core.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fexceptions -analyze -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -analyzer-checker=core.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fexceptions -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -analyzer-checker=core.DeadStores -verify -Wno-unreachable-code %s
-// RUN: %clang_cc1 -fexceptions -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-checker=core.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=basic -analyzer-constraints=basic -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=basic -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=basic -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-store=region -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
//===----------------------------------------------------------------------===//
// Basic dead store checking (but in C++ mode).
diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m
index 8e13a97393e9..3a06a8adeb0d 100644
--- a/test/Analysis/dead-stores.m
+++ b/test/Analysis/dead-stores.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=core.DeadStores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=deadcode.DeadStores -verify %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
@@ -25,7 +25,7 @@ typedef struct _NSPoint {} NSRange;
extern NSString *NSAlignmentBinding;
// This test case was reported as a false positive due to a bug in the
-// LiveVariables <-> DeadStores interplay. We should not flag a warning
+// LiveVariables <-> deadcode.DeadStores interplay. We should not flag a warning
// here. The test case was reported in:
// http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-July/002157.html
void DeadStoreTest(NSObject *anObject) {
diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m
index 194a64a85516..218083598919 100644
--- a/test/Analysis/delegates.m
+++ b/test/Analysis/delegates.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp
index 2a9244ef34b2..f65b9db17b65 100644
--- a/test/Analysis/derived-to-base.cpp
+++ b/test/Analysis/derived-to-base.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region %s
class A {
protected:
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index ea5b04684d7f..dfd438ed405d 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -analyzer-inline-call -cfg-add-implicit-dtors -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-inline-call -cfg-add-implicit-dtors -verify %s
class A {
public:
diff --git a/test/Analysis/elementtype.c b/test/Analysis/elementtype.c
index ba66015d746e..d41202a1f07f 100644
--- a/test/Analysis/elementtype.c
+++ b/test/Analysis/elementtype.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region %s
typedef struct added_obj_st {
int type;
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index f2b15bff3159..02772a148b6b 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
//
// Just exercise the analyzer on code that has at one point caused issues
// (i.e., no assertions or crashes).
diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c
index c7e223138b1c..0991d00868cf 100644
--- a/test/Analysis/fields.c
+++ b/test/Analysis/fields.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=basic -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=region -verify
unsigned foo();
typedef struct bf { unsigned x:2; } bf;
diff --git a/test/Analysis/flat-store.c b/test/Analysis/flat-store.c
index bb274b0d5dfa..bf93c724400f 100644
--- a/test/Analysis/flat-store.c
+++ b/test/Analysis/flat-store.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=flat -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=flat -Wno-null-dereference -verify %s
#define FAIL ((void)*(char*)0)
struct simple { int x; };
diff --git a/test/Analysis/free.c b/test/Analysis/free.c
index 8aba4a05f0bf..d57da69ba456 100644
--- a/test/Analysis/free.c
+++ b/test/Analysis/free.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-experimental-checks -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.experimental.Malloc -fblocks -verify %s
void free(void *);
void t1 () {
diff --git a/test/Analysis/func.c b/test/Analysis/func.c
index e4e20a0bed14..0694f7bd4c26 100644
--- a/test/Analysis/func.c
+++ b/test/Analysis/func.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
void f(void) {
void (*p)(void);
diff --git a/test/Analysis/idempotent-operations-limited-loops.c b/test/Analysis/idempotent-operations-limited-loops.c
index e4c34cdead35..47a1f2854c74 100644
--- a/test/Analysis/idempotent-operations-limited-loops.c
+++ b/test/Analysis/idempotent-operations-limited-loops.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -analyzer-max-loop 3 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -analyzer-max-loop 4 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,deadcode.IdempotentOperations -analyzer-max-loop 3 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,deadcode.IdempotentOperations -analyzer-max-loop 4 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,deadcode.IdempotentOperations %s -verify
void always_warning() { int *p = 0; *p = 0xDEADBEEF; } // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
diff --git a/test/Analysis/idempotent-operations.c b/test/Analysis/idempotent-operations.c
index b47394c1626b..10bd9ff3198c 100644
--- a/test/Analysis/idempotent-operations.c
+++ b/test/Analysis/idempotent-operations.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations -verify %s
+// RUN: %clang --analyze -Xclang -analyzer-disable-checker=deadcode.DeadStores -fblocks -Xclang -verify %s -o %t
// Basic tests
@@ -82,8 +83,8 @@ void bailout() {
typedef unsigned uintptr_t;
void kill_at_assign() {
short array[2];
- uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion}}
- short *p = x; // expected-warning{{incompatible integer to pointer conversion}}
+ uintptr_t x = (uintptr_t) array;
+ short *p = (short *) x;
// The following branch should be infeasible.
if (!(p = &array[0])) { // expected-warning{{Assigned value is always the same as the existing value}}
@@ -175,7 +176,7 @@ int false6() {
// Check that assignments filter out false positives correctly
int false7() {
- int zero = 0; // psuedo-constant
+ int zero = 0; // pseudo-constant
int one = 1;
int a = 55;
diff --git a/test/Analysis/idempotent-operations.cpp b/test/Analysis/idempotent-operations.cpp
index c213dc690e44..9d22909ed37e 100644
--- a/test/Analysis/idempotent-operations.cpp
+++ b/test/Analysis/idempotent-operations.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations -verify %s
// C++ specific false positives
@@ -13,3 +13,22 @@ void false1() {
test(five * a); // expected-warning {{The right operand to '*' is always 0}}
b = 4;
}
+
+// Test not flagging idempotent operations because we aborted the analysis
+// of a path because of an unsupported construct.
+struct RDar9219143_Foo {
+ ~RDar9219143_Foo();
+ operator bool() const;
+};
+
+RDar9219143_Foo foo();
+unsigned RDar9219143_bar();
+void RDar9219143_test() {
+ unsigned i, e;
+ for (i = 0, e = RDar9219143_bar(); i != e; ++i)
+ if (foo())
+ break;
+ if (i == e) // no-warning
+ return;
+}
+
diff --git a/test/Analysis/idempotent-operations.m b/test/Analysis/idempotent-operations.m
index a77e2cbf8719..8f534940c975 100644
--- a/test/Analysis/idempotent-operations.m
+++ b/test/Analysis/idempotent-operations.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-check-objc-mem -analyzer-checker=core.experimental.IdempotentOps -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations -verify %s
typedef signed char BOOL;
typedef unsigned long NSUInteger;
@@ -40,3 +40,15 @@ void pr9116(NSObject *placeholder) {
int x = placeholder.media.locked = placeholder ? 1 : 0;
}
+// <rdar://problem/9130239>: Test that calling property setters doesn't
+// trigger an assertion failure when the object is nil.
+@interface RDar9130239
+@property (assign) id delegate;
+@end
+
+void test_RDar9130239(RDar9130239 *x) {
+ if (x)
+ return;
+ x.delegate = x; // no-warning
+}
+
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index 2fa3a9eb86a7..656a8bf8eed8 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -cfg-add-initializers -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -cfg-add-initializers -verify %s
class A {
int x;
diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c
index d7a599a76545..2aac15661b14 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// XFAIL: *
int test1_f1() {
int y = 1;
diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c
index efdb75cc6535..97e479d4b292 100644
--- a/test/Analysis/inline2.c
+++ b/test/Analysis/inline2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
// Test parameter 'a' is registered to LiveVariables analysis data although it
// is not referenced in the function body.
diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c
index 884b3ed9dc25..9c8e26ece51b 100644
--- a/test/Analysis/inline3.c
+++ b/test/Analysis/inline3.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
// Test when entering f1(), we set the right AnalysisContext to Environment.
// Otherwise, block-level expr '1 && a' would not be block-level.
diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c
index 5a1d193beb29..c428aad5ec4b 100644
--- a/test/Analysis/inline4.c
+++ b/test/Analysis/inline4.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
int g(int a) {
return a;
diff --git a/test/Analysis/iterators.cpp b/test/Analysis/iterators.cpp
new file mode 100644
index 000000000000..c3416f5beac1
--- /dev/null
+++ b/test/Analysis/iterators.cpp
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.Iterators -verify %s
+// XFAIL: win32
+
+#include <vector>
+
+void fum(std::vector<int>::iterator t);
+
+void foo1()
+{
+ // iterators that are defined but not initialized
+ std::vector<int>::iterator it2;
+ fum(it2); // expected-warning{{Use of iterator that is not defined}}
+ *it2; // expected-warning{{Use of iterator that is not defined}}
+
+ std::vector<int> v, vv;
+ std::vector<int>::iterator it = v.begin();
+ fum(it); // no-warning
+ *it; // no-warning
+ // a valid iterator plus an integer is still valid
+ std::vector<int>::iterator et = it + 3;
+ while(it != et) { // no-warning
+ if (*it == 0) // no-warning
+ *it = 1; // no-warning
+ }
+ // iterators from different instances Cannot be compared
+ et = vv.end();
+ while(it != et) // expected-warning{{Cannot compare iterators from different containers}}
+ ;
+
+ for( std::vector<int>::iterator it = v.begin(); it != v.end(); it++ ) { // no-warning
+ if (*it == 1) // no-warning
+ *it = 0; // no-warning
+ }
+
+ // copying a valid iterator results in a valid iterator
+ et = it; // no-warning
+ *et; // no-warning
+
+ // any combo of valid iterator plus a constant is still valid
+ et = it + 2; // no-warning
+ *et; // no-warning
+ et = 2 + it; // no-warning
+ *et; // no-warning
+ et = 2 + 4 + it; // no-warning
+ *et; // no-warning
+
+ // calling insert invalidates unless assigned to as result, but still
+ // invalidates other iterators on the same instance
+ it = v.insert( it, 1 ); // no-warning
+ *et; // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}}
+ ++it; // no-warning
+
+ // calling erase invalidates the iterator
+ v.erase(it); // no-warning
+ et = it + 2; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}}
+ et = 2 + it + 2; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}}
+ et = 2 + it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}}
+ ++it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}}
+ it++; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}}
+ *it; // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}}
+ it = v.insert( it, 1 ); // expected-warning{{Attempt to use an iterator made invalid by call to 'erase'}}
+ // now valid after return from insert
+ *it; // no-warning
+}
+
+// work with using namespace
+void foo2()
+{
+ using namespace std;
+
+ vector<int> v;
+ vector<int>::iterator it = v.begin();
+ *it; // no-warning
+ v.insert( it, 1 ); // no-warning
+ *it; // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}}
+ it = v.insert( it, 1 ); // expected-warning{{Attempt to use an iterator made invalid by call to 'insert'}}
+ *it; // no-warning
+}
+
+// using reserve eliminates some warnings
+void foo3()
+{
+ std::vector<long> v;
+ std::vector<long>::iterator b = v.begin();
+ v.reserve( 100 );
+
+ // iterator assigned before the reserve is still invalidated
+ *b; // expected-warning{{Attempt to use an iterator made invalid by call to 'reserve'}}
+ b = v.begin();
+ v.insert( b, 1 ); // no-warning
+
+ // iterator after assignment is still valid (probably)
+ *b; // no-warning
+}
+
+// check on copying one iterator to another
+void foo4()
+{
+ std::vector<float> v, vv;
+ std::vector<float>::iterator it = v.begin();
+ *it; // no-warning
+ v = vv;
+ *it; // expected-warning{{Attempt to use an iterator made invalid by copying another container to its container}}
+}
+
diff --git a/test/Analysis/lvalue.cpp b/test/Analysis/lvalue.cpp
index f19c59d9d258..0cc42f50372b 100644
--- a/test/Analysis/lvalue.cpp
+++ b/test/Analysis/lvalue.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
int f1() {
int x = 0, y = 1;
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 2ffa1033598d..f9af199b5fad 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.UnreachableCode,core.experimental.CastSize -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.experimental.UnreachableCode,core.experimental.CastSize,unix.experimental.Malloc -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
@@ -33,6 +33,17 @@ void f2() {
free(p); // expected-warning{{Try to free a memory block that has been released}}
}
+void f2_realloc_0() {
+ int *p = malloc(12);
+ realloc(p,0);
+ realloc(p,0); // expected-warning{{Try to free a memory block that has been released}}
+}
+
+void f2_realloc_1() {
+ int *p = malloc(12);
+ int *q = realloc(p,0); // expected-warning{{Assigned value is garbage or undefined}}
+}
+
// ownership attributes tests
void naf1() {
int *p = my_malloc3(12);
@@ -166,6 +177,15 @@ void f6() {
free(p);
}
+void f6_realloc() {
+ int *p = malloc(12);
+ if (!p)
+ return; // no-warning
+ else
+ realloc(p,0);
+}
+
+
char *doit2();
void pr6069() {
char *buf = doit2();
@@ -182,6 +202,12 @@ void f7() {
x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
}
+void f7_realloc() {
+ char *x = (char*) malloc(4);
+ realloc(x,0);
+ x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
+}
+
void PR6123() {
int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}}
}
diff --git a/test/SemaObjC/method-arg-decay.m b/test/Analysis/method-arg-decay.m
index 6e11e97898d6..9ce88b242327 100644
--- a/test/SemaObjC/method-arg-decay.m
+++ b/test/Analysis/method-arg-decay.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyzer-check-objc-mem -verify %s
+// RUN: %clang_cc1 -analyzer-checker=core -verify %s
typedef signed char BOOL;
typedef int NSInteger;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/method-call.cpp b/test/Analysis/method-call.cpp
index b5b81e3402a1..323fffebcdbe 100644
--- a/test/Analysis/method-call.cpp
+++ b/test/Analysis/method-call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
// XFAIL: *
struct A {
diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m
index bdb12c963f95..1cd738292781 100644
--- a/test/Analysis/misc-ps-64.m
+++ b/test/Analysis/misc-ps-64.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
// <rdar://problem/6440393> - A bunch of misc. failures involving evaluating
// these expressions and building CFGs. These tests are here to prevent
diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m
index 55042c142584..a29326d8b0e7 100644
--- a/test/Analysis/misc-ps-basic-store.m
+++ b/test/Analysis/misc-ps-basic-store.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify -fblocks %s
//---------------------------------------------------------------------------
// Test case 'checkaccess_union' differs for region store and basic store.
diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m
index a0323f480ccc..649c4b07f543 100644
--- a/test/Analysis/misc-ps-eager-assume.m
+++ b/test/Analysis/misc-ps-eager-assume.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
// Delta-reduced header stuff (needed for test cases).
typedef signed char BOOL;
@@ -81,7 +81,7 @@ void pr3836(int *a, int *b) {
//===---------------------------------------------------------------------===//
// <rdar://problem/7342806>
-// This false positive occured because the symbolic constraint on a short was
+// This false positive occurred because the symbolic constraint on a short was
// not maintained via sign extension. The analyzer doesn't properly handle
// the sign extension, but now tracks the constraint. This particular
// case relies on -analyzer-eagerly-assume because of the expression
diff --git a/test/Analysis/misc-ps-flat-store.c b/test/Analysis/misc-ps-flat-store.c
index 8cbcecf51ff0..e6369cbfb079 100644
--- a/test/Analysis/misc-ps-flat-store.c
+++ b/test/Analysis/misc-ps-flat-store.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=flat -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=flat -verify %s
void f1() {
int x;
diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m
index 01a228a5dec2..f2851f3257dd 100644
--- a/test/Analysis/misc-ps-ranges.m
+++ b/test/Analysis/misc-ps-ranges.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
// <rdar://problem/6776949>
// main's 'argc' argument is always > 0
diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m
index 90183257d2b2..2988dca4abd9 100644
--- a/test/Analysis/misc-ps-region-store-i386.m
+++ b/test/Analysis/misc-ps-region-store-i386.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks %s
// Here is a case where a pointer is treated as integer, invalidated as an
// integer, and then used again as a pointer. This test just makes sure
diff --git a/test/Analysis/misc-ps-region-store-x86_64.m b/test/Analysis/misc-ps-region-store-x86_64.m
index a440bc55ae19..9f1498ef47f4 100644
--- a/test/Analysis/misc-ps-region-store-x86_64.m
+++ b/test/Analysis/misc-ps-region-store-x86_64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks %s
// Here is a case where a pointer is treated as integer, invalidated as an
// integer, and then used again as a pointer. This test just makes sure
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index 7c296fd3db9b..b122bffaaec0 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
// Test basic handling of references.
char &test1_aux();
@@ -240,3 +240,158 @@ void test_namespace() {
int x = i;
}
+// Test handling methods that accept references as parameters, and that
+// variables are properly invalidated.
+class RDar9203355 {
+ bool foo(unsigned valA, long long &result) const;
+ bool foo(unsigned valA, int &result) const;
+};
+bool RDar9203355::foo(unsigned valA, int &result) const {
+ long long val;
+ if (foo(valA, val) ||
+ (int)val != val) // no-warning
+ return true;
+ result = val; // no-warning
+ return false;
+}
+
+// Test handling of new[].
+void rdar9212512() {
+ int *x = new int[10];
+ for (unsigned i = 0 ; i < 2 ; ++i) {
+ // This previously triggered an uninitialized values warning.
+ x[i] = 1; // no-warning
+ }
+}
+
+// Test basic support for dynamic_cast<>.
+struct Rdar9212495_C { virtual void bar() const; };
+class Rdar9212495_B : public Rdar9212495_C {};
+class Rdar9212495_A : public Rdar9212495_B {};
+const Rdar9212495_A& rdar9212495(const Rdar9212495_C* ptr) {
+ const Rdar9212495_A& val = dynamic_cast<const Rdar9212495_A&>(*ptr);
+
+ if (&val == 0) {
+ val.bar(); // FIXME: This should eventually be a null dereference.
+ }
+
+ return val;
+}
+
+// Test constructors invalidating arguments. Previously this raised
+// an uninitialized value warning.
+extern "C" void __attribute__((noreturn)) PR9645_exit(int i);
+
+class PR9645_SideEffect
+{
+public:
+ PR9645_SideEffect(int *pi); // caches pi in i_
+ void Read(int *pi); // copies *pi into *i_
+private:
+ int *i_;
+};
+
+void PR9645() {
+ int i;
+
+ PR9645_SideEffect se(&i);
+ int j = 1;
+ se.Read(&j); // this has a side-effect of initializing i.
+
+ PR9645_exit(i); // no-warning
+}
+
+PR9645_SideEffect::PR9645_SideEffect(int *pi) : i_(pi) {}
+void PR9645_SideEffect::Read(int *pi) { *i_ = *pi; }
+
+// Invalidate fields during C++ method calls.
+class RDar9267815 {
+ int x;
+ void test();
+ void test_pos();
+ void test2();
+ void invalidate();
+};
+
+void RDar9267815::test_pos() {
+ int *p = 0;
+ if (x == 42)
+ return;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+}
+void RDar9267815::test() {
+ int *p = 0;
+ if (x == 42)
+ return;
+ if (x == 42)
+ *p = 0xDEADBEEF; // no-warning
+}
+
+void RDar9267815::test2() {
+ int *p = 0;
+ if (x == 42)
+ return;
+ invalidate();
+ if (x == 42)
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+}
+
+// Test reference parameters.
+void test_ref_double_aux(double &Value);
+float test_ref_double() {
+ double dVal;
+ test_ref_double_aux(dVal);
+ // This previously warned because 'dVal' was thought to be uninitialized.
+ float Val = (float)dVal; // no-warning
+ return Val;
+}
+
+// Test invalidation of class fields.
+class TestInvalidateClass {
+public:
+ int x;
+};
+
+void test_invalidate_class_aux(TestInvalidateClass &x);
+
+int test_invalidate_class() {
+ TestInvalidateClass y;
+ test_invalidate_class_aux(y);
+ return y.x; // no-warning
+}
+
+// Test correct pointer arithmetic using 'p--'. This is to warn that we
+// were loading beyond the written characters in buf.
+char *RDar9269695(char *dst, unsigned int n)
+{
+ char buff[40], *p;
+
+ p = buff;
+ do
+ *p++ = '0' + n % 10;
+ while (n /= 10);
+
+ do
+ *dst++ = *--p; // no-warning
+ while (p != buff);
+
+ return dst;
+}
+
+// Test that we invalidate byref arguments passed to constructors.
+class TestInvalidateInCtor {
+public:
+ TestInvalidateInCtor(unsigned &x);
+};
+
+unsigned test_invalidate_in_ctor() {
+ unsigned x;
+ TestInvalidateInCtor foo(x);
+ return x; // no-warning
+}
+unsigned test_invalidate_in_ctor_new() {
+ unsigned x;
+ delete (new TestInvalidateInCtor(x));
+ return x; // no-warning
+}
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 37e1a12c87bd..be0356d176b5 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental.IdempotentOps,core.experimental.CastToStruct,core.experimental.ReturnPtrRange,core.experimental.ReturnPtrRange,core.experimental.ArrayBound -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core.experimental.IdempotentOps,core.experimental.CastToStruct,core.experimental.ReturnPtrRange,core.experimental.ArrayBound -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental.CastToStruct,security.experimental.ReturnPtrRange,security.experimental.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental.CastToStruct,security.experimental.ReturnPtrRange,security.experimental.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
typedef long unsigned int size_t;
void *memcpy(void *, const void *, size_t);
@@ -1237,3 +1237,65 @@ void pr9048(pr9048_cdev_t dev, struct pr9048_diskslices * ssp, unsigned int slic
}
}
+// Test Store reference counting in the presence of Lazy compound values.
+// This previously caused an infinite recursion.
+typedef struct {} Rdar_9103310_A;
+typedef struct Rdar_9103310_B Rdar_9103310_B_t;
+struct Rdar_9103310_B {
+ unsigned char Rdar_9103310_C[101];
+};
+void Rdar_9103310_E(Rdar_9103310_A * x, struct Rdar_9103310_C * b) { // expected-warning {{declaration of 'struct Rdar_9103310_C' will not be visible outside of this function}}
+ char Rdar_9103310_D[4][4] = { "a", "b", "c", "d"};
+ int i;
+ Rdar_9103310_B_t *y = (Rdar_9103310_B_t *) x;
+ for (i = 0; i < 101; i++) {
+ Rdar_9103310_F(b, "%2d%s ", (y->Rdar_9103310_C[i]) / 4, Rdar_9103310_D[(y->Rdar_9103310_C[i]) % 4]); // expected-warning {{implicit declaration of function 'Rdar_9103310_F' is invalid in C99}}
+ }
+}
+
+// Test handling binding lazy compound values to a region and then have
+// specific elements have other bindings.
+int PR9455() {
+ char arr[4] = "000";
+ arr[0] = '1';
+ if (arr[1] == '0')
+ return 1;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ return 1;
+}
+int PR9455_2() {
+ char arr[4] = "000";
+ arr[0] = '1';
+ if (arr[1] == '0') {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+ }
+ return 1;
+}
+
+// Test initialization of substructs via lazy compound values.
+typedef float RDar9163742_Float;
+
+typedef struct {
+ RDar9163742_Float x, y;
+} RDar9163742_Point;
+typedef struct {
+ RDar9163742_Float width, height;
+} RDar9163742_Size;
+typedef struct {
+ RDar9163742_Point origin;
+ RDar9163742_Size size;
+} RDar9163742_Rect;
+
+extern RDar9163742_Rect RDar9163742_RectIntegral(RDar9163742_Rect);
+
+RDar9163742_Rect RDar9163742_IntegralRect(RDar9163742_Rect frame)
+{
+ RDar9163742_Rect integralFrame;
+ integralFrame.origin.x = frame.origin.x;
+ integralFrame.origin.y = frame.origin.y;
+ integralFrame.size = frame.size;
+ return RDar9163742_RectIntegral(integralFrame); // no-warning; all fields initialized
+}
+
diff --git a/test/Analysis/misc-ps-region-store.mm b/test/Analysis/misc-ps-region-store.mm
index a2df723c794b..08f3e2486f8a 100644
--- a/test/Analysis/misc-ps-region-store.mm
+++ b/test/Analysis/misc-ps-region-store.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
//===------------------------------------------------------------------------------------------===//
// This files tests our path-sensitive handling of Objective-c++ files.
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index db4fa02ff17c..9de4afb0ae98 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1,12 +1,12 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core.experimental,cocoa.AtSync -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-disable-checker=unix.experimental.Malloc -analyzer-store=basic -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,core.experimental,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
#ifndef __clang_analyzer__
#error __clang__analyzer__ not defined
@@ -1269,3 +1269,35 @@ void pr9287_c(int type, int *p) {
}
}
+void test_switch() {
+ switch (4) {
+ case 1: {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ break;
+ }
+ case 4: {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+ break;
+ }
+ default: {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ break;
+ }
+ }
+}
+
+// PR 9467. Tests various CFG optimizations. This previously crashed.
+static void test(unsigned int bit_mask)
+{
+ unsigned int bit_index;
+ for (bit_index = 0;
+ bit_index < 24;
+ bit_index++) {
+ switch ((0x01 << bit_index) & bit_mask) {
+ case 0x100000: ;
+ }
+ }
+}
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
index f26eecd4b196..29ac5eebd242 100644
--- a/test/Analysis/new.cpp
+++ b/test/Analysis/new.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
void f1() {
int *n = new int;
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
index eeab4312fe9c..80eeaf69ddbc 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=range -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=range -analyzer-store=region -verify %s
// <rdar://problem/6888289> - This test case shows that a nil instance
// variable can possibly be initialized by a method.
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
index 4ba1015c9a1d..3fcbc55044ea 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
@interface MyClass {}
- (void *)voidPtrM;
diff --git a/test/Analysis/no-exit-cfg.c b/test/Analysis/no-exit-cfg.c
index 2924aaeffff5..cfcd76d6e0cf 100644
--- a/test/Analysis/no-exit-cfg.c
+++ b/test/Analysis/no-exit-cfg.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
// This is a test case for the issue reported in PR 2819:
// http://llvm.org/bugs/show_bug.cgi?id=2819
diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c
index 92cb8b327110..2d77cc92adf9 100644
--- a/test/Analysis/no-outofbounds.c
+++ b/test/Analysis/no-outofbounds.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyzer-check-objc-mem -analyze -analyzer-checker=core.experimental -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyzer-check-objc-mem -analyze -analyzer-checker=core.experimental -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,unix.experimental,security.experimental.ArrayBound -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental,unix.experimental,security.experimental.ArrayBound -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
// This file tests cases where we should not flag out-of-bounds warnings.
@@ -25,7 +25,9 @@ void free(void *);
void field() {
struct vec { size_t len; int data[0]; };
- struct vec *a = malloc(sizeof(struct vec) + 10);
+ // FIXME: Not warn for this.
+ struct vec *a = malloc(sizeof(struct vec) + 10); // expected-warning {{Cast a region whose size is not a multiple of the destination type size}}
a->len = 10;
a->data[1] = 5; // no-warning
+ free(a);
}
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index df498ce5e622..85784558161e 100644
--- a/test/Analysis/null-deref-ps-region.c
+++ b/test/Analysis/null-deref-ps-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -std=gnu99 -analyzer-store=region -verify %s
// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 27f648770c94..4d0cc3fbddad 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=basic -Wreturn-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=range -analyzer-store=basic -Wreturn-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s -Wreturn-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s -Wreturn-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -verify %s -analyzer-constraints=basic -analyzer-store=basic -Wreturn-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -verify %s -analyzer-constraints=range -analyzer-store=basic -Wreturn-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s -Wreturn-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,core.experimental -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wreturn-type
typedef unsigned uintptr_t;
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
new file mode 100644
index 000000000000..b74a5abcdfa4
--- /dev/null
+++ b/test/Analysis/nullptr.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++0x -analyze -analyzer-checker=core -analyzer-store region -verify %s
+
+// test to see if nullptr is detected as a null pointer
+void foo1(void) {
+ char *np = nullptr;
+ *np = 0; // expected-warning{{Dereference of null pointer}}
+}
+
+// check if comparing nullptr to nullptr is detected properly
+void foo2(void) {
+ char *np1 = nullptr;
+ char *np2 = np1;
+ char c;
+ if (np1 == np2)
+ np1 = &c;
+ *np1 = 0; // no-warning
+}
+
+// invoving a nullptr in a more complex operation should be cause a warning
+void foo3(void) {
+ struct foo {
+ int a, f;
+ };
+ char *np = nullptr;
+ // casting a nullptr to anything should be caught eventually
+ int *ip = &(((struct foo *)np)->f);
+ *ip = 0; // expected-warning{{Dereference of null pointer}}
+ // should be error here too, but analysis gets stopped
+// *np = 0;
+}
+
+// nullptr is implemented as a zero integer value, so should be able to compare
+void foo4(void) {
+ char *np = nullptr;
+ if (np != 0)
+ *np = 0; // no-warning
+ char *cp = 0;
+ if (np != cp)
+ *np = 0; // no-warning
+}
+
diff --git a/test/Analysis/operator-calls.cpp b/test/Analysis/operator-calls.cpp
index 97d54226f055..766d16140ed0 100644
--- a/test/Analysis/operator-calls.cpp
+++ b/test/Analysis/operator-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-experimental-checks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -verify %s
struct X0 { };
bool operator==(const X0&, const X0&);
diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c
index b8d6e442ff57..8c65b478f1c2 100644
--- a/test/Analysis/out-of-bounds.c
+++ b/test/Analysis/out-of-bounds.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-check-objc-mem -analyzer-check-buffer-overflows -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,security.experimental.ArrayBoundV2 -verify %s
// Tests doing an out-of-bounds access after the end of an array using:
// - constant integer index
@@ -146,3 +146,12 @@ void test4(int x) {
if (x > 99)
buf[x] = 1;
}
+
+// Don't warn when indexing below the start of a symbolic region's whose
+// base extent we don't know.
+int *get_symbolic();
+void test_index_below_symboloc() {
+ int *buf = get_symbolic();
+ buf[-1] = 0; // no-warning;
+}
+
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 4508198b5292..891719c1932f 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core.experimental -analyzer-experimental-checks -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,unix.experimental,security.experimental.ArrayBound -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c
index ce0f1ac9abe6..1b1f9e1c0169 100644
--- a/test/Analysis/override-werror.c
+++ b/test/Analysis/override-werror.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -Werror %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -Werror %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -Werror %s -analyzer-store=basic -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -Werror %s -analyzer-store=region -verify
// This test case illustrates that using '-analyze' overrides the effect of
// -Werror. This allows basic warnings not to interfere with producing
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index 7b8c2673b085..a7e3c3cfe48a 100644
--- a/test/Analysis/plist-output-alternate.m
+++ b/test/Analysis/plist-output-alternate.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
void test_null_init(void) {
int *p = 0;
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index 2224a2fbb859..224f5194765e 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
// XFAIL: *
void test_null_init(void) {
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index 9ce07edcb02b..1e0fd32fcd03 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
// This test case was crashing due to how CFRefCount.cpp resolved the
// ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr.
diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m
index 46b7fd36a64a..73218d8bc80e 100644
--- a/test/Analysis/pr_2542_rdar_6793404.m
+++ b/test/Analysis/pr_2542_rdar_6793404.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -pedantic -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -pedantic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -pedantic -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -pedantic -analyzer-store=region -verify %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/pr_4164.c b/test/Analysis/pr_4164.c
index ee5d4028e7d3..c58c8abe3f67 100644
--- a/test/Analysis/pr_4164.c
+++ b/test/Analysis/pr_4164.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
// PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164
//
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index ce8faf52736a..ad9db1ad6818 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index fe378957531b..502de6c3ef9a 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.FixedAddr,core.experimental.PointerArithm,core.experimental.PointerSub -analyzer-check-objc-mem -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.FixedAddr,core.experimental.PointerArithm,core.experimental.PointerSub -analyzer-check-objc-mem -analyzer-store=region -verify -triple i686-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.FixedAddr,core.experimental.PointerArithm,core.experimental.PointerSub -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.FixedAddr,core.experimental.PointerArithm,core.experimental.PointerSub -analyzer-store=region -verify -triple i686-apple-darwin9 %s
// Used to trigger warnings for unreachable paths.
#define WARN do { int a, b; int c = &b-&a; } while (0)
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index 086cdd8d51b0..d576eae8f652 100644
--- a/test/Analysis/rdar-6442306-1.m
+++ b/test/Analysis/rdar-6442306-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=basic -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental %s -analyzer-store=region -verify
typedef int bar_return_t;
typedef struct {
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
index 7ce73bc48da0..4c70dbc0758f 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=core.DeadStores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-checker=deadcode.DeadStores -verify %s
//
// This test exercises the live variables analysis (LiveVariables.cpp).
// The case originally identified a non-termination bug.
diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c
index d8d1e996a5fa..5555b018578f 100644
--- a/test/Analysis/rdar-6541136-region.c
+++ b/test/Analysis/rdar-6541136-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region %s
+// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,security.experimental.ArrayBound -analyzer-store=region %s
struct tea_cheese { unsigned magic; };
typedef struct tea_cheese kernel_tea_cheese_t;
diff --git a/test/Analysis/rdar-6541136.c b/test/Analysis/rdar-6541136.c
index a175497fcba6..095aefadb8ce 100644
--- a/test/Analysis/rdar-6541136.c
+++ b/test/Analysis/rdar-6541136.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic %s
+// RUN: %clang_cc1 -verify -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic %s
struct tea_cheese { unsigned magic; };
typedef struct tea_cheese kernel_tea_cheese_t;
diff --git a/test/Analysis/rdar-6562655.m b/test/Analysis/rdar-6562655.m
index 19b2697b3831..1e0998aa974e 100644
--- a/test/Analysis/rdar-6562655.m
+++ b/test/Analysis/rdar-6562655.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region -verify %s
//
// This test case mainly checks that the retain/release checker doesn't crash
// on this file.
diff --git a/test/Analysis/rdar-6582778-basic-store.c b/test/Analysis/rdar-6582778-basic-store.c
index a545d8b6ac70..0642b64cd7fd 100644
--- a/test/Analysis/rdar-6582778-basic-store.c
+++ b/test/Analysis/rdar-6582778-basic-store.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
typedef const void * CFTypeRef;
typedef double CFTimeInterval;
diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
index 4932a526fc4c..03b2656c7ee6 100644
--- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
+++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=basic %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-constraints=basic -analyzer-store=region %s -verify
typedef struct Foo { int x; } Bar;
diff --git a/test/Analysis/rdar-7168531.m b/test/Analysis/rdar-7168531.m
index 8225cd36539f..b2b66b279296 100644
--- a/test/Analysis/rdar-7168531.m
+++ b/test/Analysis/rdar-7168531.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=region %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=basic %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -triple i386-apple-darwin10 -analyzer-store=region %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -triple i386-apple-darwin10 -analyzer-store=basic %s
// Note that the target triple is important for this test case. It specifies that we use the
// fragile Objective-C ABI.
diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m
index 4fe6d19f1cbf..8e99f3409b81 100644
--- a/test/Analysis/refcnt_naming.m
+++ b/test/Analysis/refcnt_naming.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
typedef const struct __CFString * CFStringRef;
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index b01d70825a1f..3422b58d3fe8 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -analyzer-constraints=range -verify %s
typedef typeof(sizeof(int)) size_t;
void malloc (size_t);
diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m
index 7770d29cfab9..7f4cd26e405e 100644
--- a/test/Analysis/region-1.m
+++ b/test/Analysis/region-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-store=region -verify %s
//
// This test case simply should not crash. It evaluates the logic of not
// using MemRegion::getRValueType in incorrect places.
diff --git a/test/Analysis/retain-release-basic-store.m b/test/Analysis/retain-release-basic-store.m
index 8c05efef66ee..7fd17ffb995f 100644
--- a/test/Analysis/retain-release-basic-store.m
+++ b/test/Analysis/retain-release-basic-store.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index 7d7c58fbcd51..cbf00a27721d 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=cocoa.NSAutoreleasePool -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=cocoa.NSAutoreleasePool -analyzer-check-objc-mem -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSAutoreleasePool -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
//===----------------------------------------------------------------------===//
// Header stuff.
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index ec765e3fe809..ac2362a4a73c 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-max-loop 6 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-max-loop 6 -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 5cc29b0f866b..6782c90375f6 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=macosx.CFRetainRelease,cocoa.ClassRelease -analyzer-check-objc-mem -analyzer-store=basic -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=macosx.CFRetainRelease,cocoa.ClassRelease -analyzer-check-objc-mem -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=basic -fblocks -verify -x objective-c++ %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify -x objective-c++ %s
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
@@ -910,7 +912,7 @@ void IOServiceAddMatchingNotification_wrapper(IONotificationPortRef notifyPort,
// Test of handling objects whose references "escape" to containers.
//===----------------------------------------------------------------------===//
-void CFDictionaryAddValue();
+void CFDictionaryAddValue(CFMutableDictionaryRef, void *, void *);
// <rdar://problem/6539791>
void rdar_6539791(CFMutableDictionaryRef y, void* key, void* val_key) {
@@ -920,9 +922,9 @@ void rdar_6539791(CFMutableDictionaryRef y, void* key, void* val_key) {
signed z = 1;
CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);
if (value) {
- CFDictionaryAddValue(x, val_key, value); // no-warning
+ CFDictionaryAddValue(x, val_key, (void*)value); // no-warning
CFRelease(value);
- CFDictionaryAddValue(y, val_key, value); // no-warning
+ CFDictionaryAddValue(y, val_key, (void*)value); // no-warning
}
}
@@ -1013,8 +1015,8 @@ typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t;
typedef __darwin_pthread_t pthread_t;
typedef __darwin_pthread_attr_t pthread_attr_t;
-int pthread_create(pthread_t * restrict, const pthread_attr_t * restrict,
- void *(*)(void *), void * restrict);
+int pthread_create(pthread_t *, const pthread_attr_t *,
+ void *(*)(void *), void *);
void *rdar_7299394_start_routine(void *p) {
[((id) p) release];
@@ -1435,7 +1437,6 @@ extern const void *CFDictionaryGetValue(CFDictionaryRef theDict, const void *key
typedef struct __CFError * CFErrorRef;
extern const CFStringRef kCFErrorUnderlyingErrorKey;
extern CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err);
-
static void rdar_8724287(CFErrorRef error)
{
CFErrorRef error_to_dump;
@@ -1444,7 +1445,7 @@ static void rdar_8724287(CFErrorRef error)
while (error_to_dump != ((void*)0)) {
CFDictionaryRef info;
- info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1447 and stored into 'info'}}
+ info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line 1448 and stored into 'info'}}
if (info != ((void*)0)) {
}
@@ -1453,3 +1454,10 @@ static void rdar_8724287(CFErrorRef error)
}
}
+// <rdar://problem/9234108> - Make sure the model applies cf_consumed
+// correctly in argument positions besides the first.
+extern void *CFStringCreate(void);
+extern void rdar_9234108_helper(void *key, void * CF_CONSUMED value);
+void rdar_9234108() {
+ rdar_9234108_helper(0, CFStringCreate());
+}
diff --git a/test/Analysis/security-syntax-checks-no-emit.c b/test/Analysis/security-syntax-checks-no-emit.c
index f129e8a8e5ac..4e37c44247c2 100644
--- a/test/Analysis/security-syntax-checks-no-emit.c
+++ b/test/Analysis/security-syntax-checks-no-emit.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=core.experimental.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
// This file complements 'security-syntax-checks.m', but tests that we omit
// specific checks on platforms where they don't make sense.
diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m
index bac6ee89df90..160dcf657387 100644
--- a/test/Analysis/security-syntax-checks.m
+++ b/test/Analysis/security-syntax-checks.m
@@ -1,4 +1,16 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.experimental.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DVARIANT -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.experimental.SecuritySyntactic %s -verify
+
+#ifdef USE_BUILTINS
+# define BUILTIN(f) __builtin_ ## f
+#else /* USE_BUILTINS */
+# define BUILTIN(f) f
+#endif /* USE_BUILTINS */
+
+typedef typeof(sizeof(int)) size_t;
+
// <rdar://problem/6336718> rule request: floating point used as loop
// condition (FLP30-C, FLP-30-CPP)
@@ -103,3 +115,52 @@ char *mktemp(char *buf);
void test_mktemp() {
char *x = mktemp("/tmp/zxcv"); // expected-warning{{Call to function 'mktemp' is insecure as it always creates or uses insecure temporary file}}
}
+
+
+//===----------------------------------------------------------------------===
+// strcpy()
+//===----------------------------------------------------------------------===
+#ifdef VARIANT
+
+#define __strcpy_chk BUILTIN(__strcpy_chk)
+char *__strcpy_chk(char *restrict s1, const char *restrict s2, size_t destlen);
+
+#define strcpy(a,b) __strcpy_chk(a,b,(size_t)-1)
+
+#else /* VARIANT */
+
+#define strcpy BUILTIN(strcpy)
+char *strcpy(char *restrict s1, const char *restrict s2);
+
+#endif /* VARIANT */
+
+void test_strcpy() {
+ char x[4];
+ char *y;
+
+ strcpy(x, y); //expected-warning{{Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strncpy'. CWE-119.}}
+}
+
+//===----------------------------------------------------------------------===
+// strcat()
+//===----------------------------------------------------------------------===
+#ifdef VARIANT
+
+#define __strcat_chk BUILTIN(__strcat_chk)
+char *__strcat_chk(char *restrict s1, const char *restrict s2, size_t destlen);
+
+#define strcat(a,b) __strcat_chk(a,b,(size_t)-1)
+
+#else /* VARIANT */
+
+#define strcat BUILTIN(strcat)
+char *strcat(char *restrict s1, const char *restrict s2);
+
+#endif /* VARIANT */
+
+void test_strcat() {
+ char x[4];
+ char *y;
+
+ strcat(x, y); //expected-warning{{Call to function 'strcat' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strncat'. CWE-119.}}
+}
diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m
index b8c2c3e8d984..92006a6d2459 100644
--- a/test/Analysis/self-init.m
+++ b/test/Analysis/self-init.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=cocoa.SelfInit %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.experimental.SelfInit %s -verify
@class NSZone, NSCoder;
@protocol NSObject
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
index 8e7e7dfd9a40..bf2a4fa4e13c 100644
--- a/test/Analysis/stack-addr-ps.c
+++ b/test/Analysis/stack-addr-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=core.StackAddrEscape -analyzer-store=basic -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=core.StackAddrEscape -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
int* f1() {
int x = 0;
diff --git a/test/Analysis/stackaddrleak.c b/test/Analysis/stackaddrleak.c
index f19eddc811e8..ada0cc106905 100644
--- a/test/Analysis/stackaddrleak.c
+++ b/test/Analysis/stackaddrleak.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=core.StackAddrEscape -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
char const *p;
diff --git a/test/Analysis/stream.c b/test/Analysis/stream.c
index 7dfd49b39dc0..2f372e755153 100644
--- a/test/Analysis/stream.c
+++ b/test/Analysis/stream.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-checker=unix.experimental.Stream -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.experimental.Stream -analyzer-store region -verify %s
typedef __typeof__(sizeof(int)) size_t;
typedef struct _IO_FILE FILE;
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index 756115180cab..19c838c25564 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core.experimental.CString,core.experimental.UnreachableCode -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,cplusplus.experimental.CString,deadcode.experimental.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -15,7 +15,7 @@
// Some functions are implemented as builtins. These should be #defined as
// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined.
-// Functions that have variants and are also availabe as builtins should be
+// Functions that have variants and are also available as builtins should be
// declared carefully! See memcpy() for an example.
#ifdef USE_BUILTINS
@@ -68,7 +68,7 @@ label:
}
void strlen_subregion() {
- struct two_strings { char a[2], b[2] };
+ struct two_strings { char a[2], b[2]; };
extern void use_two_strings(struct two_strings *);
struct two_strings z;
@@ -200,7 +200,7 @@ label:
}
void strnlen_subregion() {
- struct two_stringsn { char a[2], b[2] };
+ struct two_stringsn { char a[2], b[2]; };
extern void use_two_stringsn(struct two_stringsn *);
struct two_stringsn z;
@@ -438,3 +438,437 @@ void stpcpy_no_overflow(char *y) {
if (strlen(y) == 3)
stpcpy(x, y); // no-warning
}
+
+//===----------------------------------------------------------------------===
+// strcat()
+//===----------------------------------------------------------------------===
+
+#ifdef VARIANT
+
+#define __strcat_chk BUILTIN(__strcat_chk)
+char *__strcat_chk(char *restrict s1, const char *restrict s2, size_t destlen);
+
+#define strcat(a,b) __strcat_chk(a,b,(size_t)-1)
+
+#else /* VARIANT */
+
+#define strcat BUILTIN(strcat)
+char *strcat(char *restrict s1, const char *restrict s2);
+
+#endif /* VARIANT */
+
+
+void strcat_null_dst(char *x) {
+ strcat(NULL, x); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcat_null_src(char *x) {
+ strcat(x, NULL); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcat_fn(char *x) {
+ strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to byte string function is the address of the function 'strcat_fn', which is not a null-terminated string}}
+}
+
+void strcat_effects(char *y) {
+ char x[8] = "123";
+ size_t orig_len = strlen(x);
+ char a = x[0];
+
+ if (strlen(y) != 4)
+ return;
+
+ if (strcat(x, y) != x)
+ (void)*(char*)0; // no-warning
+
+ if ((int)strlen(x) != (orig_len + strlen(y)))
+ (void)*(char*)0; // no-warning
+
+ if (a != x[0])
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strcat_overflow_0(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 4)
+ strcat(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strcat_overflow_1(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 3)
+ strcat(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strcat_overflow_2(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 2)
+ strcat(x, y); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strcat_no_overflow(char *y) {
+ char x[5] = "12";
+ if (strlen(y) == 2)
+ strcat(x, y); // no-warning
+}
+
+
+//===----------------------------------------------------------------------===
+// strncat()
+//===----------------------------------------------------------------------===
+
+#ifdef VARIANT
+
+#define __strncat_chk BUILTIN(__strncat_chk)
+char *__strncat_chk(char *restrict s1, const char *restrict s2, size_t n, size_t destlen);
+
+#define strncat(a,b,c) __strncat_chk(a,b,c, (size_t)-1)
+
+#else /* VARIANT */
+
+#define strncat BUILTIN(strncat)
+char *strncat(char *restrict s1, const char *restrict s2, size_t n);
+
+#endif /* VARIANT */
+
+
+void strncat_null_dst(char *x) {
+ strncat(NULL, x, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncat_null_src(char *x) {
+ strncat(x, NULL, 4); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncat_fn(char *x) {
+ strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to byte string function is the address of the function 'strncat_fn', which is not a null-terminated string}}
+}
+
+void strncat_effects(char *y) {
+ char x[8] = "123";
+ size_t orig_len = strlen(x);
+ char a = x[0];
+
+ if (strlen(y) != 4)
+ return;
+
+ if (strncat(x, y, strlen(y)) != x)
+ (void)*(char*)0; // no-warning
+
+ if (strlen(x) != orig_len + strlen(y))
+ (void)*(char*)0; // no-warning
+
+ if (a != x[0])
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
+void strncat_overflow_0(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 4)
+ strncat(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strncat_overflow_1(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 3)
+ strncat(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strncat_overflow_2(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 2)
+ strncat(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
+}
+
+void strncat_overflow_3(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 4)
+ strncat(x, y, 2); // expected-warning{{Byte string function overflows destination buffer}}
+}
+void strncat_no_overflow_1(char *y) {
+ char x[5] = "12";
+ if (strlen(y) == 2)
+ strncat(x, y, strlen(y)); // no-warning
+}
+
+void strncat_no_overflow_2(char *y) {
+ char x[4] = "12";
+ if (strlen(y) == 4)
+ strncat(x, y, 1); // no-warning
+}
+
+//===----------------------------------------------------------------------===
+// strcmp()
+//===----------------------------------------------------------------------===
+
+#define strcmp BUILTIN(strcmp)
+int strcmp(const char *restrict s1, const char *restrict s2);
+
+void strcmp_constant0() {
+ if (strcmp("123", "123") != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_constant_and_var_0() {
+ char *x = "123";
+ if (strcmp(x, "123") != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_constant_and_var_1() {
+ char *x = "123";
+ if (strcmp("123", x) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_0() {
+ char *x = "123";
+ char *y = "123";
+ if (strcmp(x, y) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_1() {
+ char *x = "234";
+ char *y = "123";
+ if (strcmp(x, y) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_2() {
+ char *x = "123";
+ char *y = "234";
+ if (strcmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_null_0() {
+ char *x = NULL;
+ char *y = "123";
+ strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcmp_null_1() {
+ char *x = "123";
+ char *y = NULL;
+ strcmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcmp_diff_length_0() {
+ char *x = "12345";
+ char *y = "234";
+ if (strcmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_diff_length_1() {
+ char *x = "123";
+ char *y = "23456";
+ if (strcmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_diff_length_2() {
+ char *x = "12345";
+ char *y = "123";
+ if (strcmp(x, y) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcmp_diff_length_3() {
+ char *x = "123";
+ char *y = "12345";
+ if (strcmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+//===----------------------------------------------------------------------===
+// strncmp()
+//===----------------------------------------------------------------------===
+
+#define strncmp BUILTIN(strncmp)
+int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
+
+void strncmp_constant0() {
+ if (strncmp("123", "123", 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_constant_and_var_0() {
+ char *x = "123";
+ if (strncmp(x, "123", 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_constant_and_var_1() {
+ char *x = "123";
+ if (strncmp("123", x, 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_0() {
+ char *x = "123";
+ char *y = "123";
+ if (strncmp(x, y, 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_1() {
+ char *x = "234";
+ char *y = "123";
+ if (strncmp(x, y, 3) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_2() {
+ char *x = "123";
+ char *y = "234";
+ if (strncmp(x, y, 3) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_null_0() {
+ char *x = NULL;
+ char *y = "123";
+ strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncmp_null_1() {
+ char *x = "123";
+ char *y = NULL;
+ strncmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncmp_diff_length_0() {
+ char *x = "12345";
+ char *y = "234";
+ if (strncmp(x, y, 5) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_diff_length_1() {
+ char *x = "123";
+ char *y = "23456";
+ if (strncmp(x, y, 5) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_diff_length_2() {
+ char *x = "12345";
+ char *y = "123";
+ if (strncmp(x, y, 5) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_diff_length_3() {
+ char *x = "123";
+ char *y = "12345";
+ if (strncmp(x, y, 5) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_diff_length_4() {
+ char *x = "123";
+ char *y = "12345";
+ if (strncmp(x, y, 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_diff_length_5() {
+ char *x = "012";
+ char *y = "12345";
+ if (strncmp(x, y, 3) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncmp_diff_length_6() {
+ char *x = "234";
+ char *y = "12345";
+ if (strncmp(x, y, 3) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+//===----------------------------------------------------------------------===
+// strcasecmp()
+//===----------------------------------------------------------------------===
+
+#define strcasecmp BUILTIN(strcasecmp)
+int strcasecmp(const char *restrict s1, const char *restrict s2);
+
+void strcasecmp_constant0() {
+ if (strcasecmp("abc", "Abc") != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_constant_and_var_0() {
+ char *x = "abc";
+ if (strcasecmp(x, "Abc") != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_constant_and_var_1() {
+ char *x = "abc";
+ if (strcasecmp("Abc", x) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_0() {
+ char *x = "abc";
+ char *y = "Abc";
+ if (strcasecmp(x, y) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_1() {
+ char *x = "Bcd";
+ char *y = "abc";
+ if (strcasecmp(x, y) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_2() {
+ char *x = "abc";
+ char *y = "Bcd";
+ if (strcasecmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_null_0() {
+ char *x = NULL;
+ char *y = "123";
+ strcasecmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcasecmp_null_1() {
+ char *x = "123";
+ char *y = NULL;
+ strcasecmp(x, y); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strcasecmp_diff_length_0() {
+ char *x = "abcde";
+ char *y = "aBd";
+ if (strcasecmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_diff_length_1() {
+ char *x = "abc";
+ char *y = "aBdef";
+ if (strcasecmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_diff_length_2() {
+ char *x = "aBcDe";
+ char *y = "abc";
+ if (strcasecmp(x, y) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strcasecmp_diff_length_3() {
+ char *x = "aBc";
+ char *y = "abcde";
+ if (strcasecmp(x, y) != -1)
+ (void)*(char*)0; // no-warning
+}
diff --git a/test/Analysis/undef-buffers.c b/test/Analysis/undef-buffers.c
index 27c3b8df8411..df124b10d10e 100644
--- a/test/Analysis/undef-buffers.c
+++ b/test/Analysis/undef-buffers.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.experimental,core.uninitialized -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m
index a8e2f1b65592..743d36ff56de 100644
--- a/test/Analysis/uninit-msg-expr.m
+++ b/test/Analysis/uninit-msg-expr.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m
index ccaf2e8105bf..f1794068d5e1 100644
--- a/test/Analysis/uninit-ps-rdar6145427.m
+++ b/test/Analysis/uninit-ps-rdar6145427.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -verify -analyzer-store=basic -analyzer-check-objc-mem %s
-// RUN: %clang_cc1 -analyze -verify -analyzer-store=region -analyzer-check-objc-mem %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=basic %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=region %s
// Delta-Debugging reduced preamble.
typedef signed char BOOL;
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index 2b3b027657f6..1700f54dbfb0 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-checker=core.experimental.IdempotentOps -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,deadcode.IdempotentOperations -verify %s
struct s {
int data;
diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c
index 9e53fbc34881..915961aa11da 100644
--- a/test/Analysis/uninit-vals-ps.c
+++ b/test/Analysis/uninit-vals-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
struct FPRec {
void (*my_func)(int * x);
diff --git a/test/Analysis/uninit-vals.c b/test/Analysis/uninit-vals.c
deleted file mode 100644
index e4395e848661..000000000000
--- a/test/Analysis/uninit-vals.c
+++ /dev/null
@@ -1,53 +0,0 @@
-// RUN: %clang_cc1 -analyze -warn-uninit-values -verify %s
-
-int f1() {
- int x;
- return x; // expected-warning {{use of uninitialized variable}}
-}
-
-int f2(int x) {
- int y;
- int z = x + y; // expected-warning {{use of uninitialized variable}}
- return z;
-}
-
-
-int f3(int x) {
- int y;
- return x ? 1 : y; // expected-warning {{use of uninitialized variable}}
-}
-
-int f4(int x) {
- int y;
- if (x) y = 1;
- return y; // expected-warning {{use of uninitialized variable}}
-}
-
-void f5() {
- int a;
- a = 30; // no-warning
-}
-
-void f6(int i) {
- int x;
- for (i = 0 ; i < 10; i++)
- printf("%d",x++); // expected-warning {{use of uninitialized variable}} \
- // expected-warning{{implicitly declaring C library function 'printf' with type 'int (const char *, ...)'}} \
- // expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
-}
-
-void f7(int i) {
- int x = i;
- int y;
- for (i = 0; i < 10; i++ ) {
- printf("%d",x++); // no-warning
- x += y; // expected-warning {{use of uninitialized variable}}
- }
-}
-
-int f8(int j) {
- int x = 1, y = x + 1;
- if (y) // no-warning
- return x;
- return y;
-}
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 2f7f29c5d9e4..2cd5e0c11848 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/unions-region.m b/test/Analysis/unions-region.m
index 180faf8fd72d..1a716847186f 100644
--- a/test/Analysis/unions-region.m
+++ b/test/Analysis/unions-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range %s -verify
//===-- unions-region.m ---------------------------------------------------===//
//
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index 656a1c9c1340..5df6b37bb91a 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem -analyzer-checker=unix.API,macosx.API %s -analyzer-store=region -fblocks -verify
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem -analyzer-checker=unix.API,macosx.API %s -analyzer-store=basic -fblocks -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=unix.API,osx.API %s -analyzer-store=region -fblocks -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=unix.API,osx.API %s -analyzer-store=basic -fblocks -verify
struct _opaque_pthread_once_t {
long __sig;
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
index 6ae0822c7344..7df52402e735 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core.DeadStores,core.experimental.UnreachableCode -analyzer-check-objc-mem -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.experimental.UnreachableCode -verify -analyzer-opt-analyze-nested-blocks -Wno-unused-value %s
extern void foo(int a);
diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m
index b43ae18694dd..931c84a3745a 100644
--- a/test/Analysis/unused-ivars.m
+++ b/test/Analysis/unused-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -analyze -analyzer-checker=cocoa.UnusedIvars %s -verify
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -analyze -analyzer-checker=osx.cocoa.UnusedIvars %s -verify
//===--- BEGIN: Delta-debugging reduced headers. --------------------------===//
diff --git a/test/Analysis/variadic-method-types.m b/test/Analysis/variadic-method-types.m
new file mode 100644
index 000000000000..018956ab1b2d
--- /dev/null
+++ b/test/Analysis/variadic-method-types.m
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.VariadicMethodTypes -analyzer-store=basic -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.VariadicMethodTypes -analyzer-store=region -fblocks -verify %s
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from
+// Foundation.h (Mac OS X).
+//
+// It includes the basic definitions for the test cases below.
+// Not directly including Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+#define nil (void*)0
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kCGImageSourceShouldCache __attribute__((visibility("default")));
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+typedef unsigned int NSUInteger;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (oneway void)release;
+- (id)retain;
+- (id)autorelease;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@class NSCoder;
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
+@end
+typedef struct {} NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+@end
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+@end
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+@end
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjectsAndKeys:(id)firstObject, ... __attribute__((sentinel(0,1)));
+@end
+@interface NSSet : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+@end
+@interface NSSet (NSSetCreation)
++ (id)setWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+@end
+@protocol P;
+@class C;
+
+typedef struct FooType * __attribute__ ((NSObject)) FooType;
+typedef struct BarType * BarType;
+
+
+void f(id a, id<P> b, C* c, C<P> *d, FooType fooType, BarType barType) {
+ [NSArray arrayWithObjects:@"Hello", a, b, c, d, nil];
+ [NSArray arrayWithObjects:@"Foo", ^{}, nil];
+
+ [NSArray arrayWithObjects:@"Foo", "Bar", "Baz", nil]; // expected-warning 2 {{Argument to 'NSArray' method 'arrayWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+ [NSDictionary dictionaryWithObjectsAndKeys:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSDictionary' method 'dictionaryWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}}
+ [NSSet setWithObjects:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSSet' method 'setWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+
+ [[[NSArray alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+ [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}}
+ [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", (void*) 0, nil] autorelease]; // no-warning
+ [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", kCGImageSourceShouldCache, nil] autorelease]; // no-warning
+ [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", fooType, nil] autorelease]; // no-warning
+ [[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", barType, nil] autorelease]; // expected-warning {{Argument to method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'BarType'}}
+ [[[NSSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+}
+
+// This previously crashed the variadic argument checker.
+@protocol RDar9273215
+- (void)rdar9273215:(id)x, ...;
+@end
+
+void test_rdar9273215(id<RDar9273215> y) {
+ return [y rdar9273215:y, y];
+}
+
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
index 0c905fbf325d..cee7c0242033 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
@@ -17,7 +17,7 @@ namespace M {
struct Y : N::X { };
}
-void f();
+void f(); // expected-note 2 {{'f' declared here}}
void test_operator_adl(N::X x, M::Y y) {
(void)(x + x);
diff --git a/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp b/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
new file mode 100644
index 000000000000..d930f97ce791
--- /dev/null
+++ b/test/CXX/basic/basic.scope/basic.scope.local/p4-0x.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+void f() {
+ int b;
+ int arr[] = {1, 2, 3};
+
+ if (bool b = true) // expected-note 2{{previous definition}}
+ bool b; // expected-error {{redefinition}}
+ else
+ int b; // expected-error {{redefinition}}
+ while (bool b = true) // expected-note {{previous definition}}
+ int b; // expected-error {{redefinition}}
+ for (int c; // expected-note 2{{previous definition}}
+ bool c = true;) // expected-error {{redefinition}}
+ double c; // expected-error {{redefinition}}
+ switch (int n = 37 + 5) // expected-note {{previous definition}}
+ int n; // expected-error {{redefinition}}
+ for (int a : arr) // expected-note {{previous definition}}
+ int a = 0; // expected-error {{redefinition}}
+
+ if (bool b = true) { // expected-note 2{{previous definition}}
+ int b; // expected-error {{redefinition}}
+ } else {
+ int b; // expected-error {{redefinition}}
+ }
+ while (bool b = true) { // expected-note {{previous definition}}
+ int b; // expected-error {{redefinition}}
+ }
+ for (int c; // expected-note 2{{previous definition}}
+ bool c = true;) { // expected-error {{redefinition}}
+ double c; // expected-error {{redefinition}}
+ }
+ switch (int n = 37 + 5) { // expected-note {{previous definition}}
+ int n; // expected-error {{redefinition}}
+ }
+ for (int &a : arr) { // expected-note {{previous definition}}
+ int a = 0; // expected-error {{redefinition}}
+ }
+
+ if (bool b = true) {{ // expected-note {{previous definition}}
+ bool b;
+ }} else {
+ int b; // expected-error {{redefinition}}
+ }
+ if (bool b = true) { // expected-note {{previous definition}}
+ bool b; // expected-error {{redefinition}}
+ } else {{
+ int b;
+ }}
+ if (bool b = true) {{
+ bool b;
+ }} else {{
+ int b;
+ }}
+ while (bool b = true) {{
+ int b;
+ }}
+ for (int c; // expected-note {{previous definition}}
+ bool c = true; ) {{ // expected-error {{redefinition}}
+ double c;
+ }}
+ switch (int n = 37 + 5) {{
+ int n;
+ }}
+ for (int &a : arr) {{
+ int a = 0;
+ }}
+}
diff --git a/test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp b/test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp
new file mode 100644
index 000000000000..751c0df6b867
--- /dev/null
+++ b/test/CXX/basic/basic.scope/basic.scope.pdecl/p3.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// Classes.
+namespace Class {
+ namespace NS {
+ class C {}; // expected-note {{candidate}}
+ }
+ using namespace NS;
+ class C : C {}; // expected-error {{reference to 'C' is ambiguous}} \
+ expected-note {{candidate}}
+}
+
+// Enumerations.
+enum E {
+ EPtrSize = sizeof((E*)0) // ok, E is already declared
+};
+
+// Alias declarations. clang implements the proposed resolution to N1044.
+namespace Alias {
+ namespace NS {
+ class C;
+ }
+ using namespace NS;
+ using C = C; // ok, C = B::C
+ using C = NS::C; // ok, same type
+}
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
index 37a4f976bada..47b51585556f 100644
--- a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
+++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fexceptions -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
int *use_new(int N) {
if (N == 1)
return new int;
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 84b7b1915f17..4228a44fc122 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
// C++0x [class.access]p4:
diff --git a/test/CXX/class.derived/p8-0x.cpp b/test/CXX/class.derived/p8-0x.cpp
deleted file mode 100644
index 6a667f73ec3f..000000000000
--- a/test/CXX/class.derived/p8-0x.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++0x
-
-namespace Test1 {
-
-struct A {
- virtual void f(); // expected-note {{overridden virtual function is here}}
-};
-
-struct B explicit : A {
- virtual void f(); // expected-error {{overrides function without being marked 'override'}}
-};
-
-struct C {
- virtual ~C();
-};
-
-struct D explicit : C {
- virtual ~D();
-};
-
-}
-
diff --git a/test/CXX/class/class.mem/p2.cpp b/test/CXX/class/class.mem/p2.cpp
new file mode 100644
index 000000000000..09040d859c80
--- /dev/null
+++ b/test/CXX/class/class.mem/p2.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++11 [class.mem]p2:
+// A class is considered a completely-defined object type (or
+// complete type) at the closing } of the class-specifier. Within
+// the class member-specification, the class is regarded as complete
+// within function bodies, default arguments,
+// exception-specifications, and brace-or-equal-initializers for
+// non-static data members (including such things in nested classes).
+// Otherwise it is regarded as incomplete within its own class
+// member-specification.
+
+namespace test0 {
+ struct A { // expected-note {{definition of 'test0::A' is not complete until the closing '}'}}
+ A x; // expected-error {{field has incomplete type 'test0::A'}}
+ };
+}
+
+namespace test1 {
+ template <class T> struct A {
+ A<int> x; // expected-error {{implicit instantiation of template 'test1::A<int>' within its own definition}}
+ };
+}
+
+namespace test2 {
+ template <class T> struct A;
+ template <> struct A<int> {};
+ template <class T> struct A {
+ A<int> x;
+ };
+}
diff --git a/test/CXX/class/class.mem/p8-0x-pedantic.cpp b/test/CXX/class/class.mem/p8-0x-pedantic.cpp
deleted file mode 100644
index a4b775c191d8..000000000000
--- a/test/CXX/class/class.mem/p8-0x-pedantic.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++0x -pedantic -verify %s
-
-namespace inline_extension {
- struct Base1 {
- virtual void f() {}
- };
-
- struct B : Base1 {
- virtual void f() override {} // expected-warning {{'override' keyword only allowed in declarations, allowed as an extension}}
- virtual void g() final {} // expected-warning {{'final' keyword only allowed in declarations, allowed as an extension}}
- virtual void h() new {} // expected-warning {{'new' keyword only allowed in declarations, allowed as an extension}}
- };
-}
-
diff --git a/test/CXX/class/class.mem/p8-0x.cpp b/test/CXX/class/class.mem/p8-0x.cpp
index bf1b4c177bf8..836ebad48ee1 100644
--- a/test/CXX/class/class.mem/p8-0x.cpp
+++ b/test/CXX/class/class.mem/p8-0x.cpp
@@ -5,7 +5,6 @@ struct Base1 {
};
struct A : Base1 {
- virtual void f() new new; // expected-error {{class member already marked 'new'}}
virtual void g() override override; // expected-error {{class member already marked 'override'}}
virtual void h() final final; // expected-error {{class member already marked 'final'}}
};
@@ -34,7 +33,6 @@ namespace inline_extension {
};
struct A : Base1 {
- virtual void f() new new {} // expected-error {{class member already marked 'new'}}
virtual void g() override override {} // expected-error {{class member already marked 'override'}}
virtual void h() final final {} // expected-error {{class member already marked 'final'}}
};
diff --git a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
index c81e4ef1b1b8..9116e7146f81 100644
--- a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
+++ b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
@@ -35,17 +35,22 @@ namespace test1 {
struct A {
void foo(Opaque1); // expected-note {{candidate}}
void foo(Opaque2); // expected-note {{candidate}}
- void test();
};
struct B : A {
-
+ void test();
};
- void A::test() {
- B::foo(Opaque1());
- B::foo(Opaque2());
- B::foo(Opaque3()); // expected-error {{no matching member function}}
+ struct C1 : A { };
+ struct C2 : B { };
+
+ void B::test() {
+ A::foo(Opaque1());
+ A::foo(Opaque2());
+ A::foo(Opaque3()); // expected-error {{no matching member function}}
+
+ C1::foo(Opaque1()); // expected-error {{call to non-static member function without an object argument}}
+ C2::foo(Opaque1()); // expected-error {{call to non-static member function without an object argument}}
}
}
diff --git a/test/CXX/class/class.union/p1.cpp b/test/CXX/class/class.union/p1.cpp
index b5dd4dfd705d..011185fb49e4 100644
--- a/test/CXX/class/class.union/p1.cpp
+++ b/test/CXX/class/class.union/p1.cpp
@@ -7,30 +7,30 @@ class Okay {
};
class Virtual {
- virtual void foo() { abort(); } // expected-note 3 {{because type 'Virtual' has a virtual member function}}
+ virtual void foo() { abort(); } // expected-note 4 {{because type 'Virtual' has a virtual member function}}
};
-class VirtualBase : virtual Okay { // expected-note 3 {{because type 'VirtualBase' has a virtual base class}}
+class VirtualBase : virtual Okay { // expected-note 4 {{because type 'VirtualBase' has a virtual base class}}
};
class Ctor {
- Ctor() { abort(); } // expected-note 3 {{because type 'Ctor' has a user-declared constructor}}
+ Ctor() { abort(); } // expected-note 4 {{because type 'Ctor' has a user-declared constructor}}
};
class Ctor2 {
Ctor2(); // expected-note 3 {{because type 'Ctor2' has a user-declared constructor}}
};
class CopyCtor {
- CopyCtor(CopyCtor &cc) { abort(); } // expected-note 3 {{because type 'CopyCtor' has a user-declared copy constructor}}
+ CopyCtor(CopyCtor &cc) { abort(); } // expected-note 4 {{because type 'CopyCtor' has a user-declared copy constructor}}
};
// FIXME: this should eventually trigger on the operator's declaration line
-class CopyAssign { // expected-note 3 {{because type 'CopyAssign' has a user-declared copy assignment operator}}
+class CopyAssign { // expected-note 4 {{because type 'CopyAssign' has a user-declared copy assignment operator}}
CopyAssign& operator=(CopyAssign& CA) { abort(); }
};
class Dtor {
- ~Dtor() { abort(); } // expected-note 3 {{because type 'Dtor' has a user-declared destructor}}
+ ~Dtor() { abort(); } // expected-note 4 {{because type 'Dtor' has a user-declared destructor}}
};
union U1 {
@@ -100,23 +100,21 @@ union U5 {
template <class A, class B> struct Either {
bool tag;
- union {
+ union { // expected-note 6 {{in instantiation of member class}}
A a;
- B b;
+ B b; // expected-error 6 {{non-trivial}}
};
- Either(A& a) : tag(true), a(a) {}
- Either(B& b) : tag(false), b(b) {}
+ Either(const A& a) : tag(true), a(a) {}
+ Either(const B& b) : tag(false), b(b) {}
};
-/* FIXME: this should work, but crashes in template code.
void fred() {
- Either<int,Virtual> virt(0);
- Either<int,VirtualBase> vbase(0);
- Either<int,Ctor> ctor(0);
- Either<int,CopyCtor> copyctor(0);
- Either<int,CopyAssign> copyassign(0);
- Either<int,Dtor> dtor(0);
+ Either<int,Virtual> virt(0); // expected-note {{in instantiation of template}}
+ Either<int,VirtualBase> vbase(0); // expected-note {{in instantiation of template}}
+ Either<int,Ctor> ctor(0); // expected-note {{in instantiation of template}}
+ Either<int,CopyCtor> copyctor(0); // expected-note {{in instantiation of template}}
+ Either<int,CopyAssign> copyassign(0); // expected-note {{in instantiation of template}}
+ Either<int,Dtor> dtor(0); // expected-note {{in instantiation of template}}
Either<int,Okay> okay(0);
}
- */
diff --git a/test/CXX/class/p1-0x.cpp b/test/CXX/class/p1-0x.cpp
index 5851de6cc395..e677dec4caf1 100644
--- a/test/CXX/class/p1-0x.cpp
+++ b/test/CXX/class/p1-0x.cpp
@@ -2,9 +2,5 @@
namespace Test1 {
class A final { };
-class B explicit { };
-class C final explicit { };
-class D final final { }; // expected-error {{class already marked 'final'}}
-class E explicit explicit { }; // expected-error {{class already marked 'explicit'}}
}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
index b9ad6e1c067f..7c4a21c35a7d 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
@@ -95,3 +95,24 @@ namespace redecl { inline namespace n1 {
};
} }
+
+// Normal redeclarations (not for explicit instantiations or
+// specializations) are distinct in an inline namespace vs. not in an
+// inline namespace.
+namespace redecl2 {
+ inline namespace n1 {
+ void f(int) { }
+ struct X1 { };
+ template<typename T> void f(T) { }
+ template<typename T> struct X2 { };
+ int i = 71;
+ enum E { e };
+ }
+
+ void f(int) { }
+ struct X1 { };
+ template<typename T> void f(T) { }
+ template<typename T> struct X2 { };
+ int i = 71;
+ enum E { e };
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
index 15efd72c1457..07eec1edbe39 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
@@ -4,4 +4,4 @@
void f0() {
}
-inline void f0(); // expected-error {{function definition cannot preceed inline declaration}}
+inline void f0(); // expected-error {{function definition cannot precede inline declaration}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
index 18a0cf169d54..1b1f11a660b5 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++0x
struct S {
virtual ~S();
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index fec53c941e3d..09245cfd2000 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s -std=c++0x
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s -std=c++0x
struct S {
virtual ~S();
@@ -43,8 +43,7 @@ void j() {
(void)sizeof(auto); // expected-error{{'auto' not allowed here}}
(void)__alignof(auto); // expected-error{{'auto' not allowed here}}
- // FIXME: don't issue the second diagnostic for this error.
- U<auto> v; // expected-error{{'auto' not allowed in template argument}} unexpected-error{{C++ requires a type specifier}}
+ U<auto> v; // expected-error{{'auto' not allowed in template argument}}
int n;
(void)dynamic_cast<auto&>(S()); // expected-error{{'auto' not allowed here}}
@@ -63,7 +62,7 @@ enum E : auto {}; // expected-error{{'auto' not allowed here}}
struct F : auto {}; // expected-error{{expected class name}}
template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed here}}
-using A = auto; // expected-error{{expected ';'}} expected-error{{requires a qualified name}}
+using A = auto; // expected-error{{'auto' not allowed in type alias}}
// FIXME: don't issue the second diagnostic for this error.
auto k() -> auto; // expected-error{{'auto' not allowed here}} unexpected-error{{without trailing return type}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
new file mode 100644
index 000000000000..10184a058f17
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// FIXME: when clang supports alias-declarations.
+#if 0
+using X = struct { // ok
+};
+#endif
+
+class K {
+ virtual ~K();
+ // FIXME: the diagnostic here isn't very good
+ operator struct S {} (); // expected-error 2{{}}
+};
+
+void f() {
+ int arr[3] = {1,2,3};
+
+ for (struct S { S(int) {} } s : arr) { // expected-error {{types may not be defined in a for range declaration}}
+ }
+
+ new struct T {}; // expected-error {{allocation of incomplete type}} expected-note {{forward declaration}}
+
+ // FIXME: the diagnostic here isn't very good
+ try {} catch (struct U {}); // expected-error 3{{}} expected-note 2{{}}
+
+ (void)(struct V { V(int); })0; // expected-error {{'V' can not be defined in a type specifier}}
+
+ (void)dynamic_cast<struct W {}*>((K*)0); // expected-error {{'W' can not be defined in a type specifier}}
+ (void)static_cast<struct X {}*>(0); // expected-error {{'X' can not be defined in a type specifier}}
+ (void)reinterpret_cast<struct Y {}*>(0); // expected-error {{'Y' can not be defined in a type specifier}}
+ (void)const_cast<struct Z {}*>((const Z*)0); // expected-error {{'Z' can not be defined in a type specifier}}
+}
+
+void g() throw (struct Ex {}) { // expected-error {{'Ex' can not be defined in a type specifier}}
+}
+
+// FIXME: this currently gives a strange error because alignas is not recognised as a keyword yet.
+int alignas(struct Aa {}) x; // expected-error {{'Aa' can not be defined in a parameter type}} expected-error {{expected function body}}
+
+int a = sizeof(struct So {}); // expected-error {{'So' can not be defined in a type specifier}}
+int b = alignof(struct Ao {}); // expected-error {{'Ao' can not be defined in a type specifier}}
+
+namespace std { struct type_info; }
+const std::type_info &ti = typeid(struct Ti {}); // expected-error {{'Ti' can not be defined in a type specifier}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
new file mode 100644
index 000000000000..a51cfbfffcce
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -verify -std=c++0x %s
+
+namespace RedeclAliasTypedef {
+ typedef int T;
+ using T = int;
+ using T = int;
+ typedef T T;
+ using T = T;
+ typedef int T;
+}
+
+namespace IllegalTypeIds {
+ using A = void(int n = 0); // expected-error {{default arguments can only be specified for parameters in a function declaration}}
+ using B = inline void(int n); // expected-error {{type name does not allow function specifier}}
+ using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
+ using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
+ using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
+ // FIXME: this is illegal; we incorrectly accept it for typedefs too.
+ using F = void(*)(int n) &&; // expected-err
+ using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
+
+ using H = void(int n); // ok
+ using I = void(int n) &&; // ok
+}
+
+namespace IllegalSyntax {
+ using ::T = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+ using operator int = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+ using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}
+ using typename ::V = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+ using typename ::operator bool = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+}
+
+namespace VariableLengthArrays {
+ using T = int[42]; // ok
+
+ int n = 32;
+ using T = int[n]; // expected-error {{variable length array declaration not allowed at file scope}}
+
+ const int m = 42;
+ using U = int[m]; // expected-note {{previous definition}}
+ using U = int[42]; // ok
+ using U = int; // expected-error {{type alias redefinition with different types ('int' vs 'int [42]')}}
+
+ void f() {
+ int n = 42;
+ goto foo; // expected-error {{goto into protected scope}}
+ using T = int[n]; // expected-note {{bypasses initialization of VLA type alias}}
+ foo: ;
+ }
+}
+
+namespace RedeclFunc {
+ int f(int, char**);
+ using T = int;
+ T f(int, char **); // ok
+}
+
+namespace LookupFilter {
+ namespace N { struct S; }
+ using namespace N;
+ using S = S*; // ok
+}
+
+namespace InFunctions {
+ template<typename...T> void f0() {
+ using U = T*; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
+ U u;
+ }
+ template void f0<int, char>();
+
+ void f1() {
+ using T = int;
+ }
+ void f2() {
+ using T = int[-1]; // expected-error {{array size is negative}}
+ }
+
+ template<typename...T> void f3() { // expected-note {{template parameter is declared here}}
+ using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+}
+
+namespace ClassNameRedecl {
+ class C0 {
+ // FIXME: this diagnostic is pretty poor
+ using C0 = int; // expected-error {{name defined in alias declaration must be an identifier}}
+ };
+ class C1 {
+ // FIXME: this diagnostic is pretty poor
+ using C1 = C1; // expected-error {{name defined in alias declaration must be an identifier}}
+ };
+ class C2 {
+ using C0 = C1; // ok
+ };
+ template<typename...T> class C3 {
+ using f = T; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
+ };
+ template<typename T> class C4 { // expected-note {{template parameter is declared here}}
+ using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ class C5 {
+ class c; // expected-note {{previous definition}}
+ using c = int; // expected-error {{typedef redefinition with different types}}
+ class d;
+ using d = d; // ok
+ };
+ class C6 {
+ class c { using C6 = int; }; // ok
+ };
+}
+
+class CtorDtorName {
+ using X = CtorDtorName;
+ X(); // expected-error {{expected member name}}
+ ~X(); // expected-error {{destructor cannot be declared using a type alias}}
+};
+
+namespace TagName {
+ using S = struct { int n; };
+ using T = class { int n; };
+ using U = enum { a, b, c };
+ using V = struct V { int n; };
+}
+
+namespace CWG1044 {
+ // FIXME: this is terrible. one error is plenty.
+ using T = T; // expected-error {{type name requires a specifier}} \
+ expected-error {{C++ requires a type specifier}} \
+ expected-error {{expected ';' after alias declaration}}
+}
+
+namespace StdExample {
+ template<typename T, typename U> struct pair;
+
+ using handler_t = void (*)(int);
+ extern handler_t ignore;
+ extern void (*ignore)(int);
+ // FIXME: we know we're parsing a type here; don't recover as if we were
+ // using operator*.
+ using cell = pair<void*, cell*>; // expected-error {{use of undeclared identifier 'cell'}} \
+ expected-error {{expected expression}}
+}
+
+namespace Access {
+ class C0 {
+ using U = int; // expected-note {{declared private here}}
+ };
+ C0::U v; // expected-error {{'U' is a private member}}
+ class C1 {
+ public:
+ using U = int;
+ };
+ C1::U w; // ok
+}
+
+namespace VoidArg {
+ using V = void;
+ V f(int); // ok
+ V g(V); // expected-error {{empty parameter list defined with a type alias of 'void' not allowed}}
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p2.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p2.cpp
new file mode 100644
index 000000000000..3d67fccb4282
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p2.cpp
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+char test1[1]="f"; // expected-error {{initializer-string for char array is too long}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
index 5fb35ba9622b..868d009003ee 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fexceptions -verify %s
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fcxx-exceptions -fexceptions -verify %s
// When it is part of a parameter-declaration-clause, the parameter
// pack is a function parameter pack.
diff --git a/test/CXX/except/except.handle/p16.cpp b/test/CXX/except/except.handle/p16.cpp
index 24f0db08cd8d..0810be108e41 100644
--- a/test/CXX/except/except.handle/p16.cpp
+++ b/test/CXX/except/except.handle/p16.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
// The object declared in an exception-declaration or, if the
// exception-declaration does not specify a name, a temporary (12.2)
diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp
new file mode 100644
index 000000000000..0559285e77a9
--- /dev/null
+++ b/test/CXX/except/except.spec/p1.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Simple parser tests, dynamic specification.
+
+namespace dyn {
+
+ struct X { };
+
+ struct Y { };
+
+ void f() throw() { }
+
+ void g(int) throw(X) { }
+
+ void h() throw(X, Y) { }
+
+ class Class {
+ void foo() throw (X, Y) { }
+ };
+
+ void (*fptr)() throw();
+
+}
+
+// Simple parser tests, noexcept specification.
+
+namespace noex {
+
+ void f1() noexcept { }
+ void f2() noexcept (true) { }
+ void f3() noexcept (false) { }
+ void f4() noexcept (1 < 2) { }
+
+ class CA1 {
+ void foo() noexcept { }
+ void bar() noexcept (true) { }
+ };
+
+ void (*fptr1)() noexcept;
+ void (*fptr2)() noexcept (true);
+
+}
+
+namespace mix {
+
+ void f() throw(int) noexcept { } // expected-error {{cannot have both}}
+ void g() noexcept throw(int) { } // expected-error {{cannot have both}}
+
+}
+
+// Sema tests, noexcept specification
+
+namespace noex {
+
+ struct A {};
+
+ void g1() noexcept(A()); // expected-error {{not contextually convertible}}
+ void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}}
+
+}
diff --git a/test/CXX/except/except.spec/p11.cpp b/test/CXX/except/except.spec/p11.cpp
new file mode 100644
index 000000000000..268b53ad79d0
--- /dev/null
+++ b/test/CXX/except/except.spec/p11.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// This is the "let the user shoot himself in the foot" clause.
+void f() noexcept {
+ throw 0; // no-error
+}
+void g() throw() {
+ throw 0; // no-error
+}
+void h() throw(int) {
+ throw 0.0; // no-error
+}
diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp
index 9450b1cf80d7..f5e83eaac618 100644
--- a/test/CXX/except/except.spec/p14.cpp
+++ b/test/CXX/except/except.spec/p14.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify %s
struct A { };
struct B { };
struct C { };
diff --git a/test/CXX/except/except.spec/p15.cpp b/test/CXX/except/except.spec/p15.cpp
new file mode 100644
index 000000000000..2dae9623e0cc
--- /dev/null
+++ b/test/CXX/except/except.spec/p15.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Deallocation functions are implicitly noexcept.
+// Thus, explicit specs aren't allowed to conflict.
+
+void f() {
+ // Force implicit declaration of delete.
+ delete new int;
+ delete[] new int[1];
+}
+
+void operator delete(void*) noexcept;
+void operator delete[](void*) noexcept;
+
+// Same goes for explicit declarations.
+void operator delete(void*, float);
+void operator delete(void*, float) noexcept;
+
+void operator delete[](void*, float);
+void operator delete[](void*, float) noexcept;
+
+// But explicit specs stay.
+void operator delete(void*, double) throw(int); // expected-note {{previous}}
+void operator delete(void*, double) noexcept; // expected-error {{does not match}}
diff --git a/test/CXX/except/except.spec/p2-dynamic-types.cpp b/test/CXX/except/except.spec/p2-dynamic-types.cpp
new file mode 100644
index 000000000000..57f8c3251a1c
--- /dev/null
+++ b/test/CXX/except/except.spec/p2-dynamic-types.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Dynamic specifications: valid types.
+
+struct Incomplete; // expected-note 3 {{forward declaration}}
+
+// Exception spec must not have incomplete types, or pointers to them, except
+// void.
+void ic1() throw(void); // expected-error {{incomplete type 'void' is not allowed in exception specification}}
+void ic2() throw(Incomplete); // expected-error {{incomplete type 'Incomplete' is not allowed in exception specification}}
+void ic3() throw(void*);
+void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'Incomplete' is not allowed in exception specification}}
+void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'Incomplete' is not allowed in exception specification}}
+
+// Don't suppress errors in template instantiation.
+template <typename T> struct TEx; // expected-note {{template is declared here}}
+
+void tf() throw(TEx<int>); // expected-error {{implicit instantiation of undefined template}}
+
+// DR 437, class throws itself.
+struct DR437 {
+ void f() throw(DR437);
+ void g() throw(DR437*);
+ void h() throw(DR437&);
+};
+
+// DR 437 within a nested class
+struct DR437_out {
+ struct DR437_in {
+ void f() throw(DR437_out);
+ void g() throw(DR437_out*);
+ void h() throw(DR437_out&);
+ };
+};
diff --git a/test/CXX/except/except.spec/p2-places.cpp b/test/CXX/except/except.spec/p2-places.cpp
new file mode 100644
index 000000000000..db1ee77463fb
--- /dev/null
+++ b/test/CXX/except/except.spec/p2-places.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Tests where specs are allowed and where they aren't.
+
+namespace dyn {
+
+ // Straight from the standard:
+
+ // Plain function with spec
+ void f() throw(int);
+
+ // Pointer to function with spec
+ void (*fp)() throw (int);
+
+ // Function taking reference to function with spec
+ void g(void pfa() throw(int));
+
+ // Typedef for pointer to function with spec
+ typedef int (*pf)() throw(int); // expected-error {{specifications are not allowed in typedefs}}
+
+ // Some more:
+
+ // Function returning function with spec
+ void (*h())() throw(int);
+
+ // Ultimate parser thrill: function with spec returning function with spec and
+ // taking pointer to function with spec.
+ // The actual function throws int, the return type double, the argument float.
+ void (*i() throw(int))(void (*)() throw(float)) throw(double);
+
+ // Pointer to pointer to function taking function with spec
+ void (**k)(void pfa() throw(int)); // no-error
+
+ // Pointer to pointer to function with spec
+ void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
+
+ // Pointer to function returning pointer to pointer to function with spec
+ void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
+
+}
+
+namespace noex {
+
+ // These parallel those from above.
+
+ void f() noexcept(false);
+
+ void (*fp)() noexcept(false);
+
+ void g(void pfa() noexcept(false));
+
+ typedef int (*pf)() noexcept(false); // expected-error {{specifications are not allowed in typedefs}}
+
+ void (*h())() noexcept(false);
+
+ void (*i() noexcept(false))(void (*)() noexcept(true)) noexcept(false);
+
+ void (**k)(void pfa() noexcept(false)); // no-error
+
+ void (**j)() noexcept(false); // expected-error {{not allowed beyond a single}}
+
+ void (**(*h())())() noexcept(false); // expected-error {{not allowed beyond a single}}
+}
diff --git a/test/CXX/except/except.spec/p3.cpp b/test/CXX/except/except.spec/p3.cpp
new file mode 100644
index 000000000000..5df5f26a8f8f
--- /dev/null
+++ b/test/CXX/except/except.spec/p3.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Exception specification compatibility.
+// We test function pointers, because functions have an extra rule in p4.
+
+// Same type is compatible
+extern void (*r1)() throw(int);
+extern void (*r1)() throw(int);
+
+// Typedefs don't matter.
+typedef int INT;
+extern void (*r2)() throw(int);
+extern void (*r2)() throw(INT);
+
+// Order doesn't matter.
+extern void (*r3)() throw(int, float);
+extern void (*r3)() throw(float, int);
+
+// MS throw-any spec and no spec at all are compatible
+extern void (*r4)();
+extern void (*r4)() throw(...);
+
+// throw(X) and no spec are not compatible
+extern void (*r5)() throw(int); // expected-note {{previous declaration}}
+extern void (*r5)(); // expected-error {{exception specification in declaration does not match}}
+
+// For functions, we accept this with a warning.
+extern void f5() throw(int); // expected-note {{previous declaration}}
+extern void f5(); // expected-warning {{missing exception specification}}
+
+// Different types are not compatible.
+extern void (*r7)() throw(int); // expected-note {{previous declaration}}
+extern void (*r7)() throw(float); // expected-error {{exception specification in declaration does not match}}
+
+// Top-level const doesn't matter.
+extern void (*r8)() throw(int);
+extern void (*r8)() throw(const int);
+
+// Multiple appearances don't matter.
+extern void (*r9)() throw(int, int);
+extern void (*r9)() throw(int, int);
+
+
+// noexcept is compatible with itself
+extern void (*r10)() noexcept;
+extern void (*r10)() noexcept;
+
+// noexcept(true) is compatible with noexcept
+extern void (*r11)() noexcept;
+extern void (*r11)() noexcept(true);
+
+// noexcept(false) isn't
+extern void (*r12)() noexcept; // expected-note {{previous declaration}}
+extern void (*r12)() noexcept(false); // expected-error {{does not match}}
+
+// The form of the boolean expression doesn't matter.
+extern void (*r13)() noexcept(1 < 2);
+extern void (*r13)() noexcept(2 > 1);
+
+// noexcept(false) is incompatible with noexcept(true)
+extern void (*r14)() noexcept(true); // expected-note {{previous declaration}}
+extern void (*r14)() noexcept(false); // expected-error {{does not match}}
+
+// noexcept(false) is compatible with itself
+extern void (*r15)() noexcept(false);
+extern void (*r15)() noexcept(false);
+
+// noexcept(false) is compatible with MS throw(...)
+extern void (*r16)() noexcept(false);
+extern void (*r16)() throw(...);
+
+// noexcept(false) is *not* compatible with no spec
+extern void (*r17)(); // expected-note {{previous declaration}}
+extern void (*r17)() noexcept(false); // expected-error {{does not match}}
+
+// except for functions
+void f17();
+void f17() noexcept(false);
+
+// noexcept(false) is compatible with dynamic specs that throw unless
+// CWG 1073 resolution is accepted. Clang implements it.
+//extern void (*r18)() throw(int);
+//extern void (*r18)() noexcept(false);
+
+// noexcept(true) is compatible with dynamic specs that don't throw
+extern void (*r19)() throw();
+extern void (*r19)() noexcept(true);
+
+// The other way round doesn't work.
+extern void (*r20)() throw(); // expected-note {{previous declaration}}
+extern void (*r20)() noexcept(false); // expected-error {{does not match}}
+
+extern void (*r21)() throw(int); // expected-note {{previous declaration}}
+extern void (*r21)() noexcept(true); // expected-error {{does not match}}
+
+
+// As a very special workaround, we allow operator new to match no spec
+// with a throw(bad_alloc) spec, because C++0x makes an incompatible change
+// here.
+extern "C++" { namespace std { class bad_alloc {}; } }
+typedef decltype(sizeof(int)) mysize_t;
+void* operator new(mysize_t) throw(std::bad_alloc);
+void* operator new(mysize_t);
+void* operator new[](mysize_t);
+void* operator new[](mysize_t) throw(std::bad_alloc);
+
diff --git a/test/CXX/except/except.spec/p5-pointers.cpp b/test/CXX/except/except.spec/p5-pointers.cpp
new file mode 100644
index 000000000000..171afff22b5b
--- /dev/null
+++ b/test/CXX/except/except.spec/p5-pointers.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Assignment of function pointers.
+
+struct A
+{
+};
+
+struct B1 : A
+{
+};
+
+struct B2 : A
+{
+};
+
+struct D : B1, B2
+{
+};
+
+struct P : private A
+{
+};
+
+// Some functions to play with below.
+void s1() throw();
+void s2() throw(int);
+void s3() throw(A);
+void s4() throw(B1);
+void s5() throw(D);
+void s6();
+void s7() throw(int, float);
+void (*s8())() throw(B1); // s8 returns a pointer to function with spec
+void s9(void (*)() throw(B1)); // s9 takes pointer to function with spec
+
+void s10() noexcept;
+void s11() noexcept(true);
+void s12() noexcept(false);
+
+void fnptrs()
+{
+ // Assignment and initialization of function pointers.
+ void (*t1)() throw() = &s1; // valid
+ t1 = &s2; // expected-error {{not superset}} expected-error {{incompatible type}}
+ t1 = &s3; // expected-error {{not superset}} expected-error {{incompatible type}}
+ void (&t2)() throw() = s2; // expected-error {{not superset}}
+ void (*t3)() throw(int) = &s2; // valid
+ void (*t4)() throw(A) = &s1; // valid
+ t4 = &s3; // valid
+ t4 = &s4; // valid
+ t4 = &s5; // expected-error {{not superset}} expected-error {{incompatible type}}
+ void (*t5)() = &s1; // valid
+ t5 = &s2; // valid
+ t5 = &s6; // valid
+ t5 = &s7; // valid
+ t1 = t3; // expected-error {{not superset}} expected-error {{incompatible type}}
+ t3 = t1; // valid
+ void (*t6)() throw(B1);
+ t6 = t4; // expected-error {{not superset}} expected-error {{incompatible type}}
+ t4 = t6; // valid
+ t5 = t1; // valid
+ t1 = t5; // expected-error {{not superset}} expected-error {{incompatible type}}
+
+ // return types and arguments must match exactly, no inheritance allowed
+ void (*(*t7)())() throw(B1) = &s8; // valid
+ void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}}
+ void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}}
+ void (*t10)(void (*)() throw(B1)) = &s9; // valid expected-warning{{disambiguated}}
+ void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}}
+ void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}}
+}
+
+// Member function stuff
+
+struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}}
+void Str1::f() // expected-warning {{missing exception specification}}
+{
+}
+
+void mfnptr()
+{
+ void (Str1::*pfn1)() throw(int) = &Str1::f; // valid
+ void (Str1::*pfn2)() = &Str1::f; // valid
+ void (Str1::*pfn3)() throw() = &Str1::f; // expected-error {{not superset}}
+}
diff --git a/test/CXX/except/except.spec/p5-virtual.cpp b/test/CXX/except/except.spec/p5-virtual.cpp
new file mode 100644
index 000000000000..ceea9f8f2500
--- /dev/null
+++ b/test/CXX/except/except.spec/p5-virtual.cpp
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Compatibility of virtual functions.
+
+struct A
+{
+};
+
+struct B1 : A
+{
+};
+
+struct B2 : A
+{
+};
+
+struct D : B1, B2
+{
+};
+
+struct P : private A
+{
+};
+
+struct Base
+{
+ virtual void f1() throw();
+ virtual void f2() throw(int, float);
+
+ virtual void f3() throw(int, float);
+ virtual void f4() throw(A);
+ virtual void f5() throw(A, int, float);
+ virtual void f6();
+
+ virtual void f7() noexcept;
+ virtual void f8() noexcept;
+ virtual void f9() noexcept(false);
+ virtual void f10() noexcept(false);
+
+ virtual void f11() throw();
+ virtual void f12() noexcept;
+ virtual void f13() noexcept(false);
+ virtual void f14() throw(int);
+
+ virtual void f15();
+ virtual void f16();
+
+ virtual void g1() throw(); // expected-note {{overridden virtual function is here}}
+ virtual void g2() throw(int); // expected-note {{overridden virtual function is here}}
+ virtual void g3() throw(A); // expected-note {{overridden virtual function is here}}
+ virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}}
+ virtual void g5() throw(A); // expected-note {{overridden virtual function is here}}
+
+ virtual void g6() noexcept; // expected-note {{overridden virtual function is here}}
+ virtual void g7() noexcept; // expected-note {{overridden virtual function is here}}
+
+ virtual void g8() noexcept; // expected-note {{overridden virtual function is here}}
+ virtual void g9() throw(); // expected-note {{overridden virtual function is here}}
+ virtual void g10() throw(int); // expected-note {{overridden virtual function is here}}
+};
+struct Derived : Base
+{
+ virtual void f1() throw();
+ virtual void f2() throw(float, int);
+
+ virtual void f3() throw(float);
+ virtual void f4() throw(B1);
+ virtual void f5() throw(B1, B2, int);
+ virtual void f6() throw(B2, B2, int, float, char, double, bool);
+
+ virtual void f7() noexcept;
+ virtual void f8() noexcept(true);
+ virtual void f9() noexcept(true);
+ virtual void f10() noexcept(false);
+
+ virtual void f11() noexcept;
+ virtual void f12() throw();
+ virtual void f13() throw(int);
+ virtual void f14() noexcept(true);
+
+ virtual void f15() noexcept;
+ virtual void f16() throw();
+
+ virtual void g1() throw(int); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g2(); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g5() throw(P); // expected-error {{exception specification of overriding function is more lax}}
+
+ virtual void g6() noexcept(false); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g7(); // expected-error {{exception specification of overriding function is more lax}}
+
+ virtual void g8() throw(int); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g9() noexcept(false); // expected-error {{exception specification of overriding function is more lax}}
+ virtual void g10() noexcept(false); // expected-error {{exception specification of overriding function is more lax}}
+};
diff --git a/test/CXX/except/except.spec/p9-dynamic.cpp b/test/CXX/except/except.spec/p9-dynamic.cpp
new file mode 100644
index 000000000000..490d2fa21f99
--- /dev/null
+++ b/test/CXX/except/except.spec/p9-dynamic.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
+
+void external();
+
+void target() throw(int)
+{
+ // CHECK: invoke void @_Z8externalv()
+ external();
+}
+// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* bitcast (i8** @_ZTIi to i8*), i8* null) nounwind
+// CHECK: call void @__cxa_call_unexpected
diff --git a/test/CXX/except/except.spec/p9-noexcept.cpp b/test/CXX/except/except.spec/p9-noexcept.cpp
new file mode 100644
index 000000000000..76ac66c841b9
--- /dev/null
+++ b/test/CXX/except/except.spec/p9-noexcept.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -std=c++0x -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
+
+void external();
+
+void target() noexcept
+{
+ // CHECK: invoke void @_Z8externalv()
+ external();
+}
+// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* null) nounwind
+// CHECK-NEXT: call void @_ZSt9terminatev() noreturn nounwind
+// CHECK-NEXT: unreachable
+
+void reverse() noexcept(false)
+{
+ // CHECK: call void @_Z8externalv()
+ external();
+}
diff --git a/test/CXX/except/except.spec/template.cpp b/test/CXX/except/except.spec/template.cpp
new file mode 100644
index 000000000000..f8b7270344a7
--- /dev/null
+++ b/test/CXX/except/except.spec/template.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// We use pointer assignment compatibility to test instantiation.
+
+template <int N> void f1() throw(int);
+template <int N> void f2() noexcept(N > 1);
+
+void (*t1)() throw(int) = &f1<0>;
+void (*t2)() throw() = &f1<0>; // expected-error {{not superset}}
+
+void (*t3)() noexcept = &f2<2>; // no-error
+void (*t4)() noexcept = &f2<0>; // expected-error {{not superset}}
diff --git a/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp b/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp
index 6aec3a2781ef..67d853a287f8 100644
--- a/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/cg.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++0x -include %S/ser.h %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fexceptions -triple x86_64-apple-darwin10 -emit-pch -o %t-ser.pch -std=c++0x -x c++ %S/ser.h
-// RUN: %clang_cc1 -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++0x -include-pch %t-ser.pch %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++0x -include %S/ser.h %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-pch -o %t-ser.pch -std=c++0x -x c++ %S/ser.h
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -S -emit-llvm -std=c++0x -include-pch %t-ser.pch %s -o - | FileCheck %s
struct D {
~D() throw();
diff --git a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
index 98c6f4e09f51..28ed62c71ec0 100644
--- a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify -std=c++0x -fms-extensions %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x -fms-extensions %s
#define P(e) static_assert(noexcept(e), "expected nothrow")
#define N(e) static_assert(!noexcept(e), "expected throw")
@@ -20,6 +20,8 @@ void allspec() throw(...);
void intspec() throw(int);
void emptyspec() throw();
void nothrowattr() __attribute__((nothrow));
+void noexcept_true() noexcept;
+void noexcept_false() noexcept(false);
void call() {
N(nospec());
@@ -27,6 +29,8 @@ void call() {
N(intspec());
P(emptyspec());
P(nothrowattr());
+ P(noexcept_true());
+ N(noexcept_false());
}
void (*pnospec)();
diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp
index 543a86d4e351..30f8c5491951 100644
--- a/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.op/p6.cpp
@@ -29,8 +29,8 @@ bool b8 = !S(); //expected-error {{invalid argument type 'S'}}
namespace PR8181
{
- void f() { }
- void f(char) { }
- bool b = !&f; //expected-error {{cannot resolve overloaded function from context}}
+ void f() { } // expected-note{{candidate function}}
+ void f(char) { } // expected-note{{candidate function}}
+ bool b = !&f; //expected-error {{cannot resolve overloaded function 'f' from context}}
}
diff --git a/test/CXX/lex/lex.pptoken/p3-0x.cpp b/test/CXX/lex/lex.pptoken/p3-0x.cpp
new file mode 100644
index 000000000000..4ae867c2095e
--- /dev/null
+++ b/test/CXX/lex/lex.pptoken/p3-0x.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+
+int a<::> = { 1, 2, 3 };
+int b = a<:::a<:0:>:>;
+bool c = a<:0:><::b;
+
+template<int &n> void f() {}
+template void f<::b>();
+
+#define x a<:: ## : b :>
+int d = x; // expected-error {{pasting formed ':::', an invalid preprocessing token}} expected-error {{expected unqualified-id}}
diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
index f38a74e6e495..544a66d9e39a 100644
--- a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
+++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
@@ -22,6 +22,36 @@ namespace DontResolveTooEarly_WaitForOverloadResolution
} // End namespace
+namespace DontAllowUnresolvedOverloadedExpressionInAnUnusedExpression
+{
+ void one() { }
+ template<class T> void oneT() { }
+
+ void two() { } //expected-note 2{{candidate}}
+ void two(int) { } //expected-note 2{{candidate}}
+ template<class T> void twoT() { } //expected-note 2{{candidate}}
+ template<class T> void twoT(T) { } //expected-note 2{{candidate}}
+
+ void check()
+ {
+ one; // expected-warning {{expression result unused}}
+ two; // expected-error{{cannot resolve overloaded function 'two' from context}}
+ oneT<int>; // expected-warning {{expression result unused}}
+ twoT<int>; // expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ }
+
+ // check the template function case
+ template<class T> void check()
+ {
+ one; // expected-warning {{expression result unused}}
+ two; // expected-error{{cannot resolve overloaded function 'two' from context}}
+ oneT<int>; // expected-warning {{expression result unused}}
+ twoT<int>; // expected-error {{cannot resolve overloaded function 'twoT' from context}}
+
+ }
+
+}
+
template<typename T>
void twoT() { }
template<typename T, typename U>
@@ -45,13 +75,14 @@ namespace DontResolveTooEarly_WaitForOverloadResolution
int main()
{
+
{ static_cast<void>(one); }
{ (void)(one); }
{ static_cast<void>(oneT<int>); }
{ (void)(oneT<int>); }
- { static_cast<void>(two); } // expected-error {{address of overloaded}}
- { (void)(two); } // expected-error {{address of overloaded}}
+ { static_cast<void>(two); } // expected-error {{address of overloaded function 'two' cannot be static_cast to type 'void'}}
+ { (void)(two); } // expected-error {{address of overloaded function 'two' cannot be cast to type 'void'}}
{ static_cast<void>(twoT<int>); }
{ (void)(twoT<int>); }
@@ -92,4 +123,69 @@ int main()
}
-
+namespace member_pointers {
+ struct S {
+ template <typename T> bool f(T) { return false; }
+ template <typename T> static bool g(T) { return false; }
+
+ template <typename T> bool h(T) { return false; }
+ template <int N> static bool h(int) { return false; }
+ };
+
+ void test(S s) {
+ if (S::f<char>) return; // expected-error {{call to non-static member function without an object argument}}
+ if (S::f<int>) return; // expected-error {{call to non-static member function without an object argument}}
+ if (&S::f<char>) return;
+ if (&S::f<int>) return;
+ if (s.f<char>) return; // expected-error {{a bound member function may only be called}}
+ if (s.f<int>) return; // expected-error {{a bound member function may only be called}}
+ if (&s.f<char>) return; // expected-error {{cannot create a non-constant pointer to member function}}
+ if (&s.f<int>) return; // expected-error {{cannot create a non-constant pointer to member function}}
+
+ if (S::g<char>) return;
+ if (S::g<int>) return;
+ if (&S::g<char>) return;
+ if (&S::g<int>) return;
+ if (s.g<char>) return;
+ if (s.g<int>) return;
+ if (&s.g<char>) return;
+ if (&s.g<int>) return;
+
+ if (S::h<42>) return;
+ if (S::h<int>) return; // expected-error {{a bound member function may only be called}}
+ if (&S::h<42>) return;
+ if (&S::h<int>) return;
+ if (s.h<42>) return;
+ if (s.h<int>) return; // expected-error {{a bound member function may only be called}}
+ if (&s.h<42>) return;
+ if (&s.h<int>) return; // expected-error {{a bound member function may only be called}}
+
+ { bool b = S::f<char>; } // expected-error {{call to non-static member function without an object argument}}
+ { bool b = S::f<int>; } // expected-error {{call to non-static member function without an object argument}}
+ { bool b = &S::f<char>; }
+ { bool b = &S::f<int>; }
+ // These next two errors are terrible.
+ { bool b = s.f<char>; } // expected-error {{cannot initialize}}
+ { bool b = s.f<int>; } // expected-error {{cannot initialize}}
+ { bool b = &s.f<char>; } // expected-error {{cannot create a non-constant pointer to member function}}
+ { bool b = &s.f<int>; } // expected-error {{cannot create a non-constant pointer to member function}}
+
+ { bool b = S::g<char>; }
+ { bool b = S::g<int>; }
+ { bool b = &S::g<char>; }
+ { bool b = &S::g<int>; }
+ { bool b = s.g<char>; }
+ { bool b = s.g<int>; }
+ { bool b = &s.g<char>; }
+ { bool b = &s.g<int>; }
+
+ { bool b = S::h<42>; }
+ { bool b = S::h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ { bool b = &S::h<42>; }
+ { bool b = &S::h<int>; }
+ { bool b = s.h<42>; }
+ { bool b = s.h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ { bool b = &s.h<42>; }
+ { bool b = &s.h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+ }
+}
diff --git a/test/CXX/special/class.copy/p33-0x.cpp b/test/CXX/special/class.copy/p33-0x.cpp
index 262809e35cb1..1e6a025ef31b 100644
--- a/test/CXX/special/class.copy/p33-0x.cpp
+++ b/test/CXX/special/class.copy/p33-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++0x -fsyntax-only -verify %s
class X {
X(const X&);
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
new file mode 100644
index 000000000000..12acde143c4f
--- /dev/null
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -0,0 +1,210 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+namespace std {
+ template<typename T>
+ auto begin(T &&t) -> decltype(t.begin()) { return t.begin(); } // expected-note 4{{ignored: substitution failure}}
+ template<typename T>
+ auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
+
+ template<typename T>
+ auto begin(T &&t) -> decltype(t.alt_begin()) { return t.alt_begin(); } // expected-note {{selected 'begin' template [with T = }} \
+ expected-note 4{{candidate template ignored: substitution failure [with T = }}
+ template<typename T>
+ auto end(T &&t) -> decltype(t.alt_end()) { return t.alt_end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
+
+ namespace inner {
+ // These should never be considered.
+ int begin(int);
+ int end(int);
+ }
+
+ using namespace inner;
+}
+
+struct A { // expected-note {{candidate constructor}}
+ A();
+ int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
+ int *end();
+};
+
+struct B {
+ B();
+ int *alt_begin();
+ int *alt_end();
+};
+
+void f(); // expected-note {{candidate}}
+void f(int); // expected-note {{candidate}}
+
+void g() {
+ for (int a : A())
+ A __begin;
+ for (char *a : A()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
+ }
+ for (char *a : B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
+ }
+ // FIXME: Terrible diagnostic here. auto deduction should fail, but does not!
+ for (double a : f) { // expected-error {{address of overloaded function 'f' does not match required type '<overloaded function type>'}}
+ }
+ for (auto a : A()) {
+ }
+ for (auto a : B()) {
+ }
+ for (auto *a : A()) { // expected-error {{variable 'a' with type 'auto *' has incompatible initializer of type 'int'}}
+ }
+ // : is not a typo for :: here.
+ for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'A'}}
+ }
+ for (auto not_in_scope : not_in_scope) { // expected-error {{use of undeclared identifier 'not_in_scope'}}
+ }
+
+ for (auto a : A())
+ for (auto b : A()) {
+ __range.begin(); // expected-error {{use of undeclared identifier '__range'}}
+ ++__begin; // expected-error {{use of undeclared identifier '__begin'}}
+ --__end; // expected-error {{use of undeclared identifier '__end'}}
+ }
+
+ for (char c : "test")
+ ;
+ for (auto a : f()) // expected-error {{cannot use type 'void' as a range}}
+ ;
+
+ extern int incomplete[];
+ for (auto a : incomplete) // expected-error {{cannot use incomplete type 'int []' as a range}}
+ ;
+ extern struct Incomplete also_incomplete[2]; // expected-note {{forward declaration}}
+ for (auto &a : also_incomplete) // expected-error {{cannot use incomplete type 'struct Incomplete [2]' as a range}}
+ ;
+
+ struct VoidBegin {
+ void begin(); // expected-note {{selected 'begin' function with iterator type 'void'}}
+ void end();
+ };
+ for (auto a : VoidBegin()) // expected-error {{cannot use type 'void' as an iterator}}
+ ;
+
+ struct null_t {
+ operator int*();
+ };
+ struct Differ {
+ int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}}
+ null_t end(); // expected-note {{selected 'end' function with iterator type 'null_t'}}
+ };
+ for (auto a : Differ()) // expected-error {{'begin' and 'end' must return the same type (got 'int *' and 'null_t')}}
+ ;
+
+ for (void f() : "error") // expected-error {{for range declaration must declare a variable}}
+ ;
+
+ for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}
+ for (static int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'static'}}
+ for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}
+ // FIXME: when clang supports constexpr, this should be rejected.
+ for (constexpr int a : A()) {} // desired-error {{loop variable 'a' may not be declared 'constexpr'}}
+
+ struct NoBeginADL {
+ null_t alt_end();
+ };
+ struct NoEndADL {
+ null_t alt_begin();
+ };
+ for (auto u : NoBeginADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type 'NoBeginADL'}}
+ }
+ for (auto u : NoEndADL()) { // expected-error {{no matching function for call to 'end'}} expected-note {{range has type 'NoEndADL'}}
+ }
+
+ struct NoBegin {
+ null_t end();
+ };
+ struct NoEnd {
+ null_t begin();
+ };
+ for (auto u : NoBegin()) { // expected-error {{range type 'NoBegin' has 'end' member but no 'begin' member}}
+ }
+ for (auto u : NoEnd()) { // expected-error {{range type 'NoEnd' has 'begin' member but no 'end' member}}
+ }
+
+ struct NoIncr {
+ void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}}
+ void *end();
+ };
+ for (auto u : NoIncr()) { // expected-error {{arithmetic on pointer to void type}}
+ }
+
+ struct NoNotEq {
+ NoNotEq begin(); // expected-note {{selected 'begin' function with iterator type 'NoNotEq'}}
+ NoNotEq end();
+ void operator++();
+ };
+ for (auto u : NoNotEq()) { // expected-error {{invalid operands to binary expression}}
+ }
+
+ struct NoCopy {
+ NoCopy();
+ NoCopy(const NoCopy &) = delete;
+ int *begin();
+ int *end();
+ };
+ for (int n : NoCopy()) { // ok
+ }
+
+ for (int n : 42) { // expected-error {{no matching function for call to 'begin'}} \
+ expected-note {{range has type 'int'}}
+ }
+
+ for (auto a : *also_incomplete) { // expected-error {{cannot use incomplete type 'struct Incomplete' as a range}}
+ }
+}
+
+template<typename T, typename U>
+void h(T t) {
+ for (U u : t) { // expected-error {{no viable conversion from 'A' to 'int'}}
+ }
+ for (auto u : t) {
+ }
+}
+
+template void h<A, int>(A);
+template void h<A(&)[4], A &>(A(&)[4]);
+template void h<A(&)[13], A>(A(&)[13]);
+template void h<A(&)[13], int>(A(&)[13]); // expected-note {{requested here}}
+
+template<typename T>
+void i(T t) {
+ for (auto u : t) { // expected-error {{no matching function for call to 'begin'}} \
+ expected-error {{member function 'begin' not viable}} \
+ expected-note {{range has type}}
+ }
+}
+template void i<A[13]>(A*); // expected-note {{requested here}}
+template void i<const A>(const A); // expected-note {{requested here}}
+
+namespace NS {
+ class ADL {};
+ int *begin(ADL); // expected-note {{no known conversion from 'NS::NoADL' to 'NS::ADL'}}
+ int *end(ADL);
+
+ class NoADL {};
+}
+int *begin(NS::NoADL);
+int *end(NS::NoADL);
+
+struct VoidBeginADL {};
+void begin(VoidBeginADL); // expected-note {{selected 'begin' function with iterator type 'void'}}
+void end(VoidBeginADL);
+
+void j() {
+ for (auto u : NS::ADL()) {
+ }
+ for (auto u : NS::NoADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ }
+ for (auto a : VoidBeginADL()) { // expected-error {{cannot use type 'void' as an iterator}}
+ }
+}
+
+void example() {
+ int array[5] = { 1, 2, 3, 4, 5 };
+ for (int &x : array)
+ x *= 2;
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index 2df6d33a8904..cda9ac8b045c 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -216,3 +216,21 @@ namespace ExpandingNonTypeTemplateParameters {
tuple_of_values<int&, float&>::apply<i, f, i>::type tv4; // expected-error{{too many template arguments for class template 'apply'}}
}
+
+namespace ExpandingFunctionParameters {
+ template<typename ...T>
+ struct X0 {
+ typedef int type;
+ };
+
+ template<typename ...T>
+ struct X1 {
+ template<typename ... U>
+ typename X0<T(T, U...)...>::type f(U...);
+ };
+
+ void test() {
+ X1<float> x1;
+ x1.f(17, 3.14159);
+ }
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
index e2fa12293725..71839727e0d1 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fexceptions -verify %s
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
template<typename... Types> struct tuple;
template<int I> struct int_c;
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 1acc21eb4fd5..25338e3bae67 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -std=c++0x -fblocks -fms-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++0x -fblocks -fms-extensions -fsyntax-only -verify %s
template<typename T, typename U> struct pair;
template<typename ...> struct tuple;
@@ -205,6 +205,8 @@ struct TestUnexpandedDecls : T{
Types t; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
for (Types *t = 0; ; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
for (; Types *t = 0; ) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
+ T a[] = { T(), T(), T() };
+ for (Types t : a) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
switch(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
while(Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
if (Types *t = 0) { } // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
@@ -341,6 +343,8 @@ void test_unexpanded_exprs(Types ...values) {
// SizeOfPackExpr is uninteresting
// FIXME: Objective-C expressions will need to go elsewhere
+
+ for (auto t : values) { } // expected-error{{expression contains unexpanded parameter pack 'values'}}
}
// Test unexpanded parameter packs in partial specializations.
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
index 9ec8f0c90e17..1140aaee6c17 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
@@ -29,8 +29,8 @@ struct is_same<T, T> {
int typeof0[is_same<__typeof__(f<int>), void (int)>::value? 1 : -1];
int typeof1[is_same<__typeof__(&f<int>), void (*)(int)>::value? 1 : -1];
-template <typename T> void g(T);
-template <typename T> void g(T, T);
+template <typename T> void g(T); // expected-note{{candidate function}}
+template <typename T> void g(T, T); // expected-note{{candidate function}}
int typeof2[is_same<__typeof__(g<float>), void (int)>::value? 1 : -1]; // \
- // expected-error{{cannot resolve overloaded function from context}}
+ // expected-error{{cannot resolve overloaded function 'g' from context}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
index ed600e4ad999..4a17ceca7cb6 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
@@ -237,3 +237,66 @@ void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp,
xvp.ft1(vp, i);
xvp.ft1(vp, u);
}
+
+namespace has_inline_namespaces {
+ inline namespace inner {
+ template<class T> void f(T&);
+
+ template<class T>
+ struct X0 {
+ struct MemberClass;
+
+ void mem_func();
+
+ template<typename U>
+ struct MemberClassTemplate;
+
+ template<typename U>
+ void mem_func_template(U&);
+
+ static int value;
+ };
+ }
+
+ struct X1;
+ struct X2;
+
+ // An explicit specialization whose declarator-id is not qualified
+ // shall be declared in the nearest enclosing namespace of the
+ // template, or, if the namespace is inline (7.3.1), any namespace
+ // from its enclosing namespace set.
+ template<> void f(X1&);
+ template<> void f<X2>(X2&);
+
+ template<> struct X0<X1> { };
+
+ template<> struct X0<X2>::MemberClass { };
+
+ template<> void X0<X2>::mem_func();
+
+ template<> template<typename T> struct X0<X2>::MemberClassTemplate { };
+
+ template<> template<typename T> void X0<X2>::mem_func_template(T&) { }
+
+ template<> int X0<X2>::value = 12;
+}
+
+struct X3;
+struct X4;
+
+template<> void has_inline_namespaces::f(X3&);
+template<> void has_inline_namespaces::f<X4>(X4&);
+
+template<> struct has_inline_namespaces::X0<X3> { };
+
+template<> struct has_inline_namespaces::X0<X4>::MemberClass { };
+
+template<> void has_inline_namespaces::X0<X4>::mem_func();
+
+template<> template<typename T>
+struct has_inline_namespaces::X0<X4>::MemberClassTemplate { };
+
+template<> template<typename T>
+void has_inline_namespaces::X0<X4>::mem_func_template(T&) { }
+
+template<> int has_inline_namespaces::X0<X4>::value = 13;
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
index 1032a87def13..229523557008 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
@@ -237,3 +237,15 @@ void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp,
xvp.ft1(vp, i);
xvp.ft1(vp, u);
}
+
+namespace PR8979 {
+ template<typename Z>
+ struct X0 {
+ template <class T, class U> class Inner;
+ struct OtherInner;
+ template<typename T, typename U> void f(Inner<T, U>&);
+
+ typedef Inner<OtherInner, OtherInner> MyInner;
+ template<> void f(MyInner&); // expected-error{{cannot specialize a function 'f' within class scope}}
+ };
+}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
index d8f7b52145dd..d0df305941d9 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
@@ -12,16 +12,16 @@ T X<T>::member1;
template<typename T>
T X<T>::member2 = 17;
-// CHECK: @_ZN1XIiE7member1E = weak global i32 0
+// CHECK: @_ZN1XIiE7member1E = weak_odr global i32 0
template int X<int>::member1;
-// CHECK: @_ZN1XIiE7member2E = weak global i32 17
+// CHECK: @_ZN1XIiE7member2E = weak_odr global i32 17
template int X<int>::member2;
// For implicit instantiation of
long& get(bool Cond1, bool Cond2) {
- // CHECK: @_ZN1XIlE7member1E = weak global i64 0
- // CHECK: @_ZN1XIlE7member2E = weak global i64 17
+ // CHECK: @_ZN1XIlE7member1E = weak_odr global i64 0
+ // CHECK: @_ZN1XIlE7member2E = weak_odr global i64 17
// CHECK: @_ZN1XIlE7member3E = external global i64
return Cond1? X<long>::member1
: Cond2? X<long>::member2
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
new file mode 100644
index 000000000000..fdb922abcf9b
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++0x -verify %s
+
+// If the name declared in the explicit instantiation is an
+// unqualified name, the explicit instantiation shall appear in the
+// namespace where its template is declared or, if that namespace is
+// inline (7.3.1), any namespace from its enclosing namespace set.
+
+namespace has_inline_namespaces {
+ inline namespace inner {
+ template<class T> void f(T&) {}
+
+ template<class T>
+ struct X0 {
+ struct MemberClass {};
+
+ void mem_func() {}
+
+ template<typename U>
+ struct MemberClassTemplate {};
+
+ template<typename U>
+ void mem_func_template(U&) {}
+
+ static int value;
+ };
+ }
+
+ template<typename T> int X0<T>::value = 17;
+
+ struct X1 {};
+ struct X2 {};
+
+ template void f(X1&);
+ template void f<X2>(X2&);
+
+ template struct X0<X1>;
+
+ template struct X0<X2>::MemberClass;
+
+ template void X0<X2>::mem_func();
+
+ template struct X0<X2>::MemberClassTemplate<X1>;
+
+ template void X0<X2>::mem_func_template(X1&);
+
+ template int X0<X2>::value;
+}
+
+struct X3;
+struct X4;
+
+template void has_inline_namespaces::f(X3&);
+template void has_inline_namespaces::f<X4>(X4&);
+
+template struct has_inline_namespaces::X0<X3>;
+
+template struct has_inline_namespaces::X0<X4>::MemberClass;
+
+template void has_inline_namespaces::X0<X4>::mem_func();
+
+template
+struct has_inline_namespaces::X0<X4>::MemberClassTemplate<X3>;
+
+template
+void has_inline_namespaces::X0<X4>::mem_func_template(X3&);
diff --git a/test/CodeCompletion/PR9728.cpp b/test/CodeCompletion/PR9728.cpp
new file mode 100644
index 000000000000..91f49be91fcf
--- /dev/null
+++ b/test/CodeCompletion/PR9728.cpp
@@ -0,0 +1,9 @@
+namespace N {
+struct SFoo;
+}
+
+struct brokenfile_t {
+ brokenfile_t (N::
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:20 %s -o - | FileCheck %s
+ // CHECK: SFoo
+
diff --git a/test/CodeCompletion/ordinary-name.cpp b/test/CodeCompletion/ordinary-name.cpp
index 6771dd226518..4dbf84dc1783 100644
--- a/test/CodeCompletion/ordinary-name.cpp
+++ b/test/CodeCompletion/ordinary-name.cpp
@@ -4,7 +4,7 @@ typedef struct t TYPEDEF;
void foo() {
int y = 17;
- // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+ // RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -code-completion-patterns -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: COMPLETION: bool
// CHECK-CC1-NEXT: COMPLETION: char
// CHECK-CC1-NEXT: COMPLETION: class
@@ -132,7 +132,7 @@ void foo() {
// CHECK-CC3-NEXT: COMPLETION: wchar_t
// CHECK-CC3-NEXT: COMPLETION: X : X
- // RUN: %clang_cc1 -fsyntax-only -code-completion-patterns -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+ // RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -code-completion-patterns -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: COMPLETION: bool
// CHECK-CC4-NEXT: COMPLETION: char
// CHECK-CC4-NEXT: COMPLETION: class
@@ -173,3 +173,57 @@ void foo() {
// CHECK-CC4-NEXT: COMPLETION: X : X
// CHECK-CC4-NEXT: COMPLETION: y : [#int#]y
// CHECK-CC4-NEXT: COMPLETION: z : [#void#]z(<#int#>)
+
+ // RUN: %clang_cc1 -fsyntax-only -fno-rtti -code-completion-patterns -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-NO-RTTI %s
+ // CHECK-NO-RTTI: COMPLETION: bool
+ // CHECK-NO-RTTI-NEXT: COMPLETION: char
+ // CHECK-NO-RTTI-NEXT: COMPLETION: class
+ // CHECK-NO-RTTI-NEXT: COMPLETION: const
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : const_cast<<#type#>>(<#expression#>)
+ // CHECK-NO-RTTI: COMPLETION: Pattern : delete <#expression#>
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : delete [] <#expression#>
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : do{<#statements#>
+ // CHECK-NO-RTTI: COMPLETION: double
+ // CHECK-NO-RTTI-NOT: dynamic_cast
+ // CHECK-NO-RTTI: COMPLETION: enum
+ // CHECK-NO-RTTI-NEXT: COMPLETION: extern
+ // CHECK-NO-RTTI-NEXT: COMPLETION: false
+ // CHECK-NO-RTTI-NEXT: COMPLETION: float
+ // CHECK-NO-RTTI-NEXT: COMPLETION: foo : [#void#]foo()
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : for(<#init-statement#>;<#condition#>;<#inc-expression#>){
+ // CHECK-NO-RTTI: COMPLETION: Pattern : goto <#label#>
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : if(<#condition#>){<#statements#>
+ // CHECK-NO-RTTI: COMPLETION: int
+ // CHECK-NO-RTTI-NEXT: COMPLETION: long
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : new <#type#>(<#expressions#>)
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : new <#type#>[<#size#>](<#expressions#>)
+ // CHECK-NO-RTTI-NEXT: COMPLETION: operator
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : reinterpret_cast<<#type#>>(<#expression#>)
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : return
+ // CHECK-NO-RTTI-NEXT: COMPLETION: short
+ // CHECK-NO-RTTI-NEXT: COMPLETION: signed
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
+ // CHECK-NO-RTTI-NEXT: COMPLETION: static
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
+ // CHECK-NO-RTTI-NEXT: COMPLETION: struct
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : switch(<#condition#>){
+ // CHECK-NO-RTTI: COMPLETION: t : t
+ // CHECK-NO-RTTI-NOT: throw
+ // CHECK-NO-RTTI: COMPLETION: true
+ // CHECK-NO-RTTI-NOT: try
+ // CHECK-NO-RTTI: COMPLETION: TYPEDEF : TYPEDEF
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : typedef <#type#> <#name#>
+ // CHECK-NO-RTTI-NOT: typeid
+ // CHECK-NO-RTTI: COMPLETION: Pattern : typename <#qualifier#>::<#name#>
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : typeof <#expression#>
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : typeof(<#type#>)
+ // CHECK-NO-RTTI-NEXT: COMPLETION: union
+ // CHECK-NO-RTTI-NEXT: COMPLETION: unsigned
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : using namespace <#identifier#>
+ // CHECK-NO-RTTI-NEXT: COMPLETION: void
+ // CHECK-NO-RTTI-NEXT: COMPLETION: volatile
+ // CHECK-NO-RTTI-NEXT: COMPLETION: wchar_t
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : while(<#condition#>){<#statements#>
+ // CHECK-NO-RTTI: COMPLETION: X : X
+ // CHECK-NO-RTTI-NEXT: COMPLETION: y : [#int#]y
+ // CHECK-NO-RTTI-NEXT: COMPLETION: z : [#void#]z(<#int#>)
diff --git a/test/CodeGen/2008-07-17-no-emit-on-error.c b/test/CodeGen/2008-07-17-no-emit-on-error.c
index 855ede7ab02b..2cae57b3d89f 100644
--- a/test/CodeGen/2008-07-17-no-emit-on-error.c
+++ b/test/CodeGen/2008-07-17-no-emit-on-error.c
@@ -1,9 +1,9 @@
// RUN: rm -f %t1.bc
// RUN: %clang_cc1 -DPASS %s -emit-llvm-bc -o %t1.bc
-// RUN: test -f %t1.bc
+// RUN: opt %t1.bc -disable-output
// RUN: rm -f %t1.bc
// RUN: not %clang_cc1 %s -emit-llvm-bc -o %t1.bc
-// RUN: not test -f %t1.bc
+// RUN: not opt %t1.bc -disable-output
void f() {
}
diff --git a/test/CodeGen/altivec.c b/test/CodeGen/altivec.c
index 9e38df50930c..ec1efd9ba197 100644
--- a/test/CodeGen/altivec.c
+++ b/test/CodeGen/altivec.c
@@ -1,4 +1,31 @@
// RUN: %clang_cc1 -faltivec -triple powerpc-unknown-unknown -emit-llvm %s -o - | FileCheck %s
-// CHECK: @test0 = global <4 x i32> <i32 1, i32 1, i32 1, i32 1>
-vector int test0 = (vector int)(1);
+// Check initialization
+
+vector int test0 = (vector int)(1); // CHECK: @test0 = global <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+vector float test1 = (vector float)(1.0); // CHECK: @test1 = global <4 x float> <float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}>
+
+void test2()
+{
+ vector int vi;
+ vector float vf;
+ vi = (vector int)(1); // CHECK: <i32 1, i32 1, i32 1, i32 1>
+ vf = (vector float)(1.0); // CHECK: <float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}>
+ vi = (vector int)(1, 2, 3, 4); // CHECK: <i32 1, i32 2, i32 3, i32 4>
+ vi = (vector int)(1, 2, 3, 4, 5); // CHECK: <i32 1, i32 2, i32 3, i32 4>
+
+ vi = (vector int){1}; // CHECK: <i32 1, i32 0, i32 0, i32 0>
+ vi = (vector int){1, 2}; // CHECK: <i32 1, i32 2, i32 0, i32 0>
+ vi = (vector int){1, 2, 3, 4}; // CHECK: <i32 1, i32 2, i32 3, i32 4>
+
+}
+
+// Check pre/post increment/decrement
+void test3() {
+ vector int vi;
+ vi++; // CHECK: add nsw <4 x i32> {{.*}} <i32 1, i32 1, i32 1, i32 1>
+ vector unsigned int vui;
+ --vui; // CHECK: add <4 x i32> {{.*}} <i32 -1, i32 -1, i32 -1, i32 -1>
+ vector float vf;
+ vf++; // CHECK: fadd <4 x float> {{.*}} <float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}>
+}
diff --git a/test/CodeGen/arm-clear.c b/test/CodeGen/arm-clear.c
new file mode 100644
index 000000000000..eda64ce99ee4
--- /dev/null
+++ b/test/CodeGen/arm-clear.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple armv7-apple-darwin9 -emit-llvm -w -o - %s | FileCheck %s
+
+void clear0(void *ptr) {
+ // CHECK: clear0
+ // CHECK-NOT: load i8**
+ __clear_cache();
+}
+
+void clear1(void *ptr) {
+ // CHECK: clear1
+ // CHECK: load i8**
+ // CHECK-NOT: load i8**
+ __clear_cache(ptr);
+}
+
+void clear2(void *ptr, void *ptr2) {
+ // CHECK: clear2
+ // CHECK: load i8**
+ // CHECK: load i8**
+ __clear_cache(ptr, ptr2);
+}
diff --git a/test/CodeGen/arm-pcs.c b/test/CodeGen/arm-pcs.c
new file mode 100644
index 000000000000..d722f84cebd7
--- /dev/null
+++ b/test/CodeGen/arm-pcs.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple arm-none-linux-gnueabi -emit-llvm -w -o - < %s | FileCheck %s
+typedef int __attribute__((pcs("aapcs"))) (*aapcs_fn)(void);
+typedef int __attribute__((pcs("aapcs-vfp"))) (*aapcs_vfp_fn)(void);
+
+aapcs_fn bar;
+
+int foo(aapcs_vfp_fn baz) {
+// CHECK: define i32 @foo
+// CHECK: call arm_aapcscc
+// CHECK: call arm_aapcs_vfpcc
+ return bar() + baz();
+}
diff --git a/test/CodeGen/arm-vector-align.c b/test/CodeGen/arm-vector-align.c
new file mode 100644
index 000000000000..c1119cb5b736
--- /dev/null
+++ b/test/CodeGen/arm-vector-align.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple thumbv7-apple-darwin \
+// RUN: -target-abi apcs-gnu \
+// RUN: -target-cpu cortex-a8 \
+// RUN: -mfloat-abi soft \
+// RUN: -target-feature +soft-float-abi \
+// RUN: -ffreestanding \
+// RUN: -emit-llvm -w -o - %s | FileCheck %s
+
+#include <arm_neon.h>
+
+// Radar 9311427: Check that alignment specifier is used in Neon load/store
+// intrinsics.
+typedef float AlignedAddr __attribute__ ((aligned (16)));
+void t1(AlignedAddr *addr1, AlignedAddr *addr2) {
+// CHECK: call <4 x float> @llvm.arm.neon.vld1.v4f32(i8* %{{.*}}, i32 16)
+ float32x4_t a = vld1q_f32(addr1);
+// CHECK: call void @llvm.arm.neon.vst1.v4f32(i8* %{{.*}}, <4 x float> %{{.*}}, i32 16)
+ vst1q_f32(addr2, a);
+}
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
index 4a7c13f03c41..8ce2d96043f2 100644
--- a/test/CodeGen/atomic.c
+++ b/test/CodeGen/atomic.c
@@ -44,6 +44,11 @@ int atomic(void) {
// CHECK: call i32 @llvm.atomic.swap.i32.p0i32(i32* %val, i32 7)
// CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ old = __sync_swap(&val, 8);
+ // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+ // CHECK: call i32 @llvm.atomic.swap.i32.p0i32(i32* %val, i32 8)
+ // CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
+
old = __sync_val_compare_and_swap(&val, 4, 1976);
// CHECK: call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true)
// CHECK: call i32 @llvm.atomic.cmp.swap.i32.p0i32(i32* %val, i32 4, i32 1976)
diff --git a/test/CodeGen/attr-availability.c b/test/CodeGen/attr-availability.c
new file mode 100644
index 000000000000..6f9c045a3f17
--- /dev/null
+++ b/test/CodeGen/attr-availability.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin8.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_4 %s
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin9.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_5 %s
+// RUN: %clang_cc1 -fvisibility hidden "-triple" "x86_64-apple-darwin10.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_6 %s
+
+// CHECK-10_4: define hidden void @f2
+// CHECK-10_5: define hidden void @f2
+// CHECK-10_6: define hidden void @f2
+void f2();
+void f2() { }
+
+// CHECK-10_4: define void @f3
+// CHECK-10_5: define void @f3
+// CHECK-10_6: define void @f3
+void f3() __attribute__((availability(macosx,introduced=10.5)));
+void f3() { }
+
+// CHECK-10_4: declare extern_weak void @f0
+// CHECK-10_5: declare void @f0
+// CHECK-10_6: declare void @f0
+void f0() __attribute__((availability(macosx,introduced=10.5)));
+
+// CHECK-10_4: declare extern_weak void @f1
+// CHECK-10_5: declare extern_weak void @f1
+// CHECK-10_6: declare void @f1
+void f1() __attribute__((availability(macosx,introduced=10.6)));
+
+void test() {
+ f0();
+ f1();
+ f2();
+}
diff --git a/test/CodeGen/block-byref-aggr.c b/test/CodeGen/block-byref-aggr.c
new file mode 100644
index 000000000000..3027df04861c
--- /dev/null
+++ b/test/CodeGen/block-byref-aggr.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s
+// rdar://9309454
+
+typedef struct { int v; } RetType;
+
+RetType func();
+
+int main () {
+ __attribute__((__blocks__(byref))) RetType a = {100};
+
+ a = func();
+}
+// CHECK: [[C1:%.*]] = call i32 (...)* @func()
+// CHECK-NEXT: [[CO:%.*]] = getelementptr
+// CHECK-NEXT: store i32 [[C1]], i32* [[CO]]
+// CHECK-NEXT: [[FORWARDING:%.*]] = getelementptr inbounds [[BR:%.*]]* [[A:%.*]], i32 0, i32 1
+// CHECK-NEXT: [[O:%.*]] = load [[BR]]** [[FORWARDING]]
diff --git a/test/CodeGen/builtin-attributes.c b/test/CodeGen/builtin-attributes.c
index afde3fab8481..822b8eecf7d7 100644
--- a/test/CodeGen/builtin-attributes.c
+++ b/test/CodeGen/builtin-attributes.c
@@ -10,3 +10,8 @@ void f0() {
void f1() {
exit(1);
}
+
+// CHECK: call i8* @strstr{{.*}} nounwind
+char* f2(char* a, char* b) {
+ return __builtin_strstr(a, b);
+}
diff --git a/test/CodeGen/builtin-expect.c b/test/CodeGen/builtin-expect.c
index 8f02c4da78a4..88479d90a092 100644
--- a/test/CodeGen/builtin-expect.c
+++ b/test/CodeGen/builtin-expect.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
int x;
int y(void);
@@ -9,3 +9,13 @@ void FUNC() {
foo ();
}
+// rdar://9330105
+void isigprocmask(void);
+long bar();
+
+int main() {
+ (void) __builtin_expect((isigprocmask(), 0), bar());
+}
+
+// CHECK: call void @isigprocmask()
+// CHECK: [[C:%.*]] = call i64 (...)* @bar()
diff --git a/test/CodeGen/builtin-memfns.c b/test/CodeGen/builtin-memfns.c
index e8c407fd6f27..fb4d7200752d 100644
--- a/test/CodeGen/builtin-memfns.c
+++ b/test/CodeGen/builtin-memfns.c
@@ -1,12 +1,13 @@
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm < %s| FileCheck %s
+// CHECK: @test1
// CHECK: call void @llvm.memset.p0i8.i32
// CHECK: call void @llvm.memset.p0i8.i32
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32
// CHECK: call void @llvm.memmove.p0i8.p0i8.i32
// CHECK-NOT: __builtin
// CHECK: ret
-int main(int argc, char **argv) {
+int test1(int argc, char **argv) {
unsigned char a = 0x11223344;
unsigned char b = 0x11223344;
__builtin_bzero(&a, sizeof(a));
@@ -15,3 +16,35 @@ int main(int argc, char **argv) {
__builtin_memmove(&a, &b, sizeof(a));
return 0;
}
+
+// rdar://9289468
+
+// CHECK: @test2
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32
+char* test2(char* a, char* b) {
+ return __builtin_memcpy(a, b, 4);
+}
+
+// CHECK: @test3
+// CHECK: call void @llvm.memset
+void test3(char *P) {
+ __builtin___memset_chk(P, 42, 128, 128);
+}
+
+// CHECK: @test4
+// CHECK: call void @llvm.memcpy
+void test4(char *P, char *Q) {
+ __builtin___memcpy_chk(P, Q, 128, 128);
+}
+
+// CHECK: @test5
+// CHECK: call void @llvm.memmove
+void test5(char *P, char *Q) {
+ __builtin___memmove_chk(P, Q, 128, 128);
+}
+
+// CHECK: @test6
+// CHECK: call void @llvm.memcpy
+int test6(char *X) {
+ return __builtin___memcpy_chk(X, X, 42, 42) != 0;
+}
diff --git a/test/CodeGen/builtinmemcpy.c b/test/CodeGen/builtinmemcpy.c
deleted file mode 100644
index 93253c5a8a48..000000000000
--- a/test/CodeGen/builtinmemcpy.c
+++ /dev/null
@@ -1,3 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm < %s -o - | grep "llvm.memcpy"
-
-char* x(char* a, char* b) {return __builtin_memcpy(a, b, 4);}
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index e03e69c28cfe..586f1133a8dc 100644
--- a/test/CodeGen/builtins-ppc-altivec.c
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -1789,23 +1789,23 @@ void test6() {
/* vec_lvlx */
res_vsc = vec_lvlx(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vsc = vec_lvlx(0, &vsc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vuc = vec_lvlx(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vuc = vec_lvlx(0, &vuc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbc = vec_lvlx(0, &vbc); // CHECK: @llvm.ppc.altivec.lvx
@@ -1814,23 +1814,23 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
res_vs = vec_lvlx(0, &param_s); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vs = vec_lvlx(0, &vs); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vus = vec_lvlx(0, &param_us); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vus = vec_lvlx(0, &vus); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbs = vec_lvlx(0, &vbs); // CHECK: @llvm.ppc.altivec.lvx
@@ -1844,23 +1844,23 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
res_vi = vec_lvlx(0, &param_i); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vi = vec_lvlx(0, &vi); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vui = vec_lvlx(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vui = vec_lvlx(0, &vui); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbi = vec_lvlx(0, &vbi); // CHECK: @llvm.ppc.altivec.lvx
@@ -1869,29 +1869,29 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
res_vf = vec_lvlx(0, &vf); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
/* vec_lvlxl */
res_vsc = vec_lvlxl(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vsc = vec_lvlxl(0, &vsc); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vuc = vec_lvlxl(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vuc = vec_lvlxl(0, &vuc); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbc = vec_lvlxl(0, &vbc); // CHECK: @llvm.ppc.altivec.lvxl
@@ -1900,23 +1900,23 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
res_vs = vec_lvlxl(0, &param_s); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vs = vec_lvlxl(0, &vs); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vus = vec_lvlxl(0, &param_us); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vus = vec_lvlxl(0, &vus); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbs = vec_lvlxl(0, &vbs); // CHECK: @llvm.ppc.altivec.lvxl
@@ -1930,23 +1930,23 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
res_vi = vec_lvlxl(0, &param_i); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vi = vec_lvlxl(0, &vi); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vui = vec_lvlxl(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vui = vec_lvlxl(0, &vui); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbi = vec_lvlxl(0, &vbi); // CHECK: @llvm.ppc.altivec.lvxl
@@ -1955,29 +1955,29 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
res_vf = vec_lvlxl(0, &vf); // CHECK: @llvm.ppc.altivec.lvxl
- // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
/* vec_lvrx */
- res_vsc = vec_lvrx(0, &param_sc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vsc = vec_lvrx(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vsc = vec_lvrx(0, &vsc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vsc = vec_lvrx(0, &vsc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vuc = vec_lvrx(0, &param_uc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vuc = vec_lvrx(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vuc = vec_lvrx(0, &vuc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vuc = vec_lvrx(0, &vuc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbc = vec_lvrx(0, &vbc); // CHECK: store <16 x i8> zeroinitializer
@@ -1985,24 +1985,24 @@ void test6() {
// CHECK: @llvm.ppc.altivec.lvsl
// CHECK: @llvm.ppc.altivec.vperm
- res_vs = vec_lvrx(0, &param_s); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vs = vec_lvrx(0, &param_s); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vs = vec_lvrx(0, &vs); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vs = vec_lvrx(0, &vs); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vus = vec_lvrx(0, &param_us); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vus = vec_lvrx(0, &param_us); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vus = vec_lvrx(0, &vus); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vus = vec_lvrx(0, &vus); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbs = vec_lvrx(0, &vbs); // CHECK: store <8 x i16> zeroinitializer
@@ -2015,24 +2015,24 @@ void test6() {
// CHECK: @llvm.ppc.altivec.lvsl
// CHECK: @llvm.ppc.altivec.vperm
- res_vi = vec_lvrx(0, &param_i); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vi = vec_lvrx(0, &param_i); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vi = vec_lvrx(0, &vi); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vi = vec_lvrx(0, &vi); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vui = vec_lvrx(0, &param_ui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vui = vec_lvrx(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vui = vec_lvrx(0, &vui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vui = vec_lvrx(0, &vui); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbi = vec_lvrx(0, &vbi); // CHECK: store <4 x i32> zeroinitializer
@@ -2040,30 +2040,30 @@ void test6() {
// CHECK: @llvm.ppc.altivec.lvsl
// CHECK: @llvm.ppc.altivec.vperm
- res_vf = vec_lvrx(0, &vf); // CHECK: store <4 x float> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ res_vf = vec_lvrx(0, &vf); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
/* vec_lvrxl */
- res_vsc = vec_lvrxl(0, &param_sc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vsc = vec_lvrxl(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vsc = vec_lvrxl(0, &vsc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vsc = vec_lvrxl(0, &vsc); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vuc = vec_lvrxl(0, &param_uc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vuc = vec_lvrxl(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vuc = vec_lvrxl(0, &vuc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vuc = vec_lvrxl(0, &vuc); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbc = vec_lvrxl(0, &vbc); // CHECK: store <16 x i8> zeroinitializer
@@ -2071,24 +2071,24 @@ void test6() {
// CHECK: @llvm.ppc.altivec.lvsl
// CHECK: @llvm.ppc.altivec.vperm
- res_vs = vec_lvrxl(0, &param_s); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vs = vec_lvrxl(0, &param_s); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vs = vec_lvrxl(0, &vs); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vs = vec_lvrxl(0, &vs); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vus = vec_lvrxl(0, &param_us); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vus = vec_lvrxl(0, &param_us); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vus = vec_lvrxl(0, &vus); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vus = vec_lvrxl(0, &vus); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbs = vec_lvrxl(0, &vbs); // CHECK: store <8 x i16> zeroinitializer
@@ -2101,24 +2101,24 @@ void test6() {
// CHECK: @llvm.ppc.altivec.lvsl
// CHECK: @llvm.ppc.altivec.vperm
- res_vi = vec_lvrxl(0, &param_i); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vi = vec_lvrxl(0, &param_i); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vi = vec_lvrxl(0, &vi); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vi = vec_lvrxl(0, &vi); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vui = vec_lvrxl(0, &param_ui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vui = vec_lvrxl(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
- res_vui = vec_lvrxl(0, &vui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vui = vec_lvrxl(0, &vui); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
res_vbi = vec_lvrxl(0, &vbi); // CHECK: store <4 x i32> zeroinitializer
@@ -2126,39 +2126,39 @@ void test6() {
// CHECK: @llvm.ppc.altivec.lvsl
// CHECK: @llvm.ppc.altivec.vperm
- res_vf = vec_lvrxl(0, &vf); // CHECK: store <4 x float> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvxl
+ res_vf = vec_lvrxl(0, &vf); // CHECK: @llvm.ppc.altivec.lvxl
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
/* vec_stvlx */
- vec_stvlx(vsc, 0, &param_sc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vsc, 0, &param_sc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vsc, 0, &vsc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vsc, 0, &vsc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vuc, 0, &param_uc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vuc, 0, &param_uc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vuc, 0, &vuc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vuc, 0, &vuc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2172,33 +2172,33 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vs, 0, &param_s); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vs, 0, &param_s); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vs, 0, &vs); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vs, 0, &vs); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vus, 0, &param_us); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vus, 0, &param_us); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vus, 0, &vus); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vus, 0, &vus); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2220,33 +2220,33 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vi, 0, &param_i); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vi, 0, &param_i); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vi, 0, &vi); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vi, 0, &vi); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vui, 0, &param_ui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vui, 0, &param_ui); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vui, 0, &vui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vui, 0, &vui); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2260,42 +2260,42 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
- vec_stvlx(vf, 0, &vf); // CHECK: store <4 x float> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlx(vf, 0, &vf); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
/* vec_stvlxl */
- vec_stvlxl(vsc, 0, &param_sc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vsc, 0, &param_sc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vsc, 0, &vsc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vsc, 0, &vsc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vuc, 0, &param_uc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vuc, 0, &param_uc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vuc, 0, &vuc); // CHECK: store <16 x i8> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vuc, 0, &vuc); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2309,33 +2309,33 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vs, 0, &param_s); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vs, 0, &param_s); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vs, 0, &vs); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vs, 0, &vs); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vus, 0, &param_us); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vus, 0, &param_us); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vus, 0, &vus); // CHECK: store <8 x i16> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vus, 0, &vus); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2357,33 +2357,33 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vi, 0, &param_i); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vi, 0, &param_i); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vi, 0, &vi); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vi, 0, &vi); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vui, 0, &param_ui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vui, 0, &param_ui); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vui, 0, &vui); // CHECK: store <4 x i32> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vui, 0, &vui); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2397,9 +2397,9 @@ void test6() {
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
- vec_stvlxl(vf, 0, &vf); // CHECK: store <4 x float> zeroinitializer
- // CHECK: @llvm.ppc.altivec.lvx
+ vec_stvlxl(vf, 0, &vf); // CHECK: @llvm.ppc.altivec.lvx
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2407,32 +2407,32 @@ void test6() {
/* vec_stvrx */
vec_stvrx(vsc, 0, &param_sc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vsc, 0, &vsc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vuc, 0, &param_uc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vuc, 0, &vuc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2447,32 +2447,32 @@ void test6() {
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vs, 0, &param_s); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vs, 0, &vs); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vus, 0, &param_us); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vus, 0, &vus); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2495,32 +2495,32 @@ void test6() {
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vi, 0, &param_i); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vi, 0, &vi); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vui, 0, &param_ui); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vui, 0, &vui); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2535,8 +2535,8 @@ void test6() {
// CHECK: @llvm.ppc.altivec.stvx
vec_stvrx(vf, 0, &vf); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2544,32 +2544,32 @@ void test6() {
/* vec_stvrxl */
vec_stvrxl(vsc, 0, &param_sc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vsc, 0, &vsc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vuc, 0, &param_uc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vuc, 0, &vuc); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2584,32 +2584,32 @@ void test6() {
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vs, 0, &param_s); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vs, 0, &vs); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vus, 0, &param_us); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vus, 0, &vus); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2632,32 +2632,32 @@ void test6() {
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vi, 0, &param_i); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vi, 0, &vi); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vui, 0, &param_ui); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vui, 0, &vui); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -2672,8 +2672,8 @@ void test6() {
// CHECK: @llvm.ppc.altivec.stvxl
vec_stvrxl(vf, 0, &vf); // CHECK: @llvm.ppc.altivec.lvx
- // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.lvsl
+ // CHECK: store <4 x float> zeroinitializer
// CHECK: @llvm.ppc.altivec.vperm
// CHECK: @llvm.ppc.altivec.lvsr
// CHECK: @llvm.ppc.altivec.vperm
@@ -3053,7 +3053,7 @@ void test6() {
res_i = vec_any_out(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpbfp.p
}
-/* ------------------------------ Relational Operators------------------------------- */
+/* ------------------------------ Relational Operators ------------------------------ */
// CHECK: define void @test7
void test7() {
vector signed char vsc1 = (vector signed char)(-1);
@@ -3113,14 +3113,3 @@ void test7() {
res_i = (vf1 <= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2
res_i = (vf1 >= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2
}
-
-/* ------------------------------- increment/decrement: ----------------------------- */
-// CHECK: define void @test8
-void test8() {
- vector int vi;
- vi++; // CHECK: add nsw <4 x i32> {{.*}} <i32 1, i32 1, i32 1, i32 1>
- vector unsigned int vui;
- --vui; // CHECK: add <4 x i32> {{.*}} <i32 -1, i32 -1, i32 -1, i32 -1>
- vector float vf;
- vf++; // CHECK: fadd <4 x float> {{.*}} <float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}>
-}
diff --git a/test/CodeGen/builtins-ptx.c b/test/CodeGen/builtins-ptx.c
new file mode 100644
index 000000000000..6dd10188e9fb
--- /dev/null
+++ b/test/CodeGen/builtins-ptx.c
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -triple ptx32-unknown-unknown -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple ptx64-unknown-unknown -emit-llvm -o %t %s
+
+
+int read_tid() {
+
+ int x = __builtin_ptx_read_tid_x();
+ int y = __builtin_ptx_read_tid_y();
+ int z = __builtin_ptx_read_tid_z();
+ int w = __builtin_ptx_read_tid_w();
+
+ return x + y + z + w;
+
+}
+
+int read_ntid() {
+
+ int x = __builtin_ptx_read_ntid_x();
+ int y = __builtin_ptx_read_ntid_y();
+ int z = __builtin_ptx_read_ntid_z();
+ int w = __builtin_ptx_read_ntid_w();
+
+ return x + y + z + w;
+
+}
+
+int read_ctaid() {
+
+ int x = __builtin_ptx_read_ctaid_x();
+ int y = __builtin_ptx_read_ctaid_y();
+ int z = __builtin_ptx_read_ctaid_z();
+ int w = __builtin_ptx_read_ctaid_w();
+
+ return x + y + z + w;
+
+}
+
+int read_nctaid() {
+
+ int x = __builtin_ptx_read_nctaid_x();
+ int y = __builtin_ptx_read_nctaid_y();
+ int z = __builtin_ptx_read_nctaid_z();
+ int w = __builtin_ptx_read_nctaid_w();
+
+ return x + y + z + w;
+
+}
+
+int read_ids() {
+
+ int a = __builtin_ptx_read_laneid();
+ int b = __builtin_ptx_read_warpid();
+ int c = __builtin_ptx_read_nwarpid();
+ int d = __builtin_ptx_read_smid();
+ int e = __builtin_ptx_read_nsmid();
+ int f = __builtin_ptx_read_gridid();
+
+ return a + b + c + d + e + f;
+
+}
+
+int read_lanemasks() {
+
+ int a = __builtin_ptx_read_lanemask_eq();
+ int b = __builtin_ptx_read_lanemask_le();
+ int c = __builtin_ptx_read_lanemask_lt();
+ int d = __builtin_ptx_read_lanemask_ge();
+ int e = __builtin_ptx_read_lanemask_gt();
+
+ return a + b + c + d + e;
+
+}
+
+
+long read_clocks() {
+
+ int a = __builtin_ptx_read_clock();
+ long b = __builtin_ptx_read_clock64();
+
+ return (long)a + b;
+
+}
+
+int read_pms() {
+
+ int a = __builtin_ptx_read_pm0();
+ int b = __builtin_ptx_read_pm1();
+ int c = __builtin_ptx_read_pm2();
+ int d = __builtin_ptx_read_pm3();
+
+ return a + b + c + d;
+
+}
+
+void sync() {
+
+ __builtin_ptx_bar_sync(0);
+
+}
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index 56f220b8a6e8..bb63048b6166 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -273,7 +273,6 @@ void f0() {
#endif
tmp_V2i = __builtin_ia32_cvttps2pi(tmp_V4f);
(void) __builtin_ia32_maskmovq(tmp_V8c, tmp_V8c, tmp_cp);
- tmp_V4f = __builtin_ia32_loadups(tmp_fCp);
(void) __builtin_ia32_storeups(tmp_fp, tmp_V4f);
(void) __builtin_ia32_storehps(tmp_V2ip, tmp_V4f);
(void) __builtin_ia32_storelps(tmp_V2ip, tmp_V4f);
@@ -291,7 +290,6 @@ void f0() {
tmp_V4f = __builtin_ia32_sqrtps(tmp_V4f);
tmp_V4f = __builtin_ia32_sqrtss(tmp_V4f);
(void) __builtin_ia32_maskmovdqu(tmp_V16c, tmp_V16c, tmp_cp);
- tmp_V2d = __builtin_ia32_loadupd(tmp_dCp);
(void) __builtin_ia32_storeupd(tmp_dp, tmp_V2d);
tmp_i = __builtin_ia32_movmskpd(tmp_V2d);
tmp_i = __builtin_ia32_pmovmskb128(tmp_V16c);
@@ -481,4 +479,33 @@ void f0() {
__builtin_ia32_maskstoreps(tmp_V4fp, tmp_V4f, tmp_V4f);
__builtin_ia32_maskstorepd256(tmp_V4dp, tmp_V4d, tmp_V4d);
__builtin_ia32_maskstoreps256(tmp_V8fp, tmp_V8f, tmp_V8f);
+
+#ifdef USE_3DNOW
+ tmp_V8c = __builtin_ia32_pavgusb(tmp_V8c, tmp_V8c);
+ tmp_V2i = __builtin_ia32_pf2id(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfacc(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfadd(tmp_V2f, tmp_V2f);
+ tmp_V2i = __builtin_ia32_pfcmpeq(tmp_V2f, tmp_V2f);
+ tmp_V2i = __builtin_ia32_pfcmpge(tmp_V2f, tmp_V2f);
+ tmp_V2i = __builtin_ia32_pfcmpgt(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfmax(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfmin(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfmul(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrcp(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrcpit1(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrcpit2(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrsqrt(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrsqit1(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfrsqrtit1(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfsub(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfsubr(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pi2fd(tmp_V2i);
+ tmp_V4s = __builtin_ia32_pmulhrw(tmp_V4s, tmp_V4s);
+ tmp_V2i = __builtin_ia32_pf2iw(tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfnacc(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pfpnacc(tmp_V2f, tmp_V2f);
+ tmp_V2f = __builtin_ia32_pi2fw(tmp_V2i);
+ tmp_V2f = __builtin_ia32_pswapdsf(tmp_V2f);
+ tmp_V2i = __builtin_ia32_pswapdsi(tmp_V2i);
+#endif
}
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index 40f77249f918..fca087e197fc 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -138,7 +138,7 @@ void bar() {
// LLVM's hex representation of float constants is really unfortunate;
// basically it does a float-to-double "conversion" and then prints the
- // hex form of that. That gives us wierd artifacts like exponents
+ // hex form of that. That gives us weird artifacts like exponents
// that aren't numerically similar to the original exponent and
// significand bit-patterns that are offset by three bits (because
// the exponent was expanded from 8 bits to 11).
diff --git a/test/CodeGen/char-literal.c b/test/CodeGen/char-literal.c
index aff76d280d30..322041c0049a 100644
--- a/test/CodeGen/char-literal.c
+++ b/test/CodeGen/char-literal.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x c++ -triple i386-unknown-unkown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// Runs in c++ mode so that wchar_t is available.
int main() {
diff --git a/test/CodeGen/conditional.c b/test/CodeGen/conditional.c
index d079aafd787a..15e15f11e35f 100644
--- a/test/CodeGen/conditional.c
+++ b/test/CodeGen/conditional.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o %t
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
float test1(int cond, float a, float b) {
return cond ? a : b;
@@ -47,3 +47,22 @@ void test9(struct test9 *p) {
p ? p : test9spare();
}
+// CHECK: @test10
+// CHECK: select i1 {{.*}}, i32 4, i32 5
+int test10(int c) {
+ return c ? 4 : 5;
+}
+enum { Gronk = 5 };
+
+// rdar://9289603
+// CHECK: @test11
+// CHECK: select i1 {{.*}}, i32 4, i32 5
+int test11(int c) {
+ return c ? 4 : Gronk;
+}
+
+// CHECK: @test12
+// CHECK: select i1 {{.*}}, double 4.0{{.*}}, double 2.0
+double test12(int c) {
+ return c ? 4.0 : 2.0;
+}
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index 32b762d646e6..c6778630a0a0 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -4,6 +4,10 @@
// Brace-enclosed string array initializers
char a[] = { "asdf" };
+// CHECK: @a = global [5 x i8] c"asdf\00"
+
+char a2[2][5] = { "asdf" };
+// CHECK: @a2 = global [2 x [5 x i8]] {{\[}}[5 x i8] c"asdf\00", [5 x i8] zeroinitializer]
// Double-implicit-conversions of array/functions (not legal C, but
// clang accepts it for gcc compat).
diff --git a/test/CodeGen/darwin-string-literals.c b/test/CodeGen/darwin-string-literals.c
index ef5601e8f224..6f9e0d2a63ed 100644
--- a/test/CodeGen/darwin-string-literals.c
+++ b/test/CodeGen/darwin-string-literals.c
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix LSB %s
// CHECK-LSB: @.str = private unnamed_addr constant [8 x i8] c"string0\00"
-// CHECK-LSB: @.str1 = private unnamed_addr constant [8 x i8] c"string1\00"
+// CHECK-LSB: @.str1 = linker_private unnamed_addr constant [8 x i8] c"string1\00"
// CHECK-LSB: @.str2 = internal unnamed_addr constant [36 x i8] c"h\00e\00l\00l\00o\00 \00\92! \00\03& \00\90! \00w\00o\00r\00l\00d\00\00\00", align 2
// RUN: %clang_cc1 -triple powerpc-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix MSB %s
// CHECK-MSB: @.str = private unnamed_addr constant [8 x i8] c"string0\00"
-// CHECK-MSB: @.str1 = private unnamed_addr constant [8 x i8] c"string1\00"
+// CHECK-MSB: @.str1 = linker_private unnamed_addr constant [8 x i8] c"string1\00"
// CHECK-MSB: @.str2 = internal unnamed_addr constant [36 x i8] c"\00h\00e\00l\00l\00o\00 !\92\00 &\03\00 !\90\00 \00w\00o\00r\00l\00d\00\00", align 2
const char *g0 = "string0";
diff --git a/test/CodeGen/debug-info-line2.c b/test/CodeGen/debug-info-line2.c
new file mode 100644
index 000000000000..b5eba8a1a060
--- /dev/null
+++ b/test/CodeGen/debug-info-line2.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-darwin-apple -g -emit-llvm -o - %s | FileCheck %s
+// Radar 9199234
+
+int bar();
+int foo(int i) {
+ int j = 0;
+ if (i) {
+ j = bar();
+//CHECK: store i32
+//CHECK-NOT: br label %{{%[a-zA-Z0-9\.]+}}, !dbg
+ }
+ else
+ {
+ j = bar() + 2;
+ }
+ return j;
+}
diff --git a/test/CodeGen/decl.c b/test/CodeGen/decl.c
index 5be421623616..7a9971ee1812 100644
--- a/test/CodeGen/decl.c
+++ b/test/CodeGen/decl.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -w -emit-llvm < %s | FileCheck %s
-// CHECK: @test1.x = private constant [12 x i32] [i32 1
+// CHECK: @test1.x = internal constant [12 x i32] [i32 1
// CHECK: @test2.x = internal constant [13 x i32] [i32 1,
// CHECK: @test5w = global %0 { i32 2, [4 x i8] undef }
// CHECK: @test5y = global %union.test5u { double 7.300000e+0{{[0]*}}1 }
diff --git a/test/CodeGen/ext-vector.c b/test/CodeGen/ext-vector.c
index daa18265a49f..1abd9f27ae12 100644
--- a/test/CodeGen/ext-vector.c
+++ b/test/CodeGen/ext-vector.c
@@ -1,13 +1,18 @@
-// RUN: %clang_cc1 -emit-llvm-only %s
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
typedef __attribute__(( ext_vector_type(4) )) float float4;
typedef __attribute__(( ext_vector_type(2) )) float float2;
typedef __attribute__(( ext_vector_type(4) )) int int4;
+typedef __attribute__(( ext_vector_type(4) )) unsigned int uint4;
+// CHECK: @foo = global <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00>
float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 };
+// CHECK: @bar = constant <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 0x7FF0000000000000>
const float4 bar = (float4){ 1.0, 2.0, 3.0, __builtin_inff() };
+// CHECK: @test1
+// CHECK: fadd <4 x float>
float4 test1(float4 V) {
return V.wzyx+V;
}
@@ -16,6 +21,12 @@ float2 vec2, vec2_2;
float4 vec4, vec4_2;
float f;
+// CHECK: @test2
+// CHECK: shufflevector {{.*}} <i32 0, i32 1>
+// CHECK: extractelement
+// CHECK: shufflevector {{.*}} <i32 1, i32 1, i32 1, i32 1>
+// CHECK: insertelement
+// CHECK: shufflevector {{.*}} <i32 1, i32 0>
void test2() {
vec2 = vec4.xy; // shorten
f = vec2.x; // extract elt
@@ -25,10 +36,15 @@ void test2() {
vec2.yx = vec2; // reverse
}
+// CHECK: @test3
+// CHECK: store <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00>
void test3(float4 *out) {
*out = ((float4) {1.0f, 2.0f, 3.0f, 4.0f });
}
+// CHECK: @test4
+// CHECK: store <4 x float>
+// CHECK: store <4 x float>
void test4(float4 *out) {
float a = 1.0f;
float b = 2.0f;
@@ -37,6 +53,12 @@ void test4(float4 *out) {
*out = ((float4) {a,b,c,d});
}
+// CHECK: @test5
+// CHECK: shufflevector {{.*}} <4 x i32> zeroinitializer
+// CHECK: fmul <4 x float>
+// CHECK: fmul <4 x float>
+// CHECK: shufflevector {{.*}} <4 x i32> zeroinitializer
+// CHECK: fmul <4 x float>
void test5(float4 *out) {
float a;
float4 b;
@@ -50,25 +72,42 @@ void test5(float4 *out) {
*out = b;
}
+// CHECK: @test6
void test6(float4 *ap, float4 *bp, float c) {
float4 a = *ap;
float4 b = *bp;
-
+
+ // CHECK: fadd <4 x float>
+ // CHECK: fsub <4 x float>
+ // CHECK: fmul <4 x float>
+ // CHECK: fdiv <4 x float>
a = a + b;
a = a - b;
a = a * b;
a = a / b;
-
+
+ // CHECK: fadd <4 x float>
+ // CHECK: fsub <4 x float>
+ // CHECK: fmul <4 x float>
+ // CHECK: fdiv <4 x float>
a = a + c;
a = a - c;
a = a * c;
a = a / c;
+ // CHECK: fadd <4 x float>
+ // CHECK: fsub <4 x float>
+ // CHECK: fmul <4 x float>
+ // CHECK: fdiv <4 x float>
a += b;
a -= b;
a *= b;
a /= b;
-
+
+ // CHECK: fadd <4 x float>
+ // CHECK: fsub <4 x float>
+ // CHECK: fmul <4 x float>
+ // CHECK: fdiv <4 x float>
a += c;
a -= c;
a *= c;
@@ -87,76 +126,153 @@ void test6(float4 *ap, float4 *bp, float c) {
#endif
}
+// CHECK: @test7
void test7(int4 *ap, int4 *bp, int c) {
int4 a = *ap;
int4 b = *bp;
-
+
+ // CHECK: add nsw <4 x i32>
+ // CHECK: sub nsw <4 x i32>
+ // CHECK: mul nsw <4 x i32>
+ // CHECK: sdiv <4 x i32>
+ // CHECK: srem <4 x i32>
a = a + b;
a = a - b;
a = a * b;
a = a / b;
a = a % b;
-
+
+ // CHECK: add nsw <4 x i32>
+ // CHECK: sub nsw <4 x i32>
+ // CHECK: mul nsw <4 x i32>
+ // CHECK: sdiv <4 x i32>
+ // CHECK: srem <4 x i32>
a = a + c;
a = a - c;
a = a * c;
a = a / c;
a = a % c;
+ // CHECK: add nsw <4 x i32>
+ // CHECK: sub nsw <4 x i32>
+ // CHECK: mul nsw <4 x i32>
+ // CHECK: sdiv <4 x i32>
+ // CHECK: srem <4 x i32>
a += b;
a -= b;
a *= b;
a /= b;
a %= b;
-
+
+ // CHECK: add nsw <4 x i32>
+ // CHECK: sub nsw <4 x i32>
+ // CHECK: mul nsw <4 x i32>
+ // CHECK: sdiv <4 x i32>
+ // CHECK: srem <4 x i32>
a += c;
a -= c;
a *= c;
a /= c;
a %= c;
+
// Vector comparisons.
+ // CHECK: icmp slt
+ // CHECK: icmp sle
+ // CHECK: icmp sgt
+ // CHECK: icmp sge
+ // CHECK: icmp eq
+ // CHECK: icmp ne
int4 cmp;
cmp = a < b;
cmp = a <= b;
- cmp = a < b;
+ cmp = a > b;
cmp = a >= b;
cmp = a == b;
cmp = a != b;
}
+// CHECK: @test8
void test8(float4 *ap, float4 *bp, int c) {
float4 a = *ap;
float4 b = *bp;
// Vector comparisons.
+ // CHECK: fcmp olt
+ // CHECK: fcmp ole
+ // CHECK: fcmp ogt
+ // CHECK: fcmp oge
+ // CHECK: fcmp oeq
+ // CHECK: fcmp une
int4 cmp;
cmp = a < b;
cmp = a <= b;
- cmp = a < b;
+ cmp = a > b;
cmp = a >= b;
cmp = a == b;
cmp = a != b;
}
+// CHECK: @test9
+// CHECK: extractelement <4 x i32>
int test9(int4 V) {
return V.xy.x;
}
+// CHECK: @test10
+// CHECK: add nsw <4 x i32>
+// CHECK: extractelement <4 x i32>
int test10(int4 V) {
return (V+V).x;
}
+// CHECK: @test11
+// CHECK: extractelement <4 x i32>
int4 test11a();
int test11() {
return test11a().x;
}
+// CHECK: @test12
+// CHECK: shufflevector {{.*}} <i32 2, i32 1, i32 0>
+// CHECK: shufflevector {{.*}} <i32 0, i32 1, i32 2, i32 undef>
+// CHECK: shufflevector {{.*}} <i32 4, i32 5, i32 6, i32 3>
int4 test12(int4 V) {
V.xyz = V.zyx;
return V;
}
+// CHECK: @test13
+// CHECK: shufflevector {{.*}} <i32 2, i32 1, i32 0, i32 3>
int4 test13(int4 *V) {
return V->zyxw;
}
+
+// CHECK: @test14
+void test14(uint4 *ap, uint4 *bp, unsigned c) {
+ uint4 a = *ap;
+ uint4 b = *bp;
+
+ // CHECK: udiv <4 x i32>
+ // CHECK: urem <4 x i32>
+ a = a / b;
+ a = a % b;
+
+ // CHECK: udiv <4 x i32>
+ // CHECK: urem <4 x i32>
+ a = a / c;
+ a = a % c;
+
+ // CHECK: icmp ult
+ // CHECK: icmp ule
+ // CHECK: icmp ugt
+ // CHECK: icmp uge
+ // CHECK: icmp eq
+ // CHECK: icmp ne
+ a = a < b;
+ a = a <= b;
+ a = a > b;
+ a = a >= b;
+ a = a == b;
+ a = a != b;
+}
diff --git a/test/CodeGen/integer-overflow.c b/test/CodeGen/integer-overflow.c
index 103cc8427bb0..1d460656a1c7 100644
--- a/test/CodeGen/integer-overflow.c
+++ b/test/CodeGen/integer-overflow.c
@@ -49,4 +49,18 @@ void test1() {
// TRAPV: llvm.sadd.with.overflow.i32({{.*}}, i32 -1)
// TRAPV_HANDLER: foo(
--a;
+
+ // -fwrapv should turn off inbounds for GEP's, PR9256
+ extern int* P;
+ ++P;
+ // DEFAULT: getelementptr inbounds i32*
+ // WRAPV: getelementptr i32*
+ // TRAPV: getelementptr inbounds i32*
+
+ // PR9350: char increment never overflows.
+ extern volatile signed char PR9350;
+ // DEFAULT: add i8 {{.*}}, 1
+ // WRAPV: add i8 {{.*}}, 1
+ // TRAPV: add i8 {{.*}}, 1
+ ++PR9350;
}
diff --git a/test/CodeGen/mangle.c b/test/CodeGen/mangle.c
index 3bbd9c8b807e..46ef512f6950 100644
--- a/test/CodeGen/mangle.c
+++ b/test/CodeGen/mangle.c
@@ -63,3 +63,12 @@ int func(void) {
// CHECK: @_Z4foo9Dv4_f
typedef __attribute__(( vector_size(16) )) float float4;
void __attribute__((__overloadable__)) foo9(float4 f) {}
+
+// Intrinsic calls.
+extern int llvm_cas(volatile int*, int, int)
+ __asm__("llvm.atomic.cmp.swap.i32.p0i32");
+
+int foo10(volatile int* add, int from, int to) {
+ // CHECK: call i32 @llvm.atomic.cmp.swap.i32.p0i32
+ return llvm_cas(add, from, to);
+}
diff --git a/test/CodeGen/mmx-inline-asm.c b/test/CodeGen/mmx-inline-asm.c
new file mode 100644
index 000000000000..c473a930ecc8
--- /dev/null
+++ b/test/CodeGen/mmx-inline-asm.c
@@ -0,0 +1,22 @@
+// RUN: %clang -mmmx -ccc-host-triple i386-unknown-unknown -emit-llvm -S %s -o - | FileCheck %s
+// <rdar://problem/9091220>
+#include <mmintrin.h>
+
+// CHECK: type { x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx, x86_mmx }
+
+void foo(long long fill) {
+ __m64 vfill = _mm_cvtsi64_m64(fill);
+ __m64 v1, v2, v3, v4, v5, v6, v7;
+
+ __asm__ __volatile__ (
+ "\tmovq %7, %0\n"
+ "\tmovq %7, %1\n"
+ "\tmovq %7, %2\n"
+ "\tmovq %7, %3\n"
+ "\tmovq %7, %4\n"
+ "\tmovq %7, %5\n"
+ "\tmovq %7, %6"
+ : "=&y" (v1), "=&y" (v2), "=&y" (v3),
+ "=&y" (v4), "=&y" (v5), "=&y" (v6), "=y" (v7)
+ : "y" (vfill));
+}
diff --git a/test/CodeGen/mrtd.c b/test/CodeGen/mrtd.c
new file mode 100644
index 000000000000..2cc71bb0086f
--- /dev/null
+++ b/test/CodeGen/mrtd.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -mrtd -triple i386-unknown-freebsd9.0 -emit-llvm -o - %s | FileCheck %s
+
+void baz(int arg);
+
+// CHECK: define x86_stdcallcc void @foo(i32 %arg) nounwind
+void foo(int arg) {
+// CHECK: call x86_stdcallcc i32 (...)* @bar(i32
+ bar(arg);
+// CHECK: call x86_stdcallcc void @baz(i32
+ baz(arg);
+}
+
+// CHECK: declare x86_stdcallcc i32 @bar(...)
+
+// CHECK: declare x86_stdcallcc void @baz(i32)
diff --git a/test/CodeGen/ms_struct-bitfield-init.c b/test/CodeGen/ms_struct-bitfield-init.c
new file mode 100644
index 000000000000..7a483fb84b8b
--- /dev/null
+++ b/test/CodeGen/ms_struct-bitfield-init.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-darwin9 %s
+// rdar://8823265
+
+extern void abort(void);
+#define ATTR __attribute__((__ms_struct__))
+
+struct
+{
+ char foo;
+ long : 0;
+ char : 0;
+ int : 0;
+ char bar;
+} ATTR t1 = {'a', 'b'};
+
+struct
+{
+ char bar0;
+ long : 0;
+ int : 0;
+ char bar1;
+ char bar2;
+ long : 0;
+ char bar3;
+ char bar4;
+ char : 0;
+ char bar5;
+ char bar6;
+ char : 0;
+ char bar7;
+ char bar8;
+} ATTR t2 = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
+
+struct {
+ int : 0;
+ int i1;
+ int : 0;
+ int i2;
+ int : 0;
+ int i3;
+ int : 0;
+ int i4;
+} t3 = {1,2,3,4};
+
+int main() {
+ if (sizeof(t1) != 2)
+ abort();
+ if (t1.foo != 'a')
+ abort();
+ if (t1.bar != 'b')
+ abort();
+ t1.foo = 'c';
+ t1.bar = 'd';
+ if (t1.foo != 'c')
+ abort();
+ if (t1.bar != 'd')
+ abort();
+ if (sizeof(t2) != 9)
+ abort();
+ if (t2.bar0 != 'a' || t2.bar8 != 'i')
+ abort();
+ if (sizeof(t3) != 16)
+ abort();
+ if (t3.i1 != 1 || t3.i4 != 4)
+ abort();
+ return 0;
+}
+
diff --git a/test/CodeGen/ms_struct-bitfield.c b/test/CodeGen/ms_struct-bitfield.c
new file mode 100644
index 000000000000..a8f4c91a4937
--- /dev/null
+++ b/test/CodeGen/ms_struct-bitfield.c
@@ -0,0 +1,131 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-darwin9 %s
+// rdar://8823265
+
+#define ATTR __attribute__((__ms_struct__))
+
+struct
+{
+ char foo;
+ long : 0;
+ char bar;
+} ATTR t1;
+
+struct
+{
+ char foo;
+ long : 0;
+ char : 0;
+ int : 0;
+ char bar;
+} ATTR t2;
+
+struct
+{
+ char foo;
+ long : 0;
+ char : 0;
+ int : 0;
+ char bar;
+ long : 0;
+ char : 0;
+} ATTR t3;
+
+struct
+{
+ long : 0;
+ char bar;
+} ATTR t4;
+
+struct
+{
+ long : 0;
+ long : 0;
+ char : 0;
+ char bar;
+} ATTR t5;
+
+struct
+{
+ long : 0;
+ long : 0;
+ char : 0;
+ char bar;
+} ATTR t6;
+
+struct
+{
+ char foo;
+ long : 0;
+ int : 0;
+ char bar;
+ char bar1;
+ long : 0;
+ char bar2;
+ char bar3;
+ char : 0;
+ char bar4;
+ char bar5;
+ char : 0;
+ char bar6;
+ char bar7;
+} ATTR t7;
+
+struct
+{
+ long : 0;
+ long : 0;
+ char : 0;
+} ATTR t8;
+
+struct
+{
+ char foo;
+ long : 0;
+ int : 0;
+ char bar;
+ char bar1;
+ long : 0;
+ char bar2;
+ char bar3;
+ char : 0;
+ char bar4;
+ char bar5;
+ char : 0;
+ char bar6;
+ char bar7;
+ int i1;
+ char : 0;
+ long : 0;
+ char :4;
+ char bar8;
+ char : 0;
+ char bar9;
+ char bar10;
+ int i2;
+ char : 0;
+ long : 0;
+ char :4;
+} ATTR t9;
+
+struct
+{
+ char foo: 8;
+ long : 0;
+ char bar;
+} ATTR t10;
+
+static int arr1[(sizeof(t1) == 2) -1];
+static int arr2[(sizeof(t2) == 2) -1];
+static int arr3[(sizeof(t3) == 2) -1];
+static int arr4[(sizeof(t4) == 1) -1];
+static int arr5[(sizeof(t5) == 1) -1];
+static int arr6[(sizeof(t6) == 1) -1];
+static int arr7[(sizeof(t7) == 9) -1];
+static int arr8[(sizeof(t8) == 0) -1];
+static int arr9[(sizeof(t9) == 28) -1];
+static int arr10[(sizeof(t10) == 16) -1];
+
+int main() {
+ return 0;
+}
+
diff --git a/test/CodeGen/mult-alt-x86.c b/test/CodeGen/mult-alt-x86.c
index 84011f2d5303..4e2a69d85bdd 100644
--- a/test/CodeGen/mult-alt-x86.c
+++ b/test/CodeGen/mult-alt-x86.c
@@ -194,70 +194,70 @@ void single_Z()
void multi_R()
{
// CHECK: asm "foo $1,$0", "=*r|R|m,r|R|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=R,=m" (mout0) : "r,R,m" (min1));
+ asm("foo %1,%0" : "=r,R,m" (mout0) : "r,R,m" (min1));
}
// CHECK: @multi_q
void multi_q()
{
// CHECK: asm "foo $1,$0", "=*r|q|m,r|q|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=q,=m" (mout0) : "r,q,m" (min1));
+ asm("foo %1,%0" : "=r,q,m" (mout0) : "r,q,m" (min1));
}
// CHECK: @multi_Q
void multi_Q()
{
// CHECK: asm "foo $1,$0", "=*r|Q|m,r|Q|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=Q,=m" (mout0) : "r,Q,m" (min1));
+ asm("foo %1,%0" : "=r,Q,m" (mout0) : "r,Q,m" (min1));
}
// CHECK: @multi_a
void multi_a()
{
// CHECK: asm "foo $1,$0", "=*r|{ax}|m,r|{ax}|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=a,=m" (mout0) : "r,a,m" (min1));
+ asm("foo %1,%0" : "=r,a,m" (mout0) : "r,a,m" (min1));
}
// CHECK: @multi_b
void multi_b()
{
// CHECK: asm "foo $1,$0", "=*r|{bx}|m,r|{bx}|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=b,=m" (mout0) : "r,b,m" (min1));
+ asm("foo %1,%0" : "=r,b,m" (mout0) : "r,b,m" (min1));
}
// CHECK: @multi_c
void multi_c()
{
// CHECK: asm "foo $1,$0", "=*r|{cx}|m,r|{cx}|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=c,=m" (mout0) : "r,c,m" (min1));
+ asm("foo %1,%0" : "=r,c,m" (mout0) : "r,c,m" (min1));
}
// CHECK: @multi_d
void multi_d()
{
- // CHECK: asm "foo $1,$0", "=*r|{dx}|m,r|{dx}[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=d,=m" (mout0) : "r,d" (min1));
+ // CHECK: asm "foo $1,$0", "=*r|{dx}|m,r|{dx}|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
+ asm("foo %1,%0" : "=r,d,m" (mout0) : "r,d,m" (min1));
}
// CHECK: @multi_S
void multi_S()
{
// CHECK: asm "foo $1,$0", "=*r|{si}|m,r|{si}|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=S,=m" (mout0) : "r,S,m" (min1));
+ asm("foo %1,%0" : "=r,S,m" (mout0) : "r,S,m" (min1));
}
// CHECK: @multi_D
void multi_D()
{
// CHECK: asm "foo $1,$0", "=*r|{di}|m,r|{di}|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=D,=m" (mout0) : "r,D,m" (min1));
+ asm("foo %1,%0" : "=r,D,m" (mout0) : "r,D,m" (min1));
}
// CHECK: @multi_A
void multi_A()
{
// CHECK: asm "foo $1,$0", "=*r|A|m,r|A|m[[CLOBBERS]](i32* @mout0, i32 {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=A,=m" (mout0) : "r,A,m" (min1));
+ asm("foo %1,%0" : "=r,A,m" (mout0) : "r,A,m" (min1));
}
// CHECK: @multi_f
@@ -282,93 +282,93 @@ void multi_u()
void multi_y()
{
// CHECK: asm "foo $1,$0", "=*r|y|m,r|y|m[[CLOBBERS]](double* @dout0, double {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=y,=m" (dout0) : "r,y,m" (din1));
+ asm("foo %1,%0" : "=r,y,m" (dout0) : "r,y,m" (din1));
}
// CHECK: @multi_x
void multi_x()
{
// CHECK: asm "foo $1,$0", "=*r|x|m,r|x|m[[CLOBBERS]](double* @dout0, double {{[a-zA-Z0-9@%]+}})
- asm("foo %1,%0" : "=r,=x,=m" (dout0) : "r,x,m" (din1));
+ asm("foo %1,%0" : "=r,x,m" (dout0) : "r,x,m" (din1));
}
// CHECK: @multi_Y
void multi_Y0()
{
// Y constraint currently broken.
- //asm("foo %1,%0" : "=r,=Y0,=m" (mout0) : "r,Y0,m" (min1));
- //asm("foo %1,%0" : "=r,=Yz,=m" (mout0) : "r,Yz,m" (min1));
- //asm("foo %1,%0" : "=r,=Yt,=m" (mout0) : "r,Yt,m" (min1));
- //asm("foo %1,%0" : "=r,=Yi,=m" (mout0) : "r,Yi,m" (min1));
- //asm("foo %1,%0" : "=r,=Ym,=m" (mout0) : "r,Ym,m" (min1));
+ //asm("foo %1,%0" : "=r,Y0,m" (mout0) : "r,Y0,m" (min1));
+ //asm("foo %1,%0" : "=r,Yz,m" (mout0) : "r,Yz,m" (min1));
+ //asm("foo %1,%0" : "=r,Yt,m" (mout0) : "r,Yt,m" (min1));
+ //asm("foo %1,%0" : "=r,Yi,m" (mout0) : "r,Yi,m" (min1));
+ //asm("foo %1,%0" : "=r,Ym,m" (mout0) : "r,Ym,m" (min1));
}
// CHECK: @multi_I
void multi_I()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|I|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,I,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,I,m" (1));
}
// CHECK: @multi_J
void multi_J()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|J|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,J,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,J,m" (1));
}
// CHECK: @multi_K
void multi_K()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|K|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,K,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,K,m" (1));
}
// CHECK: @multi_L
void multi_L()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|L|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,L,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,L,m" (1));
}
// CHECK: @multi_M
void multi_M()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|M|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,M,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,M,m" (1));
}
// CHECK: @multi_N
void multi_N()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|N|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,N,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,N,m" (1));
}
// CHECK: @multi_G
void multi_G()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|G|m[[CLOBBERS]](i32* @mout0, double {{1.[0]+e[+]*[0]+}})
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,G,m" (1.0));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,G,m" (1.0));
}
// CHECK: @multi_C
void multi_C()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|C|m[[CLOBBERS]](i32* @mout0, double {{1.[0]+e[+]*[0]+}})
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,C,m" (1.0));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,C,m" (1.0));
}
// CHECK: @multi_e
void multi_e()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|e|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,e,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,e,m" (1));
}
// CHECK: @multi_Z
void multi_Z()
{
// CHECK: asm "foo $1,$0", "=*r|m|m,r|Z|m[[CLOBBERS]](i32* @mout0, i32 1)
- asm("foo %1,%0" : "=r,=m,=m" (mout0) : "r,Z,m" (1));
+ asm("foo %1,%0" : "=r,m,m" (mout0) : "r,Z,m" (1));
}
diff --git a/test/CodeGen/packed-arrays.c b/test/CodeGen/packed-arrays.c
new file mode 100644
index 000000000000..785db4d2dde2
--- /dev/null
+++ b/test/CodeGen/packed-arrays.c
@@ -0,0 +1,157 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -emit-llvm -Os -o %t %s
+// RUN: FileCheck < %t %s
+
+struct s0 {
+ unsigned int x[2] __attribute__((packed));
+};
+
+struct s1 {
+ unsigned int x[2] __attribute__((packed));
+ unsigned int y;
+ unsigned int z __attribute__((packed));
+};
+
+struct s2 {
+ unsigned int x[2] __attribute__((packed));
+ unsigned int y __attribute__((packed));
+ unsigned int z __attribute__((packed));
+};
+
+struct __attribute__((packed)) s3 {
+ unsigned int x[2];
+ unsigned int y;
+ unsigned int z;
+};
+
+// CHECK: @align0 = global i32 1
+int align0 = __alignof(struct s0);
+// CHECK: @align1 = global i32 4
+int align1 = __alignof(struct s1);
+// CHECK: @align2 = global i32 1
+int align2 = __alignof(struct s2);
+// CHECK: @align3 = global i32 1
+int align3 = __alignof(struct s3);
+
+// CHECK: @align0_x = global i32 1
+int align0_x = __alignof(((struct s0*) 0)->x);
+// We are currently incompatible with GCC here. <rdar://problem/9217290>
+//
+// CHECK-XFAIL: @align1_x = global i32 1
+// CHECK: @align1_x = global i32 4
+int align1_x = __alignof(((struct s1*) 0)->x);
+// CHECK: @align2_x = global i32 1
+int align2_x = __alignof(((struct s2*) 0)->x);
+// CHECK: @align3_x = global i32 1
+int align3_x = __alignof(((struct s3*) 0)->x);
+
+// CHECK: @align0_x0 = global i32 4
+int align0_x0 = __alignof(((struct s0*) 0)->x[0]);
+// CHECK: @align1_x0 = global i32 4
+int align1_x0 = __alignof(((struct s1*) 0)->x[0]);
+// CHECK: @align2_x0 = global i32 4
+int align2_x0 = __alignof(((struct s2*) 0)->x[0]);
+// CHECK: @align3_x0 = global i32 4
+int align3_x0 = __alignof(((struct s3*) 0)->x[0]);
+
+// CHECK: define i32 @f0_a
+// CHECK: load i32* %{{.*}}, align 1
+// CHECK: }
+// CHECK: define i32 @f0_b
+// CHECK: load i32* %{{.*}}, align 4
+// CHECK: }
+int f0_a(struct s0 *a) {
+ return a->x[1];
+}
+int f0_b(struct s0 *a) {
+ return *(a->x + 1);
+}
+
+// CHECK: define i32 @f1_a
+// CHECK: load i32* %{{.*}}, align 4
+// CHECK: }
+// CHECK: define i32 @f1_b
+// CHECK: load i32* %{{.*}}, align 4
+// CHECK: }
+
+// Note that we are incompatible with GCC on these two examples.
+//
+// CHECK: define i32 @f1_c
+// CHECK-XFAIL: load i32* %{{.*}}, align 1
+// CHECK: load i32* %{{.*}}, align 4
+// CHECK: }
+// CHECK: define i32 @f1_d
+// CHECK-XFAIL: load i32* %{{.*}}, align 1
+// CHECK: load i32* %{{.*}}, align 4
+// CHECK: }
+int f1_a(struct s1 *a) {
+ return a->x[1];
+}
+int f1_b(struct s1 *a) {
+ return *(a->x + 1);
+}
+int f1_c(struct s1 *a) {
+ return a->y;
+}
+int f1_d(struct s1 *a) {
+ return a->z;
+}
+
+// CHECK: define i32 @f2_a
+// CHECK: load i32* %{{.*}}, align 1
+// CHECK: }
+// CHECK: define i32 @f2_b
+// CHECK: load i32* %{{.*}}, align 4
+// CHECK: }
+// CHECK: define i32 @f2_c
+// CHECK: load i32* %{{.*}}, align 1
+// CHECK: }
+// CHECK: define i32 @f2_d
+// CHECK: load i32* %{{.*}}, align 1
+// CHECK: }
+int f2_a(struct s2 *a) {
+ return a->x[1];
+}
+int f2_b(struct s2 *a) {
+ return *(a->x + 1);
+}
+int f2_c(struct s2 *a) {
+ return a->y;
+}
+int f2_d(struct s2 *a) {
+ return a->z;
+}
+
+// CHECK: define i32 @f3_a
+// CHECK: load i32* %{{.*}}, align 1
+// CHECK: }
+// CHECK: define i32 @f3_b
+// CHECK: load i32* %{{.*}}, align 4
+// CHECK: }
+// CHECK: define i32 @f3_c
+// CHECK: load i32* %{{.*}}, align 1
+// CHECK: }
+// CHECK: define i32 @f3_d
+// CHECK: load i32* %{{.*}}, align 1
+// CHECK: }
+int f3_a(struct s3 *a) {
+ return a->x[1];
+}
+int f3_b(struct s3 *a) {
+ return *(a->x + 1);
+}
+int f3_c(struct s3 *a) {
+ return a->y;
+}
+int f3_d(struct s3 *a) {
+ return a->z;
+}
+
+// Verify we don't claim things are overaligned.
+//
+// CHECK: define double @f4
+// CHECK: load double* {{.*}}, align 8
+// CHECK: }
+extern double g4[5] __attribute__((aligned(16)));
+double f4() {
+ return g4[1];
+}
diff --git a/test/CodeGen/ptx-cc.c b/test/CodeGen/ptx-cc.c
new file mode 100644
index 000000000000..2212d4260b35
--- /dev/null
+++ b/test/CodeGen/ptx-cc.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple ptx32-unknown-unknown -O3 -S -o %t %s -emit-llvm
+// RUN: %clang_cc1 -triple ptx64-unknown-unknown -O3 -S -o %t %s -emit-llvm
+
+// Just make sure Clang uses the proper calling convention for the PTX back-end.
+// If something is wrong, the back-end will fail.
+void foo(float* a,
+ float* b) {
+ a[0] = b[0];
+}
diff --git a/test/CodeGen/regparm-flag.c b/test/CodeGen/regparm-flag.c
index f37239e473cd..8ecf53950805 100644
--- a/test/CodeGen/regparm-flag.c
+++ b/test/CodeGen/regparm-flag.c
@@ -4,12 +4,17 @@
void f1(int a, int b, int c, int d,
int e, int f, int g, int h);
+void f2(int a, int b) __attribute((regparm(0)));
+
void f0() {
// CHECK: call void @f1(i32 inreg 1, i32 inreg 2, i32 inreg 3, i32 inreg 4,
// CHECK: i32 5, i32 6, i32 7, i32 8)
f1(1, 2, 3, 4, 5, 6, 7, 8);
+// CHECK: call void @f2(i32 1, i32 2)
+ f2(1, 2);
}
// CHECK: declare void @f1(i32 inreg, i32 inreg, i32 inreg, i32 inreg,
// CHECK: i32, i32, i32, i32)
+// CHECK: declare void @f2(i32, i32)
diff --git a/test/CodeGen/switch-dce.c b/test/CodeGen/switch-dce.c
new file mode 100644
index 000000000000..bbb5f7e5aa36
--- /dev/null
+++ b/test/CodeGen/switch-dce.c
@@ -0,0 +1,247 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -O0 %s -emit-llvm -o - | FileCheck %s
+
+// PR9322 and rdar://6970405
+
+// CHECK: @test1
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32 {{.*}}, 1
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+int i;
+void dead();
+
+void test1() {
+ switch (1)
+ case 1:
+ ++i;
+
+ switch (0)
+ case 1:
+ dead();
+}
+
+
+// CHECK: @test2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32 {{.*}}, 2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test2() {
+ switch (4) {
+ case 1:
+ dead();
+ break;
+ case 4:
+ i += 2;
+ // Fall off the end of the switch.
+ }
+}
+
+
+// CHECK: @test3
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32 {{.*}}, 2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test3() {
+ switch (4) {
+ case 1:
+ dead();
+ break;
+ case 4: {
+ i += 2;
+ break;
+ }
+ }
+}
+
+// CHECK: @test4
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32 {{.*}}, 2
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test4() {
+ switch (4) {
+ case 1:
+ dead();
+ break;
+ default: {
+ i += 2;
+ break;
+ }
+ }
+}
+
+// This shouldn't crash codegen, but we don't have to optimize out the switch
+// in this case.
+void test5() {
+ switch (1) {
+ int x; // eliding var decl?
+ case 1:
+ x = 4;
+ i = x;
+ break;
+ }
+}
+
+// CHECK: @test6
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test6() {
+ // Neither case is reachable.
+ switch (40) {
+ case 1:
+ dead();
+ break;
+ case 4: {
+ dead();
+ break;
+ }
+ }
+}
+
+// CHECK: @test7
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test7() {
+ switch (4) {
+ case 1:
+ dead();
+ break;
+ {
+ case 4: // crazy brace scenario
+ ++i;
+ }
+ break;
+ }
+}
+
+// CHECK: @test8
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test8() {
+ switch (4) {
+ case 1:
+ dead();
+ break;
+ case 4:
+ ++i;
+ // Fall off the end of the switch.
+ }
+}
+
+// CHECK: @test9
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: add nsw i32
+// CHECK: add nsw i32
+// CHECK-NOT: switch
+// CHECK-NOT: @dead
+// CHECK: ret void
+void test9(int i) {
+ switch (1) {
+ case 5:
+ dead();
+ case 1:
+ ++i;
+ // Fall through is fine.
+ case 4:
+ ++i;
+ break;
+ }
+}
+
+// CHECK: @test10
+// CHECK-NOT: switch
+// CHECK: ret i32
+int test10(void) {
+ switch(8) {
+ case 8:
+ break;
+ case 4:
+ break;
+ default:
+ dead();
+ }
+
+ return 0;
+}
+
+// CHECK: @test11
+// CHECK-NOT: switch
+// CHECK: ret void
+void test11() {
+ switch (1) {
+ case 1:
+ break;
+ case 42: ;
+ int x; // eliding var decl?
+ x = 4;
+ break;
+ }
+}
+
+// CHECK: @test12
+// CHECK-NOT: switch
+// CHECK: ret void
+void test12() {
+ switch (1) {
+ case 2: {
+ int a; // Ok to skip this vardecl.
+ a = 42;
+ }
+ case 1:
+ break;
+ case 42: ;
+ int x; // eliding var decl?
+ x = 4;
+ break;
+ }
+}
+
+
+// rdar://9289524 - Check that the empty cases don't produce an empty block.
+// CHECK: @test13
+// CHECK: switch
+// CHECK: i32 42, label [[EPILOG:%[0-9.a-z]+]]
+// CHECK: i32 11, label [[EPILOG]]
+void test13(int x) {
+ switch (x) {
+ case 42: break; // No empty block please.
+ case 11: break; // No empty block please.
+ default: test13(42); break;
+ }
+}
+
+
+// Verify that case 42 only calls test14 once.
+// CHECK: @test14
+// CHECK: call void @test14(i32 97)
+// CHECK-NEXT: br label [[EPILOG2:%[0-9.a-z]+]]
+// CHECK: call void @test14(i32 42)
+// CHECK-NEXT: br label [[EPILOG2]]
+void test14(int x) {
+ switch (x) {
+ case 42: test14(97); // fallthrough
+ case 11: break;
+ default: test14(42); break;
+ }
+}
+
diff --git a/test/CodeGen/union.c b/test/CodeGen/union.c
index 1883ca639b7e..5c89e2d72a7e 100644
--- a/test/CodeGen/union.c
+++ b/test/CodeGen/union.c
@@ -42,3 +42,5 @@ int RRF(void) {return RRU.a;}
// PR6164
typedef union T0 { unsigned int : 0; } T0;
T0 t0;
+
+union { int large_bitfield: 31; char c } u2;
diff --git a/test/CodeGen/x86_64-arguments-darwin.c b/test/CodeGen/x86_64-arguments-darwin.c
new file mode 100644
index 000000000000..2f804e6efc03
--- /dev/null
+++ b/test/CodeGen/x86_64-arguments-darwin.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s| FileCheck %s
+
+// rdar://9122143
+// CHECK: declare void @func(i64, double)
+typedef struct _str {
+ union {
+ long double a;
+ long c;
+ };
+} str;
+
+void func(str s);
+str ss;
+void f9122143()
+{
+ func(ss);
+}
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 51a234d993ca..ebde884d78d6 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -1,8 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s| FileCheck %s
#include <stdarg.h>
-// CHECK: %0 = type { i64, double }
-
// CHECK: define signext i8 @f0()
char f0(void) {
return 0;
@@ -44,8 +42,8 @@ void f7(e7 a0) {
// Test merging/passing of upper eightbyte with X87 class.
//
-// CHECK: define %0 @f8_1()
-// CHECK: define void @f8_2(i64 %a0.coerce0, double %a0.coerce1)
+// CHECK: define void @f8_1(%struct.s19* sret %agg.result)
+// CHECK: define void @f8_2(%struct.s19* byval align 16 %a0)
union u8 {
long double a;
int b;
@@ -245,3 +243,19 @@ v1i64 f34(v1i64 arg) { return arg; }
typedef unsigned long v1i64_2 __attribute__((__vector_size__(8)));
v1i64_2 f35(v1i64_2 arg) { return arg+arg; }
+// rdar://9122143
+// CHECK: declare void @func(%struct._str* byval align 16)
+typedef struct _str {
+ union {
+ long double a;
+ long c;
+ };
+} str;
+
+void func(str s);
+str ss;
+void f9122143()
+{
+ func(ss);
+}
+
diff --git a/test/CodeGenCXX/PR5863-unreachable-block.cpp b/test/CodeGenCXX/PR5863-unreachable-block.cpp
index 4829b5277aad..3f32d7570435 100644
--- a/test/CodeGenCXX/PR5863-unreachable-block.cpp
+++ b/test/CodeGenCXX/PR5863-unreachable-block.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -emit-llvm-only %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm-only %s
// PR5863
class E { };
diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp
index 0198ed0e3e23..32e17a35ff2d 100644
--- a/test/CodeGenCXX/anonymous-namespaces.cpp
+++ b/test/CodeGenCXX/anonymous-namespaces.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -triple x86_64-apple-darwin10 -emit-llvm %s -o - > %t
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-llvm %s -o - > %t
// RUN: FileCheck %s -check-prefix=1 < %t
// RUN: FileCheck %s -check-prefix=2 < %t
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
index 85e931b50c91..2ddafecf6651 100644
--- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -106,14 +106,11 @@ struct S {
} s;
- //PR8760
- template <typename T>
- struct Foo {
- Foo() : ptr(__nullptr) {}
- union {
- T *ptr;
- };
- };
- Foo<int> f;
-
-
+//PR8760
+template <typename T> struct Foo {
+ Foo() : ptr(__nullptr) {}
+ union {
+ T *ptr;
+ };
+};
+Foo<int> f;
diff --git a/test/CodeGenCXX/apple-kext-guard-variable.cpp b/test/CodeGenCXX/apple-kext-guard-variable.cpp
new file mode 100644
index 000000000000..26b0d14b34d6
--- /dev/null
+++ b/test/CodeGenCXX/apple-kext-guard-variable.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -o %t.s -mkernel -Xclang -verify %s
+
+// rdar://problem/9143356
+
+int foo();
+void test() {
+ static int y = 0;
+ static int x = foo(); // expected-error {{this initialization requires a guard variable, which the kernel does not support}}
+}
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index 672ca0100788..8d74d003c3d6 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -117,7 +117,8 @@ namespace test3 {
// CHECK: [[N:%.*]] = load i32*
// CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
// CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
- // CHECK: [[SZ:%.*]] = select
+ // CHECK: [[OR:%.*]] = or i1
+ // CHECK: [[SZ:%.*]] = select i1 [[OR]]
// CHECK: call noalias i8* @_Znam(i32 [[SZ]])
// CHECK: store i32 4
// CHECK: store i32 [[N]]
diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index ea174b57e44d..a4d5b86565e2 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -55,3 +55,52 @@ namespace test1 {
// ...or non-trivial copy constructors, but it's not clear how to do
// that and still have a constant initializer in '03.
}
+
+namespace test2 {
+ struct A {
+ A();
+ A(const A &);
+ ~A();
+ };
+
+ struct B {
+ B();
+ B(const B &);
+ ~B();
+ };
+
+ // CHECK: define void @_ZN5test24testEv()
+ void test() {
+ __block A a;
+ __block B b;
+ }
+
+ // CHECK: define internal void @__Block_byref_object_copy
+ // CHECK: call void @_ZN5test21AC1ERKS0_(
+
+ // CHECK: define internal void @__Block_byref_object_dispose
+ // CHECK: call void @_ZN5test21AD1Ev(
+
+ // CHECK: define internal void @__Block_byref_object_copy
+ // CHECK: call void @_ZN5test21BC1ERKS0_(
+
+ // CHECK: define internal void @__Block_byref_object_dispose
+ // CHECK: call void @_ZN5test21BD1Ev(
+}
+
+// rdar://problem/9334739
+// Make sure we mark destructors for parameters captured in blocks.
+namespace test3 {
+ struct A {
+ A(const A&);
+ ~A();
+ };
+
+ struct B : A {
+ };
+
+ void test(B b) {
+ extern void consume(void(^)());
+ consume(^{ (void) b; });
+ }
+}
diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp
index 6675b4963bd2..96fbae8970e0 100644
--- a/test/CodeGenCXX/class-layout.cpp
+++ b/test/CodeGenCXX/class-layout.cpp
@@ -17,3 +17,31 @@ namespace Test3 {
// CHECK: %"struct.Test3::A" = type { i32 (...)**, i32 }
struct A { virtual void f(); int a; } *a;
}
+
+namespace Test4 {
+ // Test from PR5589.
+ // CHECK: %"struct.Test4::A" = type { i32, i8, float }
+ // CHECK: %"struct.Test4::B" = type { %"struct.Test4::A", i16, double }
+ struct A {
+ int a;
+ char c;
+ float b;
+ };
+ struct B : public A {
+ short d;
+ double e;
+ } *b;
+}
+
+namespace Test5 {
+ struct A {
+ virtual void f();
+ char a;
+ };
+
+ // CHECK: %"struct.Test5::B" = type { [9 x i8], i8, i8, [5 x i8] }
+ struct B : A {
+ char b : 1;
+ char c;
+ } *b;
+}
diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
new file mode 100644
index 000000000000..5b432c769016
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -emit-llvm -fexceptions -fcxx-exceptions -std=c++0x -o - %s | FileCheck %s
+
+struct non_trivial {
+ non_trivial();
+ ~non_trivial();
+};
+non_trivial::non_trivial() {}
+non_trivial::~non_trivial() {}
+
+// We use a virtual base to ensure that the constructor
+// delegation optimization (complete->base) can't be
+// performed.
+struct delegator {
+ non_trivial n;
+ delegator();
+ delegator(int);
+ delegator(char);
+ delegator(bool);
+};
+
+delegator::delegator() {
+ throw 0;
+}
+
+// CHECK: define void @_ZN9delegatorC1Ei
+// CHECK: call void @_ZN9delegatorC1Ev
+// CHECK-NOT: lpad
+// CHECK: ret
+// CHECK-NOT: lpad
+// CHECK: define void @_ZN9delegatorC2Ei
+// CHECK: call void @_ZN9delegatorC2Ev
+// CHECK-NOT: lpad
+// CHECK: ret
+// CHECK-NOT: lpad
+delegator::delegator(int)
+ : delegator()
+{}
+
+delegator::delegator(bool)
+{}
+
+// CHECK: define void @_ZN9delegatorC2Ec
+// CHECK: call void @_ZN9delegatorC2Eb
+// CHECK: call void @__cxa_throw
+delegator::delegator(char)
+ : delegator(true) {
+ throw 0;
+}
diff --git a/test/CodeGenCXX/debug-info-byval.cpp b/test/CodeGenCXX/debug-info-byval.cpp
index c99518e7a6b8..f0cb6d68c837 100644
--- a/test/CodeGenCXX/debug-info-byval.cpp
+++ b/test/CodeGenCXX/debug-info-byval.cpp
@@ -1,5 +1,5 @@
// RUN: %clang -g -S %s -o - | FileCheck %s
-// Test to check presense of debug info for byval parameter.
+// Test to check presence of debug info for byval parameter.
// Radar 8350436.
class DAG {
public:
diff --git a/test/CodeGenCXX/debug-info-cxx0x.cpp b/test/CodeGenCXX/debug-info-cxx0x.cpp
new file mode 100644
index 000000000000..5753b05d728e
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-cxx0x.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm-only -std=c++0x -g %s
+
+namespace PR9414 {
+ int f() {
+ auto x = 0;
+ return x;
+ }
+}
diff --git a/test/CodeGenCXX/debug-info-fn-template.cpp b/test/CodeGenCXX/debug-info-fn-template.cpp
new file mode 100644
index 000000000000..c8291af852d3
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-fn-template.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
+
+template<typename T>
+struct XF {
+ T member;
+};
+
+template<typename T>
+T fx(XF<T> xi) {
+ return xi.member;
+}
+
+//CHECK: DW_TAG_template_type_parameter
+//CHECK: XF<int>
+template int fx(XF<int>);
diff --git a/test/CodeGenCXX/debug-info-method-spec.cpp b/test/CodeGenCXX/debug-info-method-spec.cpp
new file mode 100644
index 000000000000..31f66633dc4c
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-method-spec.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang -fverbose-asm -cc1 -g -S %s -o - | grep DW_AT_specification
+// Radar 9254491
+class A {
+public:
+ void doSomething(int i) { ++i; }
+};
+
+void foo(A *a) {
+ a->doSomething(2);
+}
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index 2e0a96d56660..27f5eae9780f 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -g -S %s -o - | FileCheck %s
+// RUN: %clang -g -S -fverbose-asm %s -o - | FileCheck %s
// CHECK: TAG_namespace
namespace A {
diff --git a/test/CodeGenCXX/debug-info-template.cpp b/test/CodeGenCXX/debug-info-template.cpp
index 0ddfc242b10e..9d52159bed84 100644
--- a/test/CodeGenCXX/debug-info-template.cpp
+++ b/test/CodeGenCXX/debug-info-template.cpp
@@ -20,3 +20,27 @@ class TU {
};
TU<2> u2;
+
+// PR9600
+template<typename T> class vector {};
+class Foo;
+typedef vector<Foo*> FooVector[3];
+struct Test {
+ virtual void foo(FooVector *);
+};
+static Test test;
+
+// PR9608
+template <int i> struct TheTemplate {
+ struct Empty2 {};
+ typedef const Empty2 DependentType[i];
+ TheTemplate() {}
+};
+
+class TheTemplateTest : public TheTemplate<42> {
+ TheTemplateTest();
+ void method(const TheTemplate<42>::DependentType *) {}
+};
+
+TheTemplateTest::TheTemplateTest() : TheTemplate<42>() {}
+
diff --git a/test/CodeGenCXX/debug-info-this.cpp b/test/CodeGenCXX/debug-info-this.cpp
new file mode 100644
index 000000000000..a2842d021783
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-this.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
+// Radar 9239104
+class Class
+{
+public:
+//CHECK: DW_TAG_const_type
+ int foo (int p) const {
+ return p+m_int;
+ }
+
+protected:
+ int m_int;
+};
+
+Class c;
diff --git a/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
index e332f4020001..0e153022439b 100644
--- a/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
+++ b/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
struct A { int i; };
-struct B { int j; };
+struct B { char j; };
struct C : A, B { int k; };
struct D final : virtual C {
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index f382413cba41..353b61061ad1 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | FileCheck %s
// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
index 74795b5dfb0e..5eede66cd7b4 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp
@@ -2,7 +2,8 @@
struct A {
virtual void f();
-
+ virtual void f_const() const;
+
A h();
};
@@ -28,6 +29,12 @@ void f(A a, A *ap, A& ar) {
// CHECK: call void @_ZN1A1fEv
a.h().f();
+
+ // CHECK: call void @_ZNK1A7f_constEv
+ a.f_const();
+
+ // CHECK: call void @_ZN1A1fEv
+ (a).f();
}
struct B {
@@ -45,3 +52,4 @@ void f() {
// CHECK: call void @_ZN1B1fEv
B().h().f();
}
+
diff --git a/test/CodeGenCXX/dynamic-cast-always-null.cpp b/test/CodeGenCXX/dynamic-cast-always-null.cpp
new file mode 100644
index 000000000000..e4e86942181d
--- /dev/null
+++ b/test/CodeGenCXX/dynamic-cast-always-null.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -std=c++0x -o - | FileCheck %s
+struct A { virtual ~A(); };
+struct B final : A { };
+struct C { virtual ~C(); int c; };
+
+// CHECK: @_Z1fP1B
+C *f(B* b) {
+ // CHECK-NOT: call i8* @__dynamic_cast
+ // CHECK: ret %struct.C* null
+ return dynamic_cast<C*>(b);
+}
+
+// CHECK: @_Z1fR1B
+C &f(B& b) {
+ // CHECK-NOT: call i8* @__dynamic_cast
+ // CHECK: call void @__cxa_bad_cast() noreturn
+ // CHECK: ret %struct.C* undef
+ return dynamic_cast<C&>(b);
+}
diff --git a/test/CodeGenCXX/dynamic-cast.cpp b/test/CodeGenCXX/dynamic-cast.cpp
index 9838e25b1d3f..e84bb9b4ff50 100644
--- a/test/CodeGenCXX/dynamic-cast.cpp
+++ b/test/CodeGenCXX/dynamic-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s
struct A { virtual void f(); };
struct B : A { };
diff --git a/test/CodeGenCXX/dyncast.cpp b/test/CodeGenCXX/dyncast.cpp
deleted file mode 100644
index 7fd5899225c2..000000000000
--- a/test/CodeGenCXX/dyncast.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-// RUN: %clang_cc1 -I%S -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
-// RUN: FileCheck -check-prefix LL --input-file=%t.ll %s
-
-#include <typeinfo>
-
-class test1_A { virtual void f() { } };
-class test1_B { virtual void g() { } };
-class test1_D : public virtual test1_A, private test1_B {};
-class test1_E : public test1_D, public test1_B {};
-class test1_F : public test1_E, public test1_D {};
-
-extern test1_D test1_d;
-extern test1_F test1_f;
-
-extern "C" int printf(const char *str...);
-
-#define S(V, N) if (V) printf("PASS: %d\n", N); else printf("FAIL: %d\n", N)
-
-void test1() {
- test1_B* bp = (test1_B*)&test1_d;
- test1_A* ap = &test1_d;
- test1_D* dp = dynamic_cast<test1_D*>(bp);
- S(dp == 0, 1);
- ap = dynamic_cast<test1_A*>(bp);
- S(ap == 0, 2);
- bp = dynamic_cast<test1_B*>(ap);
- S(bp == 0, 3);
- ap = dynamic_cast<test1_A*>(&test1_d);
- S(ap != 0, 4);
- // FIXME: Doesn't work yet, gcc fails this at compile time. We'd need access
- // control for this to work.
- // bp = dynamic_cast<test1_B*>(&test1_d);
- // S(bp == 0, 5);
- {
- test1_A* ap = &test1_f;
- S(ap != 0, 6);
- test1_D* dp = dynamic_cast<test1_D*>(ap);
- S(dp == 0, 7);
- // cast from virtual base
- test1_E* ep1 = dynamic_cast<test1_E*>(ap);
- S(ep1 != 0, 8);
- }
- dp = dynamic_cast<test1_D*>(&test1_d);
- S(dp == &test1_d, 9);
- const test1_D *cdp = dynamic_cast<const test1_D*>(&test1_d);
- S(cdp == &test1_d, 10);
- dp = dynamic_cast<test1_D*>((test1_A*)0);
- S(dp == 0, 11);
- ap = dynamic_cast<test1_A*>(&test1_d);
- S(ap == (test1_A*)&test1_d, 12);
- test1_E* ep = dynamic_cast<test1_E*>(&test1_f);
- S(ep == (test1_E*)&test1_f, 13);
- void *vp = dynamic_cast<void*>(ap);
- S(vp == &test1_d, 14);
- const void *cvp = dynamic_cast<const void*>(ap);
- S(cvp == &test1_d, 15);
-}
-
-// CHECK-LL: define void @_Z5test1v() nounwind {
-// CHECK-LL: [[bp:%.*]] = alloca %class.test1_A*, align 8
-// CHECK-LL-NEXT: [[ap:%.*]] = alloca %class.test1_A*, align 8
-// CHECK-LL-NEXT: [[dp:%.*]] = alloca %class.test1_D*, align 8
-// CHECK-LL-NEXT: [[ap37:%.*]] = alloca %class.test1_A*, align 8
-// CHECK-LL-NEXT: [[dp53:%.*]] = alloca %class.test1_D*, align 8
-// CHECK-LL-NEXT: [[ep1:%.*]] = alloca %class.test1_E*, align 8
-// CHECK-LL-NEXT: [[cdp:%.*]] = alloca %class.test1_D*, align 8
-// CHECK-LL-NEXT: [[ep:%.*]] = alloca %class.test1_E*, align 8
-// CHECK-LL-NEXT: [[vp:%.*]] = alloca i8*, align 8
-// CHECK-LL-NEXT: [[cvp:%.*]] = alloca i8*, align 8
-// CHECK-LL-NEXT: store %class.test1_A* bitcast (%class.test1_D* @test1_d to %class.test1_A*), %class.test1_A** [[bp]]
-// CHECK-LL-NEXT: br i1 false, label %[[castnull2:.*]], label %[[castnotnull1:.*]]
-// CHECK-LL: [[castnotnull1]]
-// CHECK-LL-NEXT: [[vtable:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: [[vbaseoffsetptr:%.*]] = getelementptr i8* [[vtable]], i64 -24
-// CHECK-LL-NEXT: [[v1:%.*]] = bitcast i8* [[vbaseoffsetptr]] to i64*
-// CHECK-LL-NEXT: [[vbaseoffset:%.*]] = load i64* [[v1]]
-// CHECK-LL-NEXT: [[addptr:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset:.*]]
-// CHECK-LL-NEXT: [[v2:%.*]] = bitcast i8* [[addptr]] to %class.test1_A*
-// CHECK-LL-NEXT: br label %[[castend3:.*]]
-// CHECK-LL: [[castnull2]]
-// CHECK-LL-NEXT: br label %[[castend3]]
-// CHECK-LL: [[castend3]]
-// CHECK-LL-NEXT: [[v3:%.*]] = phi %class.test1_A* [ [[v2]], %[[castnotnull1]] ], [ null, %[[castnull2]] ]
-// CHECK-LL-NEXT: store %class.test1_A* [[v3]], %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[tmp:%.*]] = load %class.test1_A** [[bp]]
-// CHECK-LL-NEXT: [[v4:%.*]] = icmp ne %class.test1_A* [[tmp]], null
-// CHECK-LL-NEXT: br i1 [[v4]], label %[[v5:.*]], label %[[v9:.*]]
-// CHECK-LL: [[v6:%.*]] = bitcast %class.test1_A* [[tmp]] to i8*
-// CHECK-LL-NEXT: [[v7:%.*]] = call i8* @__dynamic_cast(i8* [[v6]], i8* bitcast (%0* @_ZTI7test1_B to i8*), i8* bitcast (%1* @_ZTI7test1_D to i8*), i64 -1)
-// CHECK-LL-NEXT: [[v8:%.*]] = bitcast i8* [[v7]] to %class.test1_D*
-// CHECK-LL-NEXT: br label %[[v10:.*]]
-// CHECK-LL: br label %[[v10]]
-// CHECK-LL: [[v11:%.*]] = phi %class.test1_D* [ [[v8]], %[[v5]] ], [ null, %[[v9]] ]
-// CHECK-LL-NEXT: store %class.test1_D* [[v11]], %class.test1_D** [[dp]]
-// CHECK-LL-NEXT: [[tmp4:%.*]] = load %class.test1_D** [[dp]]
-// CHECK-LL-NEXT: [[cmp:%.*]] = icmp eq %class.test1_D* [[tmp4]], null
-// CHECK-LL-NEXT: br i1 [[cmp]], label %[[ifthen:.*]], label %[[ifelse:.*]]
-// CHECK-LL: [[ifthen]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 1)
-// CHECK-LL-NEXT: br label %[[ifend:.*]]
-// CHECK-LL: [[ifelse]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 1)
-// CHECK-LL-NEXT: br label %[[ifend]]
-// CHECK-LL: [[ifend]]
-// CHECK-LL-NEXT: [[tmp6:%.*]] = load %class.test1_A** [[bp]]
-// CHECK-LL-NEXT: [[v12:%.*]] = icmp ne %class.test1_A* [[tmp6]], null
-// CHECK-LL-NEXT: br i1 [[v12]], label %[[v13:.*]], label %[[v17:.*]]
-// CHECK-LL: [[v14:%.*]] = bitcast %class.test1_A* [[tmp6]] to i8*
-// CHECK-LL-NEXT: [[v15:%.*]] = call i8* @__dynamic_cast(i8* [[v14]], i8* bitcast ({{.*}} @_ZTI7test1_B to i8*), i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i64 -1)
-// CHECK-LL-NEXT: [[v16:%.*]] = bitcast i8* [[v15]] to %class.test1_A*
-// CHECK-LL-NEXT: br label %[[v18:.*]]
-// CHECK-LL: br label %[[v18]]
-// CHECK-LL: [[v19:%.*]] = phi %class.test1_A* [ [[v16]], %[[v13]] ], [ null, %[[v17]] ]
-// CHECK-LL-NEXT: store %class.test1_A* [[v19]], %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[tmp7:%.*]] = load %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[cmp8:%.*]] = icmp eq %class.test1_A* [[tmp7]], null
-// CHECK-LL-NEXT: br i1 [[cmp8]], label %[[ifthen9:.*]], label %[[ifelse11:.*]]
-// CHECK-LL: [[ifthen9]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 2)
-// CHECK-LL-NEXT: br label %[[ifend13:.*]]
-// CHECK-LL: [[ifelse11]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 2)
-// CHECK-LL-NEXT: br label %[[ifend13]]
-// CHECK-LL: [[ifend13]]
-// CHECK-LL-NEXT: [[tmp14:%.*]] = load %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[v20:%.*]] = icmp ne %class.test1_A* [[tmp14]], null
-// CHECK-LL-NEXT: br i1 [[v20]], label %[[v21:.*]], label %[[v25:.*]]
-// CHECK-LL: [[v22:%.*]] = bitcast %class.test1_A* [[tmp14]] to i8*
-// CHECK-LL-NEXT: [[v23:%.*]] = call i8* @__dynamic_cast({{.*}} [[v22]], i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_B to i8*), i64 -1)
-// CHECK-LL-NEXT: [[v24:%.*]] = bitcast i8* [[v23]] to %class.test1_A*
-// CHECK-LL-NEXT: br label %[[v26:.*]]
-// CHECK-LL: br label %[[v26]]
-// CHECK-LL: [[v27:%.*]] = phi %class.test1_A* [ [[v24]], %[[v21]] ], [ null, %[[v25]] ]
-// CHECK-LL-NEXT: store %class.test1_A* [[v27]], %class.test1_A** [[bp]]
-// CHECK-LL-NEXT: [[tmp15:%.*]] = load %class.test1_A** [[bp]]
-// CHECK-LL-NEXT: [[cmp16:%.*]] = icmp eq %class.test1_A* [[tmp15]], null
-// CHECK-LL-NEXT: br i1 [[cmp16]], label %[[ifthen17:.*]], label %[[ifelse19:.*]]
-// CHECK-LL: [[ifthen17]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 3)
-// CHECK-LL-NEXT: br label %[[ifend21:.*]]
-// CHECK-LL: [[ifelse19]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 3)
-// CHECK-LL-NEXT: br label %[[ifend21]]
-// CHECK-LL: [[ifend21]]
-// CHECK-LL-NEXT: br i1 false, label %[[castnull27:.*]], label %[[castnotnull22:.*]]
-// CHECK-LL: [[castnotnull22]]
-// CHECK-LL-NEXT: [[vtable23:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: [[vbaseoffsetptr24:%.*]] = getelementptr i8* [[vtable23]], i64 -24
-// CHECK-LL-NEXT: [[v28:%.*]] = bitcast i8* [[vbaseoffsetptr24]] to i64*
-// CHECK-LL-NEXT: [[vbaseoffset25:%.*]] = load i64* [[v28]]
-// CHECK-LL-NEXT: [[addptr26:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset25]]
-// CHECK-LL-NEXT: [[v29:%.*]] = bitcast i8* [[addptr26]] to %class.test1_A*
-// CHECK-LL-NEXT: br label %[[castend28:.*]]
-// CHECK-LL: [[castnull27]]
-// CHECK-LL-NEXT: br label %[[castend28]]
-// CHECK-LL: [[castend28]]
-// CHECK-LL-NEXT: [[v30:%.*]] = phi %class.test1_A* [ [[v29]], %[[castnotnull22]] ], [ null, %[[castnull27]] ]
-// CHECK-LL-NEXT: store %class.test1_A* [[v30]], %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[tmp29:%.*]] = load %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[cmp30:%.*]] = icmp ne %class.test1_A* [[tmp29]], null
-// CHECK-LL-NEXT: br i1 [[cmp30]], label %[[ifthen31:.*]], label %[[ifelse33:.*]]
-// CHECK-LL: [[ifthen31]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 4)
-// CHECK-LL-NEXT: br label %[[ifend35:.*]]
-// CHECK-LL: [[ifelse33]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 4)
-// CHECK-LL-NEXT: br label %[[ifend35]]
-// CHECK-LL: [[ifend35]]
-// CHECK-LL-NEXT: br i1 false, label %[[castnull43:.*]], label %[[castnotnull38:.*]]
-// CHECK-LL: [[castnotnull38]]
-// CHECK-LL-NEXT: [[vtable39:%.*]] = load i8** bitcast (%class.test1_F* @test1_f to i8**)
-// CHECK-LL-NEXT: [[vbaseoffsetptr40:%.*]] = getelementptr i8* [[vtable39]], i64 -24
-// CHECK-LL-NEXT: [[v31:%.*]] = bitcast i8* [[vbaseoffsetptr40]] to i64*
-// CHECK-LL-NEXT: [[vbaseoffset41:%.*]] = load i64* [[v31]]
-// CHECK-LL-NEXT: [[addptr42:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_F* @test1_f, i32 0, i32 0, i32 0), i64 [[vbaseoffset41]]
-// CHECK-LL-NEXT: [[v32:%.*]] = bitcast i8* [[addptr42]] to %class.test1_A*
-// CHECK-LL-NEXT: br label %[[castend44:.*]]
-// CHECK-LL: [[castnull43]]
-// CHECK-LL-NEXT: br label %[[castend44]]
-// CHECK-LL: [[castend44]]
-// CHECK-LL-NEXT: [[v33:%.*]] = phi %class.test1_A* [ [[v32]], %[[castnotnull38]] ], [ null, %[[castnull43]] ]
-// CHECK-LL-NEXT: store %class.test1_A* [[v33]], %class.test1_A** [[ap37]]
-// CHECK-LL-NEXT: [[tmp45:%.*]] = load %class.test1_A** [[ap37]]
-// CHECK-LL-NEXT: [[cmp46:%.*]] = icmp ne %class.test1_A* [[tmp45]], null
-// CHECK-LL-NEXT: br i1 [[cmp46]], label %[[ifthen47:.*]], label %[[ifelse49:.*]]
-// CHECK-LL: [[ifthen47]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 6)
-// CHECK-LL-NEXT: br label %[[ifend51:.*]]
-// CHECK-LL: [[ifelse49]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 6)
-// CHECK-LL-NEXT: br label %[[ifend51]]
-// CHECK-LL: [[ifend51]]
-// CHECK-LL-NEXT: [[tmp54:%.*]] = load %class.test1_A** [[ap37]]
-// CHECK-LL-NEXT: [[v34:%.*]] = icmp ne %class.test1_A* [[tmp54]], null
-// CHECK-LL-NEXT: br i1 [[v34]], label %[[v35:.*]], label %[[v39:.*]]
-// CHECK-LL: [[v36:%.*]] = bitcast %class.test1_A* [[tmp54]] to i8*
-// CHECK-LL-NEXT: [[v37:%.*]] = call i8* @__dynamic_cast(i8* [[v36]], i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_D to i8*), i64 -1)
-// CHECK-LL-NEXT: [[v38:%.*]] = bitcast i8* [[v37]] to %class.test1_D*
-// CHECK-LL-NEXT: br label %[[v40:.*]]
-// CHECK-LL: br label %[[v40]]
-// CHECK-LL: [[v41:%.*]] = phi %class.test1_D* [ [[v38]], %[[v35]] ], [ null, %[[v39]] ]
-// CHECK-LL-NEXT: store %class.test1_D* [[v41]], %class.test1_D** [[dp53]]
-// CHECK-LL-NEXT: [[tmp55:%.*]] = load %class.test1_D** [[dp53]]
-// CHECK-LL-NEXT: [[cmp56:%.*]] = icmp eq %class.test1_D* [[tmp55]], null
-// CHECK-LL-NEXT: br i1 [[cmp56]], label %[[ifthen57:.*]], label %[[ifelse59:.*]]
-// CHECK-LL: [[ifthen57]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 7)
-// CHECK-LL-NEXT: br label %[[ifend61:.*]]
-// CHECK-LL: [[ifelse59]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 7)
-// CHECK-LL-NEXT: br label %[[ifend61]]
-// CHECK-LL: [[ifend61]]
-// CHECK-LL-NEXT: [[tmp63:%.*]] = load %class.test1_A** [[ap37]]
-// CHECK-LL-NEXT: [[v42:%.*]] = icmp ne %class.test1_A* [[tmp63]], null
-// CHECK-LL-NEXT: br i1 [[v42]], label %[[v43:.*]], label %[[v47:.*]]
-// CHECK-LL: [[v44:%.*]] = bitcast %class.test1_A* [[tmp63]] to i8*
-// CHECK-LL-NEXT: [[v45:%.*]] = call i8* @__dynamic_cast(i8* [[v44]], i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_E to i8*), i64 -1)
-// CHECK-LL-NEXT: [[v46:%.*]] = bitcast i8* [[v45]] to %class.test1_E*
-// CHECK-LL-NEXT: br label %[[v48:.*]]
-// CHECK-LL: br label %[[v48]]
-// CHECK-LL: [[v49:%.*]] = phi %class.test1_E* [ [[v46]], %[[v43]] ], [ null, %[[v47]] ]
-// CHECK-LL-NEXT: store %class.test1_E* [[v49]], %class.test1_E** [[ep1]]
-// CHECK-LL-NEXT: [[tmp64:%.*]] = load %class.test1_E** [[ep1]]
-// CHECK-LL-NEXT: [[cmp65:%.*]] = icmp ne %class.test1_E* [[tmp64]], null
-// CHECK-LL-NEXT: br i1 [[cmp65]], label %[[ifthen66:.*]], label %[[ifelse68:.*]]
-// CHECK-LL: [[ifthen66]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 8)
-// CHECK-LL-NEXT: br label %[[ifend70:.*]]
-// CHECK-LL: [[ifelse68]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 8)
-// CHECK-LL-NEXT: br label %[[ifend70]]
-// CHECK-LL: [[ifend70]]
-// CHECK-LL-NEXT: store %class.test1_D* @test1_d, %class.test1_D** [[dp]]
-// CHECK-LL-NEXT: [[tmp71:%.*]] = load %class.test1_D** [[dp]]
-// CHECK-LL-NEXT: [[cmp72:%.*]] = icmp eq %class.test1_D* [[tmp71]], @test1_d
-// CHECK-LL-NEXT: br i1 [[cmp72]], label %[[ifthen73:.*]], label %[[ifelse75:.*]]
-// CHECK-LL: [[ifthen73]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 9)
-// CHECK-LL-NEXT: br label %[[ifend77:.*]]
-// CHECK-LL: [[ifelse75]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 9)
-// CHECK-LL-NEXT: br label %[[ifend77]]
-// CHECK-LL: [[ifend77]]
-// CHECK-LL-NEXT: store %class.test1_D* @test1_d, %class.test1_D** [[cdp]]
-// CHECK-LL-NEXT: [[tmp79:%.*]] = load %class.test1_D** [[cdp]]
-// CHECK-LL-NEXT: [[cmp80:%.*]] = icmp eq %class.test1_D* [[tmp79]], @test1_d
-// CHECK-LL-NEXT: br i1 [[cmp80]], label %[[ifthen81:.*]], label %[[ifelse83:.*]]
-// CHECK-LL: [[ifthen81]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 10)
-// CHECK-LL-NEXT: br label %[[ifend85:.*]]
-// CHECK-LL: [[ifelse83]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 10)
-// CHECK-LL-NEXT: br label %[[ifend85]]
-// CHECK-LL: [[ifend85]]
-// CHECK-LL-NEXT: br i1 false, label %[[v50:.*]], label %[[v53:.*]]
-// CHECK-LL: [[v51:%.*]] = call i8* @__dynamic_cast(i8* null, i8* bitcast ({{.*}}* @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_D to i8*), i64 -1)
-// CHECK-LL-NEXT: [[v52:%.*]] = bitcast i8* [[v51]] to %class.test1_D*
-// CHECK-LL-NEXT: br label %[[v54:.*]]
-// CHECK-LL: br label %[[v54]]
-// CHECK-LL: [[v55:%.*]] = phi %class.test1_D* [ [[v52]], %[[v50]] ], [ null, %[[v53]] ]
-// CHECK-LL-NEXT: store %class.test1_D* [[v55]], %class.test1_D** [[dp]]
-// CHECK-LL-NEXT: [[tmp86:%.*]] = load %class.test1_D** [[dp]]
-// CHECK-LL-NEXT: [[cmp87:%.*]] = icmp eq %class.test1_D* [[tmp86]], null
-// CHECK-LL-NEXT: br i1 [[cmp87]], label %[[ifthen88:.*]], label %[[ifelse90:.*]]
-// CHECK-LL: [[ifthen88]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 11)
-// CHECK-LL-NEXT: br label %[[ifend92:.*]]
-// CHECK-LL: [[ifelse90]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 11)
-// CHECK-LL-NEXT: br label %[[ifend92]]
-// CHECK-LL: [[ifend92]]
-// CHECK-LL-NEXT: br i1 false, label %[[castnull98:.*]], label %[[castnotnull93:.*]]
-// CHECK-LL: [[castnotnull93]]
-// CHECK-LL-NEXT: [[vtable94:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: [[vbaseoffsetptr95:%.*]] = getelementptr i8* [[vtable94]], i64 -24
-// CHECK-LL-NEXT: [[v56:%.*]] = bitcast i8* [[vbaseoffsetptr95]] to i64*
-// CHECK-LL-NEXT: [[vbaseoffset96:%.*]] = load i64* [[v56]]
-// CHECK-LL-NEXT: [[addptr97:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset96]]
-// CHECK-LL-NEXT: [[v57:%.*]] = bitcast i8* [[addptr97]] to %class.test1_A*
-// CHECK-LL-NEXT: br label %[[castend99:.*]]
-// CHECK-LL: [[castnull98]]
-// CHECK-LL-NEXT: br label %[[castend99]]
-// CHECK-LL: [[castend99]]
-// CHECK-LL-NEXT: [[v58:%.*]] = phi %class.test1_A* [ [[v57]], %[[castnotnull93]] ], [ null, %[[castnull98]] ]
-// CHECK-LL-NEXT: store %class.test1_A* [[v58]], %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[tmp100:%.*]] = load %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: br i1 false, label %[[castnull106:.*]], label %[[castnotnull101:.*]]
-// CHECK-LL: [[castnotnull101]]
-// CHECK-LL-NEXT: [[vtable102:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: [[vbaseoffsetptr103:%.*]] = getelementptr i8* [[vtable102]], i64 -24
-// CHECK-LL-NEXT: [[v59:%.*]] = bitcast i8* [[vbaseoffsetptr103]] to i64*
-// CHECK-LL-NEXT: [[vbaseoffset104:%.*]] = load i64* [[v59]]
-// CHECK-LL-NEXT: [[addptr105:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset104]]
-// CHECK-LL-NEXT: [[v60:%.*]] = bitcast i8* [[addptr105]] to %class.test1_A*
-// CHECK-LL-NEXT: br label %[[castend107:.*]]
-// CHECK-LL: [[castnull106]]
-// CHECK-LL-NEXT: br label %[[castend107]]
-// CHECK-LL: [[castend107]]
-// CHECK-LL-NEXT: [[v61:%.*]] = phi %class.test1_A* [ [[v60]], %[[castnotnull101]] ], [ null, %[[castnull106]] ]
-// CHECK-LL-NEXT: [[cmp108:%.*]] = icmp eq %class.test1_A* [[tmp100]], [[v61]]
-// CHECK-LL-NEXT: br i1 [[cmp108]], label %[[ifthen109:.*]], label %[[ifelse111:.*]]
-// CHECK-LL: [[ifthen109]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 12)
-// CHECK-LL-NEXT: br label %[[ifend113:.*]]
-// CHECK-LL: [[ifelse111]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 12)
-// CHECK-LL-NEXT: br label %[[ifend113]]
-// CHECK-LL: [[ifend113]]
-// CHECK-LL-NEXT: store %class.test1_E* bitcast (%class.test1_F* @test1_f to %class.test1_E*), %class.test1_E** [[ep]]
-// CHECK-LL-NEXT: [[tmp118:%.*]] = load %class.test1_E** [[ep]]
-// CHECK-LL-NEXT: [[cmp122:%.*]] = icmp eq %class.test1_E* [[tmp118]], bitcast (%class.test1_F* @test1_f to %class.test1_E*)
-
-// CHECK-LL-NEXT: br i1 [[cmp122]], label %[[ifthen123:.*]], label %[[ifelse125:.*]]
-// CHECK-LL: [[ifthen123]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 13)
-// CHECK-LL-NEXT: br label %[[ifend127:.*]]
-// CHECK-LL: [[ifelse125]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 13)
-// CHECK-LL-NEXT: br label %[[ifend127]]
-// CHECK-LL: [[ifend127]]
-// CHECK-LL-NEXT: [[tmp129:%.*]] = load %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[v64:%.*]] = icmp ne %class.test1_A* [[tmp129]], null
-// CHECK-LL-NEXT: br i1 [[v64]], label %[[v65:.*]], label %[[v70:.*]]
-// CHECK-LL: [[v66:%.*]] = bitcast %class.test1_A* [[tmp129]] to i64**
-// CHECK-LL-NEXT: [[vtable130:%.*]] = load i64** [[v66]]
-// CHECK-LL-NEXT: [[v67:%.*]] = getelementptr inbounds i64* [[vtable130]], i64 -2
-// CHECK-LL-NEXT: [[offsettotop:%.*]] = load i64* [[v67]]
-// CHECK-LL-NEXT: [[v68:%.*]] = bitcast %class.test1_A* [[tmp129]] to i8*
-// CHECK-LL-NEXT: [[v69:%.*]] = getelementptr inbounds i8* [[v68]], i64 [[offsettotop]]
-// CHECK-LL-NEXT: br label %[[v71:.*]]
-// CHECK-LL: br label %[[v71]]
-// CHECK-LL: [[v72:%.*]] = phi i8* [ [[v69]], %[[v65]] ], [ null, %[[v70]] ]
-// CHECK-LL-NEXT: store i8* [[v72]], i8** [[vp]]
-// CHECK-LL-NEXT: [[tmp131:%.*]] = load i8** [[vp]]
-// CHECK-LL-NEXT: [[cmp132:%.*]] = icmp eq i8* [[tmp131]], getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0)
-// CHECK-LL-NEXT: br i1 [[cmp132]], label %[[ifthen133:.*]], label %[[ifelse135:.*]]
-// CHECK-LL: [[ifthen133]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 14)
-// CHECK-LL-NEXT: br label %[[ifend137:.*]]
-// CHECK-LL: [[ifelse135]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 14)
-// CHECK-LL-NEXT: br label %[[ifend137]]
-// CHECK-LL: [[ifend137]]
-// CHECK-LL-NEXT: [[tmp139:%.*]] = load %class.test1_A** [[ap]]
-// CHECK-LL-NEXT: [[v73:%.*]] = icmp ne %class.test1_A* [[tmp139]], null
-// CHECK-LL-NEXT: br i1 [[v73]], label %[[v74:.*]], label %[[v79:.*]]
-// CHECK-LL: [[v75:%.*]] = bitcast %class.test1_A* [[tmp139]] to i64**
-// CHECK-LL-NEXT: [[vtable140:%.*]] = load i64** [[v75]]
-// CHECK-LL-NEXT: [[v76:%.*]] = getelementptr inbounds i64* [[vtable140]], i64 -2
-// CHECK-LL-NEXT: [[offsettotop141:%.*]] = load i64* [[v76]]
-// CHECK-LL-NEXT: [[v77:%.*]] = bitcast %class.test1_A* [[tmp139]] to i8*
-// CHECK-LL-NEXT: [[v78:%.*]] = getelementptr inbounds i8* [[v77]], i64 [[offsettotop141]]
-// CHECK-LL-NEXT: br label %[[v80:.*]]
-// CHECK-LL: br label %[[v80]]
-// CHECK-LL: [[v81:%.*]] = phi i8* [ [[v78]], %[[v74]] ], [ null, %[[v79]] ]
-// CHECK-LL-NEXT: store i8* [[v81]], i8** [[cvp]]
-// CHECK-LL-NEXT: [[tmp142:%.*]] = load i8** [[cvp]]
-// CHECK-LL-NEXT: [[cmp143:%.*]] = icmp eq i8* [[tmp142]], getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0)
-// CHECK-LL-NEXT: br i1 [[cmp143]], label %[[ifthen144:.*]], label %[[ifelse146:.*]]
-// CHECK-LL: [[ifthen144]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 15)
-// CHECK-LL-NEXT: br label %[[ifend148:.*]]
-// CHECK-LL: [[ifelse146]]
-// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 15)
-// CHECK-LL-NEXT: br label %[[ifend148]]
-// CHECK-LL: [[ifend148]]
-// CHECK-LL-NEXT: ret void
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index 5ae65ccfaab6..6c44c7612966 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s
struct test1_D {
diff --git a/test/CodeGenCXX/exceptions-no-rtti.cpp b/test/CodeGenCXX/exceptions-no-rtti.cpp
index bbbc1b8a8bb6..902d6ac2973a 100644
--- a/test/CodeGenCXX/exceptions-no-rtti.cpp
+++ b/test/CodeGenCXX/exceptions-no-rtti.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fno-rtti -fexceptions %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -fcxx-exceptions -fexceptions %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK: @_ZTIN5test11AE = linkonce_odr unnamed_addr constant
// CHECK: @_ZTIN5test11BE = linkonce_odr unnamed_addr constant
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index 80818189f48b..d9b850672cd1 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
typedef typeof(sizeof(0)) size_t;
@@ -305,3 +305,88 @@ namespace test6 {
}
}
}
+
+// PR9298
+namespace test7 {
+ struct A { A(); ~A(); };
+ struct B {
+ // The throw() operator means that a bad allocation is signalled
+ // with a null return, which means that the initializer is
+ // evaluated conditionally.
+ static void *operator new(size_t size) throw();
+ B(const A&, B*);
+ ~B();
+ };
+
+ B *test() {
+ // CHECK: define [[B:%.*]]* @_ZN5test74testEv()
+ // CHECK: [[OUTER_NEW:%.*]] = alloca i1
+ // CHECK-NEXT: alloca [[A:%.*]],
+ // CHECK-NEXT: alloca i8*
+ // CHECK-NEXT: alloca i32
+ // CHECK-NEXT: [[OUTER_A:%.*]] = alloca i1
+ // CHECK-NEXT: alloca i8*
+ // CHECK-NEXT: [[INNER_NEW:%.*]] = alloca i1
+ // CHECK-NEXT: alloca [[A]]
+ // CHECK-NEXT: [[INNER_A:%.*]] = alloca i1
+
+ // These entry-block stores are to deactivate the delete cleanups.
+ // CHECK-NEXT: store i1 false, i1* [[INNER_NEW]]
+ // CHECK-NEXT: store i1 false, i1* [[OUTER_NEW]]
+
+ // Allocate the outer object.
+ // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test71BnwEm(
+ // CHECK-NEXT: icmp eq i8* [[NEW]], null
+
+ // These stores, emitted before the outermost conditional branch,
+ // deactivate the temporary cleanups.
+ // CHECK-NEXT: store i1 false, i1* [[OUTER_A]]
+ // CHECK-NEXT: store i1 false, i1* [[INNER_A]]
+ // CHECK-NEXT: br i1
+
+ // We passed the first null check; activate that cleanup and continue.
+ // CHECK: store i1 true, i1* [[OUTER_NEW]]
+ // CHECK-NEXT: bitcast
+
+ // Create the first A temporary and activate that cleanup.
+ // CHECK-NEXT: invoke void @_ZN5test71AC1Ev(
+ // CHECK: store i1 true, i1* [[OUTER_A]]
+
+ // Allocate the inner object.
+ // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test71BnwEm(
+ // CHECK-NEXT: icmp eq i8* [[NEW]], null
+ // CHECK-NEXT: br i1
+
+ // We passed the second null check; save that pointer, activate
+ // that cleanup, and continue.
+ // CHECK: store i8* [[NEW]]
+ // CHECK-NEXT: store i1 true, i1* [[INNER_NEW]]
+ // CHECK-NEXT: bitcast
+
+ // Build the second A temporary and activate that cleanup.
+ // CHECK-NEXT: invoke void @_ZN5test71AC1Ev(
+ // CHECK: store i1 true, i1* [[INNER_A]]
+
+ // Build the inner B object and deactivate the inner delete cleanup.
+ // CHECK-NEXT: invoke void @_ZN5test71BC1ERKNS_1AEPS0_(
+ // CHECK: store i1 false, i1* [[INNER_NEW]]
+ // CHECK: phi
+
+ // Build the outer B object and deactivate the outer delete cleanup.
+ // CHECK-NEXT: invoke void @_ZN5test71BC1ERKNS_1AEPS0_(
+ // CHECK: store i1 false, i1* [[OUTER_NEW]]
+ // CHECK: phi
+
+ // Destroy the inner A object.
+ // CHECK-NEXT: load i1* [[INNER_A]]
+ // CHECK-NEXT: br i1
+ // CHECK: invoke void @_ZN5test71AD1Ev(
+
+ // Destroy the outer A object.
+ // CHECK: load i1* [[OUTER_A]]
+ // CHECK-NEXT: br i1
+ // CHECK: invoke void @_ZN5test71AD1Ev(
+
+ return new B(A(), new B(A(), 0));
+ }
+}
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index b82958568a8a..8daf3c680006 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s
// This check logically is attached to 'template int S<int>::i;' below.
-// CHECK: @_ZN1SIiE1iE = weak global i32
+// CHECK: @_ZN1SIiE1iE = weak_odr global i32
template<typename T, typename U, typename Result>
struct plus {
diff --git a/test/CodeGenCXX/for-range-temporaries.cpp b/test/CodeGenCXX/for-range-temporaries.cpp
new file mode 100644
index 000000000000..be594ce5223d
--- /dev/null
+++ b/test/CodeGenCXX/for-range-temporaries.cpp
@@ -0,0 +1,131 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -UDESUGAR %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - -DDESUGAR %s | opt -instnamer -S | FileCheck %s
+
+struct A {
+ A();
+ A(const A &);
+ ~A();
+};
+
+struct B {
+ B();
+ B(const B &);
+ ~B();
+};
+
+struct C {
+ C(const B &);
+ C(const C &);
+ ~C();
+};
+
+struct E;
+struct D {
+ D(const C &);
+ D(const D &);
+ ~D();
+};
+E begin(D);
+E end(D);
+
+struct F;
+struct G;
+struct H;
+struct E {
+ E(const E &);
+ ~E();
+ F operator*();
+ G operator++();
+ H operator!=(const E &o);
+};
+
+struct I;
+struct F {
+ F(const F &);
+ ~F();
+ operator I();
+};
+
+struct G {
+ G(const G &);
+ ~G();
+ operator bool();
+};
+
+struct H {
+ H(const H &);
+ ~H();
+ operator bool();
+};
+
+struct I {
+ I(const I &);
+ ~I();
+};
+
+void body(const I &);
+
+void for_temps() {
+ A a;
+#ifdef DESUGAR
+ {
+ auto && __range = D(B());
+ for (auto __begin = begin(__range), __end = end(__range);
+ __begin != __end; ++__begin) {
+ I i = *__begin;
+ body(i);
+ }
+ }
+#else
+ for (I i : D(B())) {
+ body(i);
+ }
+#endif
+}
+
+// CHECK: define void @_Z9for_tempsv()
+// CHECK: call void @_ZN1AC1Ev(
+// CHECK: call void @_ZN1BC1Ev(
+// CHECK: call void @_ZN1CC1ERK1B(
+// CHECK: call void @_ZN1DC1ERK1C(
+// CHECK: call void @_ZN1CD1Ev(
+// CHECK: call void @_ZN1BD1Ev(
+// CHECK: call void @_ZN1DC1ERKS_(
+// CHECK: call void @_Z5begin1D(
+// CHECK: call void @_ZN1DD1Ev(
+// CHECK: call void @_ZN1DC1ERKS_(
+// CHECK: call void @_Z3end1D(
+// CHECK: call void @_ZN1DD1Ev(
+// CHECK: br label %[[COND:.*]]
+
+// CHECK: [[COND]]:
+// CHECK: call void @_ZN1EneERKS_(
+// CHECK: %[[CMP:.*]] = call zeroext i1 @_ZN1HcvbEv(
+// CHECK: call void @_ZN1HD1Ev(
+// CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
+
+// CHECK: [[CLEANUP]]:
+// CHECK: call void @_ZN1ED1Ev(
+// CHECK: call void @_ZN1ED1Ev(
+// In for-range:
+// call void @_ZN1DD1Ev(
+// CHECK: br label %[[END:.*]]
+
+// CHECK: [[BODY]]:
+// CHECK: call void @_ZN1EdeEv(
+// CHECK: call void @_ZN1Fcv1IEv(
+// CHECK: call void @_ZN1FD1Ev(
+// CHECK: call void @_Z4bodyRK1I(
+// CHECK: call void @_ZN1ID1Ev(
+// CHECK: br label %[[INC:.*]]
+
+// CHECK: [[INC]]:
+// CHECK: call void @_ZN1EppEv(
+// CHECK: call void @_ZN1GD1Ev(
+// CHECK: br label %[[COND]]
+
+// CHECK: [[END]]:
+// In desugared version:
+// call void @_ZN1DD1Ev(
+// CHECK: call void @_ZN1AD1Ev(
+// CHECK: ret void
diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp
new file mode 100644
index 000000000000..af4664462351
--- /dev/null
+++ b/test/CodeGenCXX/for-range.cpp
@@ -0,0 +1,128 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++0x -emit-llvm -o - %s | opt -instnamer -S | FileCheck %s
+
+struct A {
+ A();
+ A(const A&);
+ ~A();
+};
+
+struct B {
+ B();
+ B(const B&);
+ ~B();
+};
+
+struct C {
+ C();
+ C(const C&);
+ ~C();
+};
+
+struct D {
+ D();
+ D(const D&);
+ ~D();
+
+ B *begin();
+ B *end();
+};
+
+namespace std {
+ B *begin(C&);
+ B *end(C&);
+}
+
+extern B array[5];
+
+// CHECK: define void @_Z9for_arrayv(
+void for_array() {
+ // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
+ A a;
+ for (B b : array) {
+ // CHECK-NOT: 5begin
+ // CHECK-NOT: 3end
+ // CHECK: getelementptr {{.*}}, i32 0
+ // CHECK: getelementptr {{.*}}, i64 5
+ // CHECK: br label %[[COND:.*]]
+
+ // CHECK: [[COND]]:
+ // CHECK: %[[CMP:.*]] = icmp ne
+ // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]]
+
+ // CHECK: [[BODY]]:
+ // CHECK: call void @_ZN1BC1ERKS_(
+ // CHECK: call void @_ZN1BD1Ev(
+ // CHECK: br label %[[INC:.*]]
+
+ // CHECK: [[INC]]:
+ // CHECK: getelementptr {{.*}} i32 1
+ // CHECK: br label %[[COND]]
+ }
+ // CHECK: [[END]]:
+ // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
+ // CHECK: ret void
+}
+
+// CHECK: define void @_Z9for_rangev(
+void for_range() {
+ // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
+ A a;
+ for (B b : C()) {
+ // CHECK: call void @_ZN1CC1Ev(
+ // CHECK: = call %struct.A* @_ZSt5beginR1C(
+ // CHECK: = call %struct.A* @_ZSt3endR1C(
+ // CHECK: br label %[[COND:.*]]
+
+ // CHECK: [[COND]]:
+ // CHECK: %[[CMP:.*]] = icmp ne
+ // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
+
+ // CHECK: [[CLEANUP]]:
+ // CHECK: call void @_ZN1CD1Ev(
+ // CHECK: br label %[[END:.*]]
+
+ // CHECK: [[BODY]]:
+ // CHECK: call void @_ZN1BC1ERKS_(
+ // CHECK: call void @_ZN1BD1Ev(
+ // CHECK: br label %[[INC:.*]]
+
+ // CHECK: [[INC]]:
+ // CHECK: getelementptr {{.*}} i32 1
+ // CHECK: br label %[[COND]]
+ }
+ // CHECK: [[END]]:
+ // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
+ // CHECK: ret void
+}
+
+// CHECK: define void @_Z16for_member_rangev(
+void for_member_range() {
+ // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]])
+ A a;
+ for (B b : D()) {
+ // CHECK: call void @_ZN1DC1Ev(
+ // CHECK: = call %struct.A* @_ZN1D5beginEv(
+ // CHECK: = call %struct.A* @_ZN1D3endEv(
+ // CHECK: br label %[[COND:.*]]
+
+ // CHECK: [[COND]]:
+ // CHECK: %[[CMP:.*]] = icmp ne
+ // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]]
+
+ // CHECK: [[CLEANUP]]:
+ // CHECK: call void @_ZN1DD1Ev(
+ // CHECK: br label %[[END:.*]]
+
+ // CHECK: [[BODY]]:
+ // CHECK: call void @_ZN1BC1ERKS_(
+ // CHECK: call void @_ZN1BD1Ev(
+ // CHECK: br label %[[INC:.*]]
+
+ // CHECK: [[INC]]:
+ // CHECK: getelementptr {{.*}} i32 1
+ // CHECK: br label %[[COND]]
+ }
+ // CHECK: [[END]]:
+ // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]])
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index 600327081681..9bd7390d076c 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -20,8 +20,8 @@ struct D { ~D(); };
// PR6205: The casts should not require global initializers
// CHECK: @_ZN6PR59741cE = external global %"struct.PR5974::C"
-// CHECK: @_ZN6PR59741aE = global %"struct.PR5974::A"* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to %"struct.PR5974::A"*), align 8
-// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::A"* bitcast (i8* getelementptr (%"struct.PR5974::C"* @_ZN6PR59741cE, i32 0, i32 0, i64 4) to %"struct.PR5974::A"*), align 8
+// CHECK: @_ZN6PR59741aE = global %"struct.PR5974::A"* getelementptr inbounds (%"struct.PR5974::C"* @_ZN6PR59741cE, i32 0, i32 0)
+// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::A"* bitcast (i8* getelementptr (i8* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to i8*), i64 4) to %"struct.PR5974::A"*), align 8
// CHECK: call void @_ZN1AC1Ev(%struct.A* @a)
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
@@ -90,6 +90,23 @@ namespace PR5974 {
// CHECK-NEXT: sub
// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1yE
+// PR9570: the indirect field shouldn't crash IR gen.
+namespace test5 {
+ static union {
+ unsigned bar[4096] __attribute__((aligned(128)));
+ };
+}
+
+namespace test6 {
+ struct A {
+ A();
+ };
+ extern int foo();
+
+ // This needs an initialization function but not guard variables.
+ __attribute__((weak)) int x = foo();
+}
+
// At the end of the file, we check that y is initialized before z.
// CHECK: define internal void @_GLOBAL__I_a() section "__TEXT,__StaticInit,regular,pure_instructions" {
diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp
index 938d4e12d8d5..3286b228b25f 100644
--- a/test/CodeGenCXX/goto.cpp
+++ b/test/CodeGenCXX/goto.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fexceptions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fcxx-exceptions -fexceptions -emit-llvm -o - | FileCheck %s
// Reduced from a crash on boost::interprocess's node_allocator_test.cpp.
namespace test0 {
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index e5f26e584b06..46c46f04a8a2 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -49,3 +49,63 @@ namespace Casts {
// CHECK: define weak_odr void @_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE(
template void auto_<int>(int*);
}
+
+namespace test1 {
+ short foo(short);
+ int foo(int);
+
+ // CHECK: define linkonce_odr signext i16 @_ZN5test11aIsEEDTcl3foocvT__EEES1_(
+ template <class T> auto a(T t) -> decltype(foo(T())) { return foo(t); }
+
+ // CHECK: define linkonce_odr signext i16 @_ZN5test11bIsEEDTcp3foocvT__EEES1_(
+ template <class T> auto b(T t) -> decltype((foo)(T())) { return (foo)(t); }
+
+ void test(short s) {
+ a(s);
+ b(s);
+ }
+}
+
+namespace test2 {
+ template <class T> void a(T x, decltype(x()) y) {}
+ template <class T> auto b(T x) -> decltype(x()) { return x(); }
+ template <class T> void c(T x, void (*p)(decltype(x()))) {}
+ template <class T> void d(T x, auto (*p)() -> decltype(x())) {}
+ template <class T> void e(auto (*p)(T y) -> decltype(y())) {}
+ template <class T> void f(void (*p)(T x, decltype(x()) y)) {}
+ template <class T> void g(T x, decltype(x()) y) {
+ static decltype(x()) variable;
+ variable = 0;
+ }
+ template <class T> void h(T x, decltype((decltype(x())(*)()) 0) y) {}
+ template <class T> void i(decltype((auto (*)(T x) -> decltype(x())) 0) y) {}
+
+ float foo();
+ void bar(float);
+ float baz(float(*)());
+ void fred(float(*)(), float);
+
+ // CHECK: define void @_ZN5test211instantiateEv
+ void instantiate() {
+ // CHECK: call void @_ZN5test21aIPFfvEEEvT_DTclfL0p_EE(
+ a(foo, 0.0f);
+ // CHECK: call float @_ZN5test21bIPFfvEEEDTclfp_EET_(
+ (void) b(foo);
+ // CHECK: call void @_ZN5test21cIPFfvEEEvT_PFvDTclfL1p_EEE(
+ c(foo, bar);
+ // CHECK: call void @_ZN5test21dIPFfvEEEvT_PFDTclfL0p_EEvE(
+ d(foo, foo);
+ // CHECK: call void @_ZN5test21eIPFfvEEEvPFDTclfp_EET_E(
+ e(baz);
+ // CHECK: call void @_ZN5test21fIPFfvEEEvPFvT_DTclfL0p_EEE(
+ f(fred);
+ // CHECK: call void @_ZN5test21gIPFfvEEEvT_DTclfL0p_EE(
+ g(foo, 0.0f);
+ // CHECK: call void @_ZN5test21hIPFfvEEEvT_DTcvPFDTclfL0p_EEvELi0EE(
+ h(foo, foo);
+ // CHECK: call void @_ZN5test21iIPFfvEEEvDTcvPFDTclfp_EET_ELi0EE(
+ i<float(*)()>(baz);
+ }
+
+ // CHECK: store float {{.*}}, float* @_ZZN5test21gIPFfvEEEvT_DTclfL0p_EEE8variable,
+}
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
index 8d79988da8e3..fea3582d321a 100644
--- a/test/CodeGenCXX/mangle-subst-std.cpp
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -5,8 +5,8 @@
// CHECK: @_ZTTSd = linkonce_odr unnamed_addr constant
// CHECK: @_ZTVSd = linkonce_odr unnamed_addr constant
-// CHECK: @_ZTCSd0_Si = internal constant
-// CHECK: @_ZTCSd16_So = internal constant
+// CHECK: @_ZTCSd0_Si = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTCSd16_So = linkonce_odr unnamed_addr constant
// CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant
// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant
// CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index ec496fe1f753..27777a51c4f1 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -183,7 +183,7 @@ template <typename T> typename T::U ft6(const T&) { return 0; }
// CHECK: @_Z3ft6I1SENT_1UERKS1_
template int ft6<S>(const S&);
-template<typename> struct __is_scalar {
+template<typename> struct __is_scalar_type {
enum { __value = 1 };
};
@@ -194,11 +194,11 @@ template<typename T> struct __enable_if<true, T> {
};
// PR5063
-template<typename T> typename __enable_if<__is_scalar<T>::__value, void>::__type ft7() { }
+template<typename T> typename __enable_if<__is_scalar_type<T>::__value, void>::__type ft7() { }
-// CHECK: @_Z3ft7IiEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft7IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft7<int>();
-// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft7<void*>();
// PR5144
@@ -225,15 +225,15 @@ struct S7 {
S7::S7() {}
// PR5063
-template<typename T> typename __enable_if<(__is_scalar<T>::__value), void>::__type ft8() { }
-// CHECK: @_Z3ft8IiEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+template<typename T> typename __enable_if<(__is_scalar_type<T>::__value), void>::__type ft8() { }
+// CHECK: @_Z3ft8IiEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft8<int>();
-// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr11__is_scalarIT_E7__valueEvE6__typeEv
+// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr16__is_scalar_typeIT_E7__valueEvE6__typeEv
template void ft8<void*>();
// PR5796
namespace PR5796 {
-template<typename> struct __is_scalar {
+template<typename> struct __is_scalar_type {
enum { __value = 0 };
};
@@ -241,8 +241,8 @@ template<bool, typename> struct __enable_if {};
template<typename T> struct __enable_if<true, T> { typedef T __type; };
template<typename T>
-// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsrNS_11__is_scalarIT_EE7__valueEvE6__typeEv
-typename __enable_if<!__is_scalar<T>::__value, void>::__type __fill_a() { };
+// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsrNS_16__is_scalar_typeIT_EE7__valueEvE6__typeEv
+typename __enable_if<!__is_scalar_type<T>::__value, void>::__type __fill_a() { };
void f() { __fill_a<int>(); }
}
@@ -348,7 +348,7 @@ namespace test0 {
char buffer[sizeof(float)];
g<float>(buffer);
}
- // CHECK: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40A00000E_c(
+ // CHECK: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c(
template <class T> void h(char (&buffer)[sizeof(T() + 5.0)]) {}
void test3() {
@@ -373,7 +373,7 @@ namespace test1 {
template void f(X<int>);
}
-// CHECK: define internal void @_Z27functionWithInternalLinkagev()
+// CHECK: define internal void @_ZL27functionWithInternalLinkagev()
static void functionWithInternalLinkage() { }
void g() { functionWithInternalLinkage(); }
@@ -390,26 +390,29 @@ namespace test2 {
// CHECK: define linkonce_odr i32 @_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_(
}
+// rdar://problem/9280586
namespace test3 {
struct AmbiguousBase { int ab; };
struct Path1 : AmbiguousBase { float p; };
struct Path2 : AmbiguousBase { double p; };
struct Derived : Path1, Path2 { };
- //template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; }
- //template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; }
+ // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path1E2abERS2_(
+ template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; }
- // define weak_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path11pERS2_(
+ // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path2E2abERS2_(
+ template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; }
+
+ // CHECK: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path1E1pERS2_(
template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; }
- // define weak_odr double @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path21pERS2_(
+ // CHECK: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path2E1pERS2_(
template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; }
Derived obj;
void test() {
- // FIXME: uncomment these when we support diamonds competently
- //get_ab_1(obj);
- //get_ab_2(obj);
+ get_ab_1(obj);
+ get_ab_2(obj);
get_p_1(obj);
get_p_2(obj);
}
@@ -647,3 +650,29 @@ namespace test23 {
void f(vpca5 volatile (&)[10]) {}
// CHECK: define void @_ZN6test231fERA10_A5_VKPv(
}
+
+namespace test24 {
+ void test0() {
+ extern int foo();
+ // CHECK: call i32 @_ZN6test243fooEv()
+ foo();
+ }
+
+ static char foo() {}
+ void test1() {
+ // CHECK: call signext i8 @_ZN6test24L3fooEv()
+ foo();
+ }
+}
+
+// rdar://problem/8806641
+namespace test25 {
+ template <void (*fn)()> struct A {
+ static void call() { fn(); }
+ };
+ void foo();
+ void test() {
+ // CHECK: call void @_ZN6test251AIXadL_ZNS_3fooEvEEE4callEv()
+ A<foo>::call();
+ }
+}
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index 78a571e196e4..011e9cd68556 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -209,3 +209,26 @@ namespace test8 {
return pmf();
}
}
+
+namespace test9 {
+ struct A {
+ void foo();
+ };
+ struct B : A {
+ void foo();
+ };
+
+ typedef void (A::*fooptr)();
+
+ struct S {
+ fooptr p;
+ };
+
+ // CHECK: define void @_ZN5test94testEv(
+ // CHECK: alloca i32
+ // CHECK-NEXT: ret void
+ void test() {
+ int x;
+ static S array[] = { (fooptr) &B::foo };
+ }
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index d03b21bacbaf..ad6fa4f74456 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -O1 -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
+// RUN: %clang_cc1 -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
// Test code generation for the named return value optimization.
class X {
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index 40723a856cd6..2a22d23e509d 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -55,7 +55,7 @@ namespace ZeroInit {
};
struct C : A, B { int j; };
- // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer }
+ // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.PR7139::ptr_to_member_struct"] [%"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }, %"struct.PR7139::ptr_to_member_struct" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8
C c;
}
@@ -172,15 +172,15 @@ struct A {
int A::*i;
};
-// CHECK-GLOBAL: @_ZN12VirtualBases1bE = global {{%.*}} { i32 (...)** null, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
+// CHECK-GLOBAL: @_ZN12VirtualBases1bE = global %"struct.VirtualBases::B" { i32 (...)** null, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8
struct B : virtual A { };
B b;
-// CHECK-GLOBAL: @_ZN12VirtualBases1cE = global {{%.*}} { i32 (...)** null, i64 -1, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
+// CHECK-GLOBAL: @_ZN12VirtualBases1cE = global %"struct.VirtualBases::C" { i32 (...)** null, i64 -1, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8
struct C : virtual A { int A::*i; };
C c;
- // CHECK-GLOBAL: @_ZN12VirtualBases1dE = global {{%.*}} { [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i64 -1, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
+// CHECK-GLOBAL: @_ZN12VirtualBases1dE = global %"struct.VirtualBases::D" { %"struct.VirtualBases::C.base" { i32 (...)** null, i64 -1 }, i64 -1, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8
struct D : C { int A::*i; };
D d;
@@ -227,6 +227,6 @@ namespace test4 {
struct C : virtual B { int *C_p; };
struct D : C { int *D_p; };
- // CHECK-GLOBAL: @_ZN5test41dE = global {{%.*}} { [16 x i8] zeroinitializer, i32* null, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", [4 x i8] zeroinitializer }
+ // CHECK-GLOBAL: @_ZN5test41dE = global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, i32* null, %"struct.VirtualBases::C.base" { i32 (...)** null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8
D d;
}
diff --git a/test/CodeGenCXX/pragma-pack.cpp b/test/CodeGenCXX/pragma-pack.cpp
index c0ddb1d855a9..c0b025978467 100644
--- a/test/CodeGenCXX/pragma-pack.cpp
+++ b/test/CodeGenCXX/pragma-pack.cpp
@@ -10,5 +10,7 @@ struct Sub : virtual Base {
char c;
};
-// CHECK: %struct.Sub = type <{ i32 (...)**, i8, [8 x i8] }>
+// CHECK: %struct.Sub = type <{ i32 (...)**, i8, %struct.Base }>
void f(Sub*) { }
+
+static int i[sizeof(Sub) == 13 ? 1 : -1];
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index d2ad98013553..25bc8d801790 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -258,3 +258,14 @@ void f() {
}
}
+// PR9494
+namespace N5 {
+struct AnyS { bool b; };
+void f(const bool&);
+AnyS g();
+void h() {
+ // CHECK: call i8 @_ZN2N51gEv()
+ // CHECK: call void @_ZN2N51fERKb(i8*
+ f(g().b);
+}
+}
diff --git a/test/CodeGenCXX/specialized-static-data-mem-init.cpp b/test/CodeGenCXX/specialized-static-data-mem-init.cpp
index 8f5765bcbbe9..c2a2ddb11254 100644
--- a/test/CodeGenCXX/specialized-static-data-mem-init.cpp
+++ b/test/CodeGenCXX/specialized-static-data-mem-init.cpp
@@ -2,8 +2,8 @@
// rdar: // 8562966
// pr8409
-// CHECK: @_ZN1CIiE11needs_guardE = weak global
-// CHECK: @_ZGVN1CIiE11needs_guardE = weak global
+// CHECK: @_ZN1CIiE11needs_guardE = weak_odr global
+// CHECK: @_ZGVN1CIiE11needs_guardE = weak_odr global
struct K
{
diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp
index 64fca2eb6837..b19067af61df 100644
--- a/test/CodeGenCXX/static-data-member.cpp
+++ b/test/CodeGenCXX/static-data-member.cpp
@@ -2,8 +2,8 @@
// CHECK: @_ZN5test11A1aE = constant i32 10, align 4
// CHECK: @_ZN5test212_GLOBAL__N_11AIiE1xE = internal global i32 0, align 4
-// CHECK: @_ZN5test31AIiE1xE = weak global i32 0, align 4
-// CHECK: @_ZGVN5test31AIiE1xE = weak global i64 0
+// CHECK: @_ZN5test31AIiE1xE = weak_odr global i32 0, align 4
+// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0
// PR5564.
namespace test1 {
diff --git a/test/CodeGenCXX/static-init-3.cpp b/test/CodeGenCXX/static-init-3.cpp
index 5bf76a61708e..bd717caaa172 100644
--- a/test/CodeGenCXX/static-init-3.cpp
+++ b/test/CodeGenCXX/static-init-3.cpp
@@ -16,8 +16,8 @@ struct X1
}
};
-// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak global %struct.X0* null, align 8
-// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak global %struct.X0* null, align 8
+// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak_odr global %struct.X0* null, align 8
+// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak_odr global %struct.X0* null, align 8
template<class T> T & X1<T>::instance = X1<T>::get();
class A { };
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index dd9ed61434e2..78749a7a2faf 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -2,7 +2,7 @@
// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
-// CHECK: @_ZZN5test16getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16
+// CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16
// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0
// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0
@@ -50,7 +50,7 @@ namespace test0 {
}
namespace test1 {
- // CHECK: define internal i32 @_ZN5test16getvarEi(
+ // CHECK: define internal i32 @_ZN5test1L6getvarEi(
static inline int getvar(int index) {
static const int var[] = { 1, 0, 2, 4 };
return var[index];
diff --git a/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp b/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp
index ca4446cd200e..2c62b60b1100 100644
--- a/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp
+++ b/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fvisibility hidden -emit-llvm -o - %s | FileCheck %s
// Verify that symbols are hidden.
-// CHECK: @_ZN1CIiE5Inner6Inner26StaticE = weak hidden global
+// CHECK: @_ZN1CIiE5Inner6Inner26StaticE = weak_odr hidden global
// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner1fEv
// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner6Inner21gEv
diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
index 87be57295cbd..0bd810eeca56 100644
--- a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
+++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - -fexceptions -triple x86_64-apple-darwin10 %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 %s | FileCheck %s
struct X {
X();
diff --git a/test/CodeGenCXX/threadsafe-statics.cpp b/test/CodeGenCXX/threadsafe-statics.cpp
index 65ebc43c5d25..8afc2746f42e 100644
--- a/test/CodeGenCXX/threadsafe-statics.cpp
+++ b/test/CodeGenCXX/threadsafe-statics.cpp
@@ -1,8 +1,11 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck -check-prefix=WITH-TSS %s
-// RUN: %clang_cc1 -emit-llvm -o - %s -fno-threadsafe-statics | FileCheck -check-prefix=NO-TSS %s
+// RUN: %clang_cc1 -emit-llvm -triple=x86_64-apple-darwin10 -o - %s | FileCheck -check-prefix=WITH-TSS %s
+// RUN: %clang_cc1 -emit-llvm -triple=x86_64-apple-darwin10 -o - %s -fno-threadsafe-statics | FileCheck -check-prefix=NO-TSS %s
int f();
+// WITH-TSS: @_ZZ1gvE1a = internal global i32 0, align 4
+// WITH-TSS: @_ZGVZ1gvE1a = internal global i64 0
+
// WITH-TSS: define void @_Z1gv() nounwind
// WITH-TSS: call i32 @__cxa_guard_acquire
// WITH-TSS: call void @__cxa_guard_release
@@ -11,6 +14,9 @@ void g() {
static int a = f();
}
+// NO-TSS: @_ZZ1gvE1a = internal global i32 0, align 4
+// NO-TSS: @_ZGVZ1gvE1a = internal global i8 0
+
// NO-TSS: define void @_Z1gv() nounwind
// NO-TSS-NOT: call i32 @__cxa_guard_acquire
// NO-TSS-NOT: call void @__cxa_guard_release
diff --git a/test/CodeGenCXX/throw-expression-dtor.cpp b/test/CodeGenCXX/throw-expression-dtor.cpp
index f87657fdcc01..0de6683f88d1 100644
--- a/test/CodeGenCXX/throw-expression-dtor.cpp
+++ b/test/CodeGenCXX/throw-expression-dtor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm-only -verify -fexceptions
+// RUN: %clang_cc1 %s -emit-llvm-only -verify -fcxx-exceptions -fexceptions
// PR7281
class A {
diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp
index 1d22ec05c37f..0fd32c44575b 100644
--- a/test/CodeGenCXX/throw-expressions.cpp
+++ b/test/CodeGenCXX/throw-expressions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -emit-llvm-only -verify %s -Wno-unreachable-code
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm-only -verify %s -Wno-unreachable-code
int val = 42;
int& test1() {
diff --git a/test/CodeGenCXX/try-catch.cpp b/test/CodeGenCXX/try-catch.cpp
index 2b5f3232d1fb..89f229fee375 100644
--- a/test/CodeGenCXX/try-catch.cpp
+++ b/test/CodeGenCXX/try-catch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
struct X { };
diff --git a/test/CodeGenCXX/typeid.cpp b/test/CodeGenCXX/typeid.cpp
new file mode 100644
index 000000000000..1af96705ba41
--- /dev/null
+++ b/test/CodeGenCXX/typeid.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s
+#include <typeinfo>
+
+namespace Test1 {
+
+// PR7400
+struct A { virtual void f(); };
+
+// CHECK: define i8* @_ZN5Test11fEv
+const char *f() {
+ try {
+ // CHECK: br i1
+ // CHECK: invoke void @__cxa_bad_typeid() noreturn
+ return typeid(*static_cast<A *>(0)).name();
+ } catch (...) {
+ // CHECK: call i8* @llvm.eh.exception
+ }
+
+ return 0;
+}
+
+}
diff --git a/test/CodeGenCXX/unknown-anytype.cpp b/test/CodeGenCXX/unknown-anytype.cpp
new file mode 100644
index 000000000000..902cc8de5c97
--- /dev/null
+++ b/test/CodeGenCXX/unknown-anytype.cpp
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o - %s | FileCheck %s
+
+int test0() {
+ extern __unknown_anytype test0_any;
+ // CHECK: load i32* @test0_any
+ return (int) test0_any;
+}
+
+int test1() {
+ extern __unknown_anytype test1_any();
+ // CHECK: call i32 @_Z9test1_anyv()
+ return (int) test1_any();
+}
+
+extern "C" __unknown_anytype test2_any(...);
+float test2() {
+ // CHECK: call float (...)* @test2_any(double {{[^,]+}})
+ return (float) test2_any(0.5f);
+}
+
+extern "C" __unknown_anytype test2a_any(...);
+float test2a() {
+ // CHECK: call float (...)* @test2a_any(float {{[^,]+}})
+ return (float) test2a_any((float) 0.5f);
+}
+
+float test3() {
+ extern __unknown_anytype test3_any;
+ // CHECK: [[FN:%.*]] = load float (i32)** @test3_any,
+ // CHECK: call float [[FN]](i32 5)
+ return ((float(*)(int)) test3_any)(5);
+}
+
+namespace test4 {
+ extern __unknown_anytype test4_any1;
+ extern __unknown_anytype test4_any2;
+
+ int test() {
+ // CHECK: load i32* @_ZN5test410test4_any1E
+ // CHECK: load i8* @_ZN5test410test4_any2E
+ return (int) test4_any1 + (char) test4_any2;
+ }
+}
+
+extern "C" __unknown_anytype test5_any();
+void test5() {
+ // CHECK: call void @test5_any()
+ return (void) test5_any();
+}
+
+extern "C" __unknown_anytype test6_any(float *);
+long test6() {
+ // CHECK: call i64 @test6_any(float* null)
+ return (long) test6_any(0);
+}
+
+struct Test7 {
+ ~Test7();
+};
+extern "C" __unknown_anytype test7_any(int);
+Test7 test7() {
+ // CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5)
+ return (Test7) test7_any(5);
+}
+
+struct Test8 {
+ __unknown_anytype foo();
+ __unknown_anytype foo(int);
+
+ void test();
+};
+void Test8::test() {
+ float f;
+ // CHECK: call i32 @_ZN5Test83fooEv(
+ f = (int) foo();
+ // CHECK: call i32 @_ZN5Test83fooEi(
+ f = (int) foo(5);
+ // CHECK: call i32 @_ZN5Test83fooEv(
+ f = (float) this->foo();
+ // CHECK: call i32 @_ZN5Test83fooEi(
+ f = (float) this->foo(5);
+}
+void test8(Test8 *p) {
+ double d;
+ // CHECK: call i32 @_ZN5Test83fooEv(
+ d = (double) p->foo();
+ // CHECK: call i32 @_ZN5Test83fooEi(
+ d = (double) p->foo(5);
+ // CHECK: call i32 @_ZN5Test83fooEv(
+ d = (bool) (*p).foo();
+ // CHECK: call i32 @_ZN5Test83fooEi(
+ d = (bool) (*p).foo(5);
+}
+
+extern "C" __unknown_anytype test9_foo;
+void *test9() {
+ // CHECK: ret i8* bitcast (i32* @test9_foo to i8*)
+ return (int*) &test9_foo;
+}
diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
index 258d6926e148..a5a0b67d57d8 100644
--- a/test/CodeGenCXX/value-init.cpp
+++ b/test/CodeGenCXX/value-init.cpp
@@ -83,6 +83,61 @@ namespace ptrmem {
}
}
+namespace PR9801 {
+
+struct Test {
+ Test() : i(10) {}
+ Test(int i) : i(i) {}
+ int i;
+private:
+ int j;
+};
+
+struct Test2 {
+ Test t;
+};
+
+struct Test3 : public Test { };
+
+// CHECK: define void @_ZN6PR98011fEv
+void f() {
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98014TestC1Ei
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98014TestC1Ev
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98014TestC1Ev
+ Test partial[3] = { 1 };
+
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98014TestC1Ev
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98014TestC1Ev
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98014TestC1Ev
+ Test empty[3] = {};
+
+ // CHECK: call void @llvm.memset.p0i8.i64
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98015Test2C1Ev
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98015Test2C1Ev
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98015Test2C1Ev
+ Test2 empty2[3] = {};
+
+ // CHECK: call void @llvm.memset.p0i8.i64
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98015Test3C1Ev
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98015Test3C1Ev
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64
+ // CHECK: call void @_ZN6PR98015Test3C1Ev
+ Test3 empty3[3] = {};
+}
+
+}
+
namespace zeroinit {
struct S { int i; };
@@ -121,6 +176,7 @@ namespace zeroinit {
template<typename>
struct X3 : X2<int> {
X3() : X2<int>() { }
+ int i;
};
@@ -133,7 +189,7 @@ namespace zeroinit {
X3<int>().f();
}
- // CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%struct.B* %this) unnamed_addr
+ // CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index 931465060b62..7644e47ff780 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -411,3 +411,14 @@ namespace Test20 {
B<A<2> >::test5();
}
}
+
+// PR9371
+namespace test21 {
+ enum En { en };
+ template<En> struct A {
+ __attribute__((visibility("default"))) void foo() {}
+ };
+
+ // CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv(
+ template void A<en>::foo();
+}
diff --git a/test/CodeGenCXX/vtable-debug-info.cpp b/test/CodeGenCXX/vtable-debug-info.cpp
index c355406fae4a..9294d20e7292 100644
--- a/test/CodeGenCXX/vtable-debug-info.cpp
+++ b/test/CodeGenCXX/vtable-debug-info.cpp
@@ -2,8 +2,9 @@
// Radar 8730409
// XFAIL: win32
-// FIXME: This test crashes on Windows.
-#ifdef _WIN32
+// FIXME: This test crashes on *-pc-win32
+// for lack of debugging support on -integrated-as (MCCOFF).
+#ifdef _MSC_VER
#error this test must xfail
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index 1cf8a52d44b9..bd696813c814 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -41,6 +41,7 @@
// RUN: FileCheck --check-prefix=CHECK-40 %s < %t
// RUN: FileCheck --check-prefix=CHECK-41 %s < %t
// RUN: FileCheck --check-prefix=CHECK-42 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-43 %s < %t
// For now, just verify this doesn't crash.
namespace test0 {
@@ -1679,3 +1680,24 @@ struct D : virtual B, C {
void D::g() { }
}
+
+namespace Test37 {
+
+// Test that we give C::f the right vtable index. (PR9660).
+struct A {
+ virtual A* f() = 0;
+};
+
+struct B : virtual A {
+ virtual B* f();
+};
+
+// CHECK-43: VTable indices for 'Test37::C' (1 entries).
+// CHECK-43-NEXT: 1 | Test37::C *Test37::C::f()
+struct C : B {
+ virtual C* f();
+};
+
+C* C::f() { return 0; }
+
+}
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index fc14c71a0e48..4633a3fe9569 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -203,7 +203,7 @@ void G_f0() { new G<int>(); }
// RUN: FileCheck --check-prefix=CHECK-H %s < %t
// H<int> has a key function without a body but it's a template instantiation
-// so its VTable must be emmitted.
+// so its VTable must be emitted.
// CHECK-H: @_ZTV1HIiE = linkonce_odr unnamed_addr constant
template <typename T>
class H {
diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp
index e7316989feaa..01f1a445b1c7 100644
--- a/test/CodeGenCXX/x86_64-arguments.cpp
+++ b/test/CodeGenCXX/x86_64-arguments.cpp
@@ -3,13 +3,13 @@
// Basic base class test.
struct f0_s0 { unsigned a; };
struct f0_s1 : public f0_s0 { void *b; };
-// CHECK: define void @_Z2f05f0_s1(i64 %a0.coerce0, i8* %a0.coerce1)
+// CHECK: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1)
void f0(f0_s1 a0) { }
// Check with two eight-bytes in base class.
struct f1_s0 { unsigned a; unsigned b; float c; };
struct f1_s1 : public f1_s0 { float d;};
-// CHECK: define void @_Z2f15f1_s1(i64 %a0.coerce0, double %a0.coerce1)
+// CHECK: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1)
void f1(f1_s1 a0) { }
// Check with two eight-bytes in base class and merge.
@@ -54,7 +54,7 @@ namespace PR7742 { // Also rdar://8250764
struct c2 : public s2 {};
- // CHECK: define double @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P)
+ // CHECK: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P)
c2 foo(c2 *P) {
}
diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m
index 93eeca820117..3cd12a5c2c1a 100644
--- a/test/CodeGenObjC/atomic-aggregate-property.m
+++ b/test/CodeGenObjC/atomic-aggregate-property.m
@@ -23,7 +23,7 @@ struct s1 {
@synthesize y;
@synthesize z;
@end
-
// CHECK-LP64: call void @objc_copyStruct
// CHECK-LP64: call void @objc_copyStruct
// CHECK-LP64: call void @objc_copyStruct
+// CHECK-LP64: call i8* @objc_memmove_collectable
diff --git a/test/CodeGenObjC/attr-availability.m b/test/CodeGenObjC/attr-availability.m
new file mode 100644
index 000000000000..d2b2973c78d3
--- /dev/null
+++ b/test/CodeGenObjC/attr-availability.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fvisibility hidden -fobjc-nonfragile-abi "-triple" "x86_64-apple-darwin8.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_4 %s
+// RUN: %clang_cc1 -fvisibility hidden -fobjc-nonfragile-abi "-triple" "x86_64-apple-darwin9.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_5 %s
+// RUN: %clang_cc1 -fvisibility hidden -fobjc-nonfragile-abi "-triple" "x86_64-apple-darwin10.0.0" -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-10_6 %s
+
+// CHECK-10_4: @"OBJC_CLASS_$_WeakClass1" = extern_weak global
+// CHECK-10_5: @"OBJC_CLASS_$_WeakClass1" = external global
+// CHECK-10_6: @"OBJC_CLASS_$_WeakClass1" = external global
+__attribute__((availability(macosx,introduced=10.5)))
+@interface WeakClass1 @end
+
+@implementation WeakClass1(MyCategory) @end
+
+@implementation WeakClass1(YourCategory) @end
+
+// CHECK-10_4: @"OBJC_CLASS_$_WeakClass2" = extern_weak global
+// CHECK-10_5: @"OBJC_CLASS_$_WeakClass2" = extern_weak global
+// CHECK-10_6: @"OBJC_CLASS_$_WeakClass2" = external global
+__attribute__((availability(macosx,introduced=10.6)))
+@interface WeakClass2 @end
+
+@implementation WeakClass2(MyCategory) @end
+
+@implementation WeakClass2(YourCategory) @end
+
diff --git a/test/CodeGenObjC/bitfield-access.m b/test/CodeGenObjC/bitfield-access.m
index 16b0001ddfda..ab776abd4ea6 100644
--- a/test/CodeGenObjC/bitfield-access.m
+++ b/test/CodeGenObjC/bitfield-access.m
@@ -1,7 +1,8 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -o %t %s
-// RUN: FileCheck -check-prefix=CHECK-I386 < %t %s
-// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -emit-llvm -o %t %s
-// RUN: FileCheck -check-prefix=CHECK-ARM < %t %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -o %t1 %s
+// RUN: FileCheck -check-prefix=CHECK-I386 < %t1 %s
+
+// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -emit-llvm -o %t2 %s
+// RUN: FileCheck -check-prefix=CHECK-ARM < %t2 %s
@interface I0 {
@public
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index 06dc908f2ba3..151c16234214 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -87,3 +87,16 @@ void test2(Test2 *x) {
__weak __block Test2 *weakX = x;
test2_helper(^{ [weakX destroy]; });
}
+
+// rdar://problem/9124263
+// In the test above, check that the use in the invocation function
+// doesn't require a read barrier.
+// CHECK: define internal void @__test2_block_invoke_
+// CHECK: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[WEAK_T]]*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[WEAK_T]]* [[T2]], i32 0, i32 1
+// CHECK-NEXT: [[T4:%.*]] = load [[WEAK_T]]** [[T3]]
+// CHECK-NEXT: [[WEAKX:%.*]] = getelementptr inbounds [[WEAK_T]]* [[T4]], i32 0, i32 6
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[WEAKX]], align 4
diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m
index 227694969bfe..398981362e08 100644
--- a/test/CodeGenObjC/constant-strings.m
+++ b/test/CodeGenObjC/constant-strings.m
@@ -1,6 +1,18 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
-// RUN: %clang_cc1 -fgnu-runtime -emit-llvm -o %t %s && grep NXConstantString %t | count 1
-// RUN: %clang_cc1 -fgnu-runtime -fconstant-string-class NSConstantString -emit-llvm -o %t %s && grep NSConstantString %t | count 1
+// RUN: FileCheck --check-prefix=CHECK-NEXT < %t %s
+// Check that we set alignment 1 on the string.
+//
+// CHECK-NEXT: @.str = {{.*}}constant [13 x i8] c"Hello World!\00", align 1
+
+// RUN: %clang_cc1 -fgnu-runtime -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix=CHECK-GNU < %t %s
+// CHECK-GNU: NXConstantString
+// CHECK-GNU-NOT: NXConstantString
+
+// RUN: %clang_cc1 -fgnu-runtime -fconstant-string-class NSConstantString -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix=CHECK-GNU-WITH-CLASS < %t %s
+// CHECK-GNU-WITH-CLASS: NSConstantString
+// CHECK-GNU-WITH-CLASS-NOT: NSConstantString
id a = @"Hello World!";
diff --git a/test/CodeGenObjC/debug-info-foreach.m b/test/CodeGenObjC/debug-info-foreach.m
index c056e0e249de..89b409c7169e 100644
--- a/test/CodeGenObjC/debug-info-foreach.m
+++ b/test/CodeGenObjC/debug-info-foreach.m
@@ -4,10 +4,17 @@
@class NSArray;
+int i;
void f(NSArray *a) {
id keys;
for (id thisKey in keys) {
+ int j = i;
+ ++j;
+ i = j;
}
for (id thisKey in keys) {
+ int k = i;
+ ++k;
+ i = k;
}
}
diff --git a/test/CodeGenObjC/debug-info-getter-name.m b/test/CodeGenObjC/debug-info-getter-name.m
index 0263f112aeb4..746fcee18298 100644
--- a/test/CodeGenObjC/debug-info-getter-name.m
+++ b/test/CodeGenObjC/debug-info-getter-name.m
@@ -1,5 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -g %s -o %t
-// RUN: grep "\[InstanceVariablesEverywhereButTheInterface someString\]" %t | count 6
+// RUN: %clang_cc1 -fno-dwarf2-cfi-asm -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -g %s -o - | FileCheck %s
+
+//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString]":
+//CHECK: .quad "-[InstanceVariablesEverywhereButTheInterface someString]"
+//CHECK: .ascii "-[InstanceVariablesEverywhereButTheInterface someString]"
+//CHECK: .asciz "-[InstanceVariablesEverywhereButTheInterface someString]"
+//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString].eh":
//rdar: //8498026
diff --git a/test/CodeGenObjC/debug-info-property.m b/test/CodeGenObjC/debug-info-property.m
new file mode 100644
index 000000000000..d86b7c7a5eba
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-property.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
+
+// CHECK: AT_APPLE_property_name
+@interface I1 {
+int p1;
+}
+@property int p1;
+@end
+
+@implementation I1
+@synthesize p1;
+@end
diff --git a/test/CodeGenObjC/fpret.m b/test/CodeGenObjC/fpret.m
index 48848885c1f6..bde0caa8ff3a 100644
--- a/test/CodeGenObjC/fpret.m
+++ b/test/CodeGenObjC/fpret.m
@@ -16,7 +16,7 @@
// CHECK-X86_32: define void @t0()
// CHECK-X86_32: call float bitcast {{.*}} @objc_msgSend_fpret to
-// CHECK-X86_32: call double {{.*}} @objc_msgSend_fpret(
+// CHECK-X86_32: call double bitcast {{.*}} @objc_msgSend_fpret to
// CHECK-X86_32: call x86_fp80 bitcast {{.*}} @objc_msgSend_fpret to
// CHECK-X86_32: }
//
diff --git a/test/CodeGenObjC/instance-method-metadata.m b/test/CodeGenObjC/instance-method-metadata.m
new file mode 100644
index 000000000000..ae87c7a85345
--- /dev/null
+++ b/test/CodeGenObjC/instance-method-metadata.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -o %t %s
+// RUN: FileCheck < %t %s
+
+// rdar://9072317
+
+/** The problem looks like clang getting confused when a single translation unit
+ contains a protocol with a property and two classes that implement that protocol
+ and synthesize the property.
+*/
+
+@protocol Proto
+@property (assign) id prop;
+@end
+
+@interface NSObject @end
+
+@interface Foo : NSObject <Proto> { int x; } @end
+
+@interface Bar : NSObject <Proto> @end
+
+@implementation Foo
+@synthesize prop;
+@end
+
+@implementation Bar
+@synthesize prop;
+@end
+
+// CHECK: l_OBJC_$_INSTANCE_METHODS_Bar:
+// CHECK-NEXT .long 24
+// CHECK-NEXT .long 2
+// CHECK-NEXT .quad L_OBJC_METH_VAR_NAME_
+// CHECK-NEXT .quad L_OBJC_METH_VAR_TYPE_
+// CHECK-NEXT .quad "-[Bar prop]"
diff --git a/test/CodeGenObjC/messages.m b/test/CodeGenObjC/messages.m
index b36fe5b644ed..a921dc774ad1 100644
--- a/test/CodeGenObjC/messages.m
+++ b/test/CodeGenObjC/messages.m
@@ -13,35 +13,35 @@ void f0(id a) {
int i;
MyPoint pt = { 1, 2};
- // CHECK-MAC: call {{.*}} @objc_msgSend(
- // CHECK-MAC-NF: call {{.*}} @objc_msgSend(
+ // CHECK-MAC: call {{.*}} @objc_msgSend to
+ // CHECK-MAC-NF: call {{.*}} @objc_msgSend to
// CHECK-GNU: call {{.*}} @objc_msg_lookup(
// CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender(
[a print0];
// CHECK-MAC: call {{.*}} @objc_msgSend to
// CHECK-MAC-NF: call {{.*}} @objc_msgSend to
- // CHECK-GNU: call {{.*}} @objc_msg_lookup to
- // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender to
+ // CHECK-GNU: call {{.*}} @objc_msg_lookup(
+ // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender(
[a print1: 10];
// CHECK-MAC: call {{.*}} @objc_msgSend to
// CHECK-MAC-NF: call {{.*}} @objc_msgSend to
- // CHECK-GNU: call {{.*}} @objc_msg_lookup to
- // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender to
+ // CHECK-GNU: call {{.*}} @objc_msg_lookup(
+ // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender(
[a print2: 10 and: "hello" and: 2.2];
// CHECK-MAC: call {{.*}} @objc_msgSend to
// CHECK-MAC-NF: call {{.*}} @objc_msgSend to
- // CHECK-GNU: call {{.*}} @objc_msg_lookup to
- // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender to
+ // CHECK-GNU: call {{.*}} @objc_msg_lookup(
+ // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender(
[a takeStruct: pt ];
void *s = @selector(print0);
for (i=0; i<2; ++i)
// CHECK-MAC: call {{.*}} @objc_msgSend to
// CHECK-MAC-NF: call {{.*}} @objc_msgSend to
- // CHECK-GNU: call {{.*}} @objc_msg_lookup to
- // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender to
+ // CHECK-GNU: call {{.*}} @objc_msg_lookup(
+ // CHECK-GNU-NF: call {{.*}} @objc_msg_lookup_sender(
[a performSelector:s];
}
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index dbc06d76cd50..908c95cdf5d2 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -7,11 +7,11 @@
// RUN: grep '@"OBJC_METACLASS_$_A" = global .* section "__DATA, __objc_data", align 8' %t
// RUN: grep '@"\\01L_OBJC_CLASSLIST_REFERENCES_$_[0-9]*" = internal global .* section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8' %t
// RUN: grep '@"\\01L_OBJC_CLASSLIST_SUP_REFS_$_[0-9]*" = internal global .* section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8' %t | count 2
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t
+// RUN: grep '@"\\01L_OBJC_CLASS_NAME_[0-9]*" = internal global .* section "__TEXT,__objc_classname,cstring_literals", align 1' %t
// RUN: grep '@"\\01L_OBJC_LABEL_CATEGORY_$" = internal global .* section "__DATA, __objc_catlist, regular, no_dead_strip", align 8' %t
// RUN: grep '@"\\01L_OBJC_LABEL_CLASS_$" = internal global .* section "__DATA, __objc_classlist, regular, no_dead_strip", align 8' %t
-// RUN: grep '@"\\01L_OBJC_METH_VAR_NAME_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t
-// RUN: grep '@"\\01L_OBJC_METH_VAR_TYPE_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t
+// RUN: grep '@"\\01L_OBJC_METH_VAR_NAME_[0-9]*" = internal global .* section "__TEXT,__objc_methname,cstring_literals", align 1' %t
+// RUN: grep '@"\\01L_OBJC_METH_VAR_TYPE_[0-9]*" = internal global .* section "__TEXT,__objc_methtype,cstring_literals", align 1' %t
// RUN: grep '@"\\01L_OBJC_PROP_NAME_ATTR_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t
// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_*" = internal global .* section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"' %t
// RUN: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t
diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m
index d86422999f61..370ca6eccbe9 100644
--- a/test/CodeGenObjC/metadata_symbols.m
+++ b/test/CodeGenObjC/metadata_symbols.m
@@ -4,7 +4,7 @@
// CHECK-X86_64: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 8
// CHECK-X86_64: @"OBJC_METACLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 8
-// CHECK-X86_64: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK-X86_64: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 8
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH2" = external global
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 8
@@ -28,7 +28,7 @@
// CHECK-ARMV6: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
// CHECK-ARMV6: @"OBJC_METACLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
-// CHECK-ARMV6: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK-ARMV6: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__objc_classname,cstring_literals", align 1
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 4
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH2" = external global
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 4
diff --git a/test/CodeGenObjC/misc-atomic-property.m b/test/CodeGenObjC/misc-atomic-property.m
new file mode 100644
index 000000000000..26402d355b59
--- /dev/null
+++ b/test/CodeGenObjC/misc-atomic-property.m
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
+// rdar: //8808439
+
+typedef struct {
+#ifdef __LP64__
+ unsigned char b[15];
+#else
+ unsigned char b[7];
+#endif
+} bools_minus_one;
+
+typedef struct {
+#ifdef __LP64__
+ unsigned char b[16];
+#else
+ unsigned char b[8];
+#endif
+} bools;
+
+
+@interface Foo
+{
+#ifndef __LP64__
+ bools x;
+ bools_minus_one y;
+#endif
+}
+@property(assign) bools bools_p;
+@property(assign) bools_minus_one bools_minus_one_p;
+@end
+
+@implementation Foo
+@synthesize bools_p=x;
+@synthesize bools_minus_one_p=y;
+@end
+
+#ifdef __LP64__
+typedef __int128_t dword;
+#else
+typedef long long int dword;
+#endif
+
+@interface Test_dwords
+{
+#ifndef __LP64__
+ dword dw;
+#endif
+}
+@property(assign) dword dword_p;
+@end
+
+@implementation Test_dwords
+@synthesize dword_p=dw;
+@end
+
+
+@interface Test_floats
+{
+ float fl;
+ double d;
+ long double ld;
+}
+@property(assign) float fl_p;
+@property(assign) double d_p;
+@property(assign) long double ld_p;
+@end
+
+@implementation Test_floats
+@synthesize fl_p = fl;
+@synthesize d_p = d;
+@synthesize ld_p = ld;
+@end
+
+// CHECK: call void @objc_copyStruct
+// CHECK: call void @objc_copyStruct
+// CHECK: call void @objc_copyStruct
+// CHECK: call void @objc_copyStruct
+// CHECK: call void @objc_copyStruct
+// CHECK: call void @objc_copyStruct
diff --git a/test/CodeGenObjC/missing-atend-metadata.m b/test/CodeGenObjC/missing-atend-metadata.m
deleted file mode 100644
index 50e597c8d1a8..000000000000
--- a/test/CodeGenObjC/missing-atend-metadata.m
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s
-
-@interface I0
-@end
-
-@implementation I0 // expected-warning {{'@end' is missing in implementation context}}
-- meth { return 0; }
-
-@interface I1 : I0
-@end
-
-@implementation I1 // expected-warning {{'@end' is missing in implementation context}}
--(void) im0 { self = [super init]; }
-
-@interface I2 : I0
-- I2meth;
-@end
-
-@implementation I2 // expected-warning {{'@end' is missing in implementation context}}
-- I2meth { return 0; }
-
-@implementation I2(CAT) // expected-warning {{'@end' is missing in implementation context}}
-
-// CHECK: @"\01L_OBJC_CLASS_I1" = internal global
diff --git a/test/CodeGenObjC/no-vararg-messaging.m b/test/CodeGenObjC/no-vararg-messaging.m
new file mode 100644
index 000000000000..f72820a4b66e
--- /dev/null
+++ b/test/CodeGenObjC/no-vararg-messaging.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -o - %s | FileCheck %s
+// rdar://9048030
+
+@interface Foo
++(id)alloc;
+-(id)init;
+-(id)self;
+-(id)retain;
+-(void)release;
+-(id)autorelease;
+@end
+
+void test(void)
+{
+ [[[[[[Foo alloc] init] retain] autorelease] self] release];
+}
+
+// CHECK-NOT: xorb
diff --git a/test/CodeGenObjC/property-agrr-getter.m b/test/CodeGenObjC/property-agrr-getter.m
index 2dd32bb4f373..6d8f1d6b03ad 100644
--- a/test/CodeGenObjC/property-agrr-getter.m
+++ b/test/CodeGenObjC/property-agrr-getter.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -emit-llvm-only %s
typedef struct {
unsigned f0;
@@ -36,3 +36,9 @@ float f ()
AnObject* obj;
return (obj.size).width;
}
+
+// rdar://problem/9272392
+void test3(AnObject *obj) {
+ obj.size;
+ (void) obj.size;
+}
diff --git a/test/CodeGenObjC/simplify-exceptions.mm b/test/CodeGenObjC/simplify-exceptions.mm
new file mode 100644
index 000000000000..a35b10d73d2d
--- /dev/null
+++ b/test/CodeGenObjC/simplify-exceptions.mm
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm \
+// RUN: -fexceptions -fobjc-exceptions -fobjc-nonfragile-abi \
+// RUN: -o %t %s
+// RUN: FileCheck < %t %s
+//
+// <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes
+
+// Check that we don't emit unnecessary personality function references.
+struct t0_A { t0_A(); };
+struct t0_B { t0_A a; };
+
+// CHECK: define {{.*}} @_Z2t0v(){{.*}} {
+// CHECK-NOT: objc_personality
+// CHECK: }
+t0_B& t0() {
+ static t0_B x;
+ return x;
+}
diff --git a/test/CodeGenObjCXX/exceptions.mm b/test/CodeGenObjCXX/exceptions.mm
index 00de88c15220..d4c0756cb89f 100644
--- a/test/CodeGenObjCXX/exceptions.mm
+++ b/test/CodeGenObjCXX/exceptions.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fcxx-exceptions -fexceptions -o - %s | FileCheck %s
@interface OCType @end
void opaque();
diff --git a/test/CodeGenObjCXX/ivar-objects.mm b/test/CodeGenObjCXX/ivar-objects.mm
index d0432edf2b29..d05763b3fcf8 100644
--- a/test/CodeGenObjCXX/ivar-objects.mm
+++ b/test/CodeGenObjCXX/ivar-objects.mm
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK: -[A .cxx_construct]
// CHECK: -[A .cxx_destruct]
+// CHECK: -[B .cxx_construct]
+// CHECK-NOT: -[B .cxx_destruct]
+// CHECK-NOT: -[C .cxx_construct]
+// CHECK: -[C .cxx_destruct]
@interface NSObject
- alloc;
@@ -84,3 +88,17 @@ public:
@implementation I
@synthesize position;
@end
+
+// This class should have a .cxx_construct but no .cxx_destruct.
+namespace test3 { struct S { S(); }; }
+@implementation B {
+ test3::S s;
+}
+@end
+
+// This class should have a .cxx_destruct but no .cxx_construct.
+namespace test4 { struct S { ~S(); }; }
+@implementation C {
+ test4::S s;
+}
+@end
diff --git a/test/CodeGenObjCXX/message-reference.mm b/test/CodeGenObjCXX/message-reference.mm
new file mode 100644
index 000000000000..b7cf98d88c66
--- /dev/null
+++ b/test/CodeGenObjCXX/message-reference.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// rdar://8604515
+
+@interface I {}
+-(unsigned int&)referenceCount;
+@end
+
+@interface MyClass
++(int)writeBlip:(I*)srcBlip;
+@end
+
+@implementation MyClass
++(int)writeBlip:(I*)srcBlip{
+ return ([srcBlip referenceCount] == 0);
+}
+@end
+
+// CHECK: [[T:%.*]] = call i32* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: [[U:%.*]] = load i32* [[T]]
+// CHECK [[V:%.*]] = icmp eq i32 [[U]], 0
diff --git a/test/CodeGenObjCXX/property-reference.mm b/test/CodeGenObjCXX/property-reference.mm
new file mode 100644
index 000000000000..7c235cb9b4ef
--- /dev/null
+++ b/test/CodeGenObjCXX/property-reference.mm
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// rdar://9208606
+
+struct MyStruct
+{
+ int x;
+ int y;
+ int z;
+};
+
+@interface MyClass
+{
+ MyStruct _foo;
+}
+
+@property (assign, readwrite) const MyStruct& foo;
+
+- (const MyStruct&) foo;
+- (void) setFoo:(const MyStruct&)inFoo;
+@end
+
+int main()
+{
+ MyClass* myClass;
+ MyStruct myStruct;
+
+ myClass.foo = myStruct;
+
+ const MyStruct& currentMyStruct = myClass.foo;
+ return 0;
+}
+
+// CHECK: [[C:%.*]] = call %struct.MyStruct* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: store %struct.MyStruct* [[C]], %struct.MyStruct** [[D:%.*]]
diff --git a/test/CodeGenObjCXX/references.mm b/test/CodeGenObjCXX/references.mm
index 8875fd624074..6265c7be7613 100644
--- a/test/CodeGenObjCXX/references.mm
+++ b/test/CodeGenObjCXX/references.mm
@@ -30,7 +30,7 @@ void f(B* b) {
@protocol P2 @end
@protocol P3 @end
@interface foo<P1> {} @end
-@interface bar : foo <P1, P2> {} @end
+@interface bar : foo <P1, P2, P3> {} @end
typedef bar baz;
void f5(foo&);
void f5b(foo<P1>&);
diff --git a/test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl b/test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl
new file mode 100644
index 000000000000..c61be69b5739
--- /dev/null
+++ b/test/CodeGenOpenCL/2011-04-15-vec-init-from-vec.cl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o %t
+
+typedef __attribute__((ext_vector_type(4))) unsigned char uchar4;
+typedef __attribute__((ext_vector_type(4))) unsigned int int4;
+typedef __attribute__((ext_vector_type(8))) unsigned char uchar8;
+
+// OpenCL allows vectors to be initialized by vectors Handle bug in
+// VisitInitListExpr for this case below.
+void foo( int4 v )
+{
+ uchar4 val[4] = {{(uchar4){((uchar8)(v.lo)).lo}}};
+} \ No newline at end of file
diff --git a/test/CodeGenOpenCL/address-spaces.cl b/test/CodeGenOpenCL/address-spaces.cl
new file mode 100644
index 000000000000..e030c77d3e01
--- /dev/null
+++ b/test/CodeGenOpenCL/address-spaces.cl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+
+void f__p(__private int *arg) { }
+// CHECK: i32* nocapture %arg
+
+void f__g(__global int *arg) { }
+// CHECK: i32 addrspace(1)* nocapture %arg
+
+void f__l(__local int *arg) { }
+// CHECK: i32 addrspace(2)* nocapture %arg
+
+void f__c(__constant int *arg) { }
+// CHECK: i32 addrspace(3)* nocapture %arg
+
+
+void fp(private int *arg) { }
+// CHECK: i32* nocapture %arg
+
+void fg(global int *arg) { }
+// CHECK: i32 addrspace(1)* nocapture %arg
+
+void fl(local int *arg) { }
+// CHECK: i32 addrspace(2)* nocapture %arg
+
+void fc(constant int *arg) { }
+// CHECK: i32 addrspace(3)* nocapture %arg
+
diff --git a/test/Coverage/ast-printing.c b/test/Coverage/ast-printing.c
index bbbc366eb711..ecaf3abeaa8a 100644
--- a/test/Coverage/ast-printing.c
+++ b/test/Coverage/ast-printing.c
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only %s
// RUN: %clang_cc1 -ast-print %s
// RUN: %clang_cc1 -ast-dump %s
-// RUN: %clang_cc1 -ast-print-xml -o %t %s
// RUN: %clang_cc1 -print-decl-contexts %s
#include "c-language-features.inc"
diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp
index 0de56422895f..3205078758f1 100644
--- a/test/Coverage/ast-printing.cpp
+++ b/test/Coverage/ast-printing.cpp
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only %s
// RUN: %clang_cc1 -ast-print %s
// RUN: %clang_cc1 -ast-dump %s
-// RUN: %clang_cc1 -ast-print-xml -o %t %s
// RUN: %clang_cc1 -print-decl-contexts %s
// RUN: %clang_cc1 -fdump-record-layouts %s
diff --git a/test/Coverage/html-diagnostics.c b/test/Coverage/html-diagnostics.c
index be820fb90f29..4f1b0e3763b8 100644
--- a/test/Coverage/html-diagnostics.c
+++ b/test/Coverage/html-diagnostics.c
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-check-objc-mem -o %t %s
+// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t %s
// RUN: cat %t/*.html | FileCheck %s
// CHECK: <h3>Annotated Source Code</h3>
diff --git a/test/Driver/apple-kext-i386.cpp b/test/Driver/apple-kext-i386.cpp
new file mode 100644
index 000000000000..dc4e6a641f0d
--- /dev/null
+++ b/test/Driver/apple-kext-i386.cpp
@@ -0,0 +1,9 @@
+// Check that we transparently fallback to llvm-gcc for i386 kexts, we don't
+// support the ABI they use (yet).
+
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK < %t %s
+
+// CHECK: cc1plus"
+// CHECK: "-fapple-kext"
diff --git a/test/Driver/apple-kext-mkernel.c b/test/Driver/apple-kext-mkernel.c
index 712dfc8d0eba..82a6896415c2 100644
--- a/test/Driver/apple-kext-mkernel.c
+++ b/test/Driver/apple-kext-mkernel.c
@@ -1,6 +1,18 @@
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -mkernel -### -fsyntax-only %s 2> %t
-// RUN grep "-disable-red-zone" %t
-// RUN grep "-fapple-kext" %t
-// RUN grep "-fno-builtin" %t
-// RUN grep "-fno-rtti" %t
-// RUN grep "-fno-common" %t
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 \
+// RUN: -mkernel -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-X86 < %t %s
+
+// CHECK-X86: "-disable-red-zone"
+// CHECK-X86: "-fno-builtin"
+// CHECK-X86: "-fno-rtti"
+// CHECK-X86: "-fno-common"
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 \
+// RUN: -arch armv7 -mkernel -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-ARM < %t %s
+
+// CHECK-ARM: "-backend-option" "-arm-long-calls"
+// CHECK-ARM: "-backend-option" "-arm-strict-align"
+// CHECK-ARM: "-fno-builtin"
+// CHECK-ARM: "-fno-rtti"
+// CHECK-ARM: "-fno-common"
diff --git a/test/Driver/ast.c b/test/Driver/ast.c
index 6e5857fba5e3..e9fbb068d969 100644
--- a/test/Driver/ast.c
+++ b/test/Driver/ast.c
@@ -22,5 +22,5 @@
// COMPILE-AST-PHASES: END
// FIXME: There is a problem with compiling AST's in that the input language is
-// not availabe for use by other tools (for example, to automatically add
+// not available for use by other tools (for example, to automatically add
// -lstdc++). We may need -x [objective-]c++-ast and all that goodness. :(
diff --git a/test/Driver/cc-log-diagnostics.c b/test/Driver/cc-log-diagnostics.c
new file mode 100644
index 000000000000..a70686ad615a
--- /dev/null
+++ b/test/Driver/cc-log-diagnostics.c
@@ -0,0 +1,29 @@
+// RUN: env RC_DEBUG_OPTIONS=1 \
+// RUN: CC_LOG_DIAGNOSTICS=1 \
+// RUN: CC_LOG_DIAGNOSTICS_FILE=%t.log \
+// RUN: %clang -no-canonical-prefixes -ccc-host-triple x86_64-apple-darwin10 -fsyntax-only %s
+// RUN: FileCheck %s < %t.log
+
+int f0() {}
+
+// CHECK: <dict>
+// CHECK: <key>main-file</key>
+// CHECK: <string>{{.*}}cc-log-diagnostics.c</string>
+// CHECK: <key>dwarf-debug-flags</key>
+// CHECK: <string>{{.*}}clang{{.*}}-fsyntax-only{{.*}}</string>
+// CHECK: <key>diagnostics</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>level</key>
+// CHECK: <string>warning</string>
+// CHECK: <key>filename</key>
+// CHECK: <string>{{.*}}cc-log-diagnostics.c</string>
+// CHECK: <key>line</key>
+// CHECK: <integer>7</integer>
+// CHECK: <key>column</key>
+// CHECK: <integer>11</integer>
+// CHECK: <key>message</key>
+// CHECK: <string>control reaches end of non-void function</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
diff --git a/test/Driver/cc-print-options.c b/test/Driver/cc-print-options.c
index 7b798cb08a85..77dd0fef5f98 100644
--- a/test/Driver/cc-print-options.c
+++ b/test/Driver/cc-print-options.c
@@ -1,6 +1,6 @@
// RUN: env CC_PRINT_OPTIONS=1 \
// RUN: CC_PRINT_OPTIONS_FILE=%t.log \
-// RUN: %clang -S -o %t.s %s
+// RUN: %clang -no-canonical-prefixes -S -o %t.s %s
// RUN: FileCheck %s < %t.log
// CHECK: [Logging clang options]{{.*}}clang{{.*}}"-S"
diff --git a/test/Driver/clang-exception-flags.cpp b/test/Driver/clang-exception-flags.cpp
new file mode 100644
index 000000000000..90a9ebf5e44e
--- /dev/null
+++ b/test/Driver/clang-exception-flags.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang -### %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
+// DEFAULT: "-cc1" {{.*}} "-fcxx-exceptions" "-fexceptions"
+//
+// RUN: %clang -### -fexceptions %s 2>&1 | FileCheck %s -check-prefix=ON1
+// ON1: "-cc1" {{.*}} "-fcxx-exceptions" "-fexceptions"
+//
+// RUN: %clang -### -fno-exceptions -fcxx-exceptions %s 2>&1 | FileCheck %s -check-prefix=ON2
+// ON2: "-cc1" {{.*}} "-fcxx-exceptions" "-fexceptions"
+//
+// RUN: %clang -### -fno-cxx-exceptions -fexceptions %s 2>&1 | FileCheck %s -check-prefix=ON3
+// ON3: "-cc1" {{.*}} "-fcxx-exceptions" "-fexceptions"
+//
+// RUN: %clang -### -fno-exceptions %s 2>&1 | FileCheck %s -check-prefix=OFF1
+// OFF1-NOT: "-cc1" {{.*}} "-fcxx-exceptions"
+//
+// RUN: %clang -### -fno-cxx-exceptions %s 2>&1 | FileCheck %s -check-prefix=OFF2
+// OFF2-NOT: "-cc1" {{.*}} "-fcxx-exceptions"
+//
+// RUN: %clang -### -fcxx-exceptions -fno-exceptions %s 2>&1 | FileCheck %s -check-prefix=OFF3
+// OFF3-NOT: "-cc1" {{.*}} "-fcxx-exceptions"
+//
+// RUN: %clang -### -fexceptions -fno-cxx-exceptions %s 2>&1 | FileCheck %s -check-prefix=OFF4
+// OFF4-NOT: "-cc1" {{.*}} "-fcxx-exceptions"
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index 2464f03b7a1e..b2b358f0ebb8 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -31,6 +31,8 @@
// ARMV7_SOFTFLOAT: "-cc1"
// ARMV7_SOFTFLOAT: "-msoft-float"
// ARMV7_SOFTFLOAT: "-mfloat-abi" "soft"
+// ARMV7_SOFTFLOAT: "-target-feature"
+// ARMV7_SOFTFLOAT: "-neon"
// ARMV7_SOFTFLOAT: "-x" "c"
// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### -S %s 2> %t.log \
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 8e6b0fe850de..4eed4aa06f3f 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -12,3 +12,20 @@
// CHECK-OPTIONS2: -fshort-wchar
// CHECK-OPTIONS2: -fno-common
// CHECK-OPTIONS2: -fno-show-source-location
+
+// RUN: %clang -### -S -Wwrite-strings %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS1 %s
+// WRITE-STRINGS1: -fconst-strings
+// RUN: %clang -### -S -Wwrite-strings -Wno-write-strings %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS2 %s
+// WRITE-STRINGS2-NOT: -fconst-strings
+// RUN: %clang -### -S -Wwrite-strings -w %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS3 %s
+// WRITE-STRINGS3: -fconst-strings
+
+// RUN: %clang -### -x c++ -c %s 2>&1 | FileCheck -check-prefix=DEPRECATED-ON-CHECK %s
+// RUN: %clang -### -x c++ -c -Wdeprecated %s 2>&1 | FileCheck -check-prefix=DEPRECATED-ON-CHECK %s
+// RUN: %clang -### -x c++ -c -Wno-deprecated %s 2>&1 | FileCheck -check-prefix=DEPRECATED-OFF-CHECK %s
+// RUN: %clang -### -x c++ -c -Wno-deprecated -Wdeprecated %s 2>&1 | FileCheck -check-prefix=DEPRECATED-ON-CHECK %s
+// RUN: %clang -### -x c++ -c -w %s 2>&1 | FileCheck -check-prefix=DEPRECATED-ON-CHECK %s
+// RUN: %clang -### -c %s 2>&1 | FileCheck -check-prefix=DEPRECATED-OFF-CHECK %s
+// RUN: %clang -### -c -Wdeprecated %s 2>&1 | FileCheck -check-prefix=DEPRECATED-OFF-CHECK %s
+// DEPRECATED-ON-CHECK: -fdeprecated-macro
+// DEPRECATED-OFF-CHECK-NOT: -fdeprecated-macro
diff --git a/test/Driver/clang_wrapv_opts.c b/test/Driver/clang_wrapv_opts.c
new file mode 100644
index 000000000000..826468e0678d
--- /dev/null
+++ b/test/Driver/clang_wrapv_opts.c
@@ -0,0 +1,11 @@
+// RUN: %clang -### -S -fwrapv -fno-wrapv -fwrapv %s 2>&1 | FileCheck -check-prefix=CHECK1 %s
+// CHECK1: -fwrapv
+//
+// RUN: %clang -### -S -fstrict-overflow -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
+// CHECK2: -fwrapv
+//
+// RUN: %clang -### -S -fwrapv -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
+// CHECK3: -fwrapv
+//
+// RUN: %clang -### -S -fno-wrapv -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK4 %s
+// CHECK4-NOT: -fwrapv
diff --git a/test/Driver/darwin-cc.c b/test/Driver/darwin-cc.c
index b068bb4e3fd4..247b02bebea2 100644
--- a/test/Driver/darwin-cc.c
+++ b/test/Driver/darwin-cc.c
@@ -1,5 +1,4 @@
// RUN: %clang -ccc-no-clang -ccc-host-triple i386-apple-darwin10 -m32 -### -MD -g -fast -Q -dA -mkernel -ansi -aFOO -S -o /tmp/OUTPUTNAME -g0 -gfull -O2 -Werror -pedantic -Wmost -w -std=c99 -trigraphs -v -pg -fFOO -undef -Qn --param a=b -fmudflap -coverage -save-temps -nostdinc -I ARG0 -F ARG1 -I ARG2 -P -MF ARG3 -MG -MP -remap -g3 -H -D ARG4 -U ARG5 -A ARG6 -D ARG7 -U ARG8 -A ARG9 -include ARG10 -pthread %s 2> %t.log
-// RUN: grep ' ".*cc1" "-E" "-nostdinc" "-v" "-I" "ARG0" "-FARG1" "-I" "ARG2" "-P" "-MD" "/tmp/OUTPUTNAME.d" "-MF" "ARG3" "-MG" "-MP" "-MQ" "/tmp/OUTPUTNAME" "-remap" "-dD" "-H" "-D__STATIC__" "-D_REENTRANT" "-D" "ARG4" "-U" "ARG5" "-A" "ARG6" "-D" "ARG7" "-U" "ARG8" "-A" "ARG9" "-include" "ARG10" ".*darwin-cc.c" "-D_MUDFLAP" "-include" "mf-runtime.h" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-std=c99" "-trigraphs" "-Werror" "-pedantic" "-Wmost" "-w" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-O2" "-undef" "-fpch-preprocess" "-o" ".*darwin-cc.i"' %t.log
-// RUN: grep ' ".*cc1" "-fpreprocessed" ".*darwin-cc.i" "-O3" "-dumpbase" ".*darwin-cc.c" "-dA" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-aFOO" "-auxbase-strip" "/tmp/OUTPUTNAME" "-g" "-g0" "-g" "-g3" "-O2" "-Werror" "-pedantic" "-Wmost" "-w" "-ansi" "-std=c99" "-trigraphs" "-version" "-p" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-undef" "-fno-ident" "-o" "/tmp/OUTPUTNAME" "--param" "a=b" "-fno-builtin" "-fno-merge-constants" "-fprofile-arcs" "-ftest-coverage"' %t.log
-
-
+// RUN: FileCheck %s < %t.log
+// CHECK: {{ ".*cc1.*" "-E" "-nostdinc" "-v" "-I" "ARG0" "-FARG1" "-I" "ARG2" "-P" "-MD" "[^"]*/OUTPUTNAME.d" "-MF" "ARG3" "-MG" "-MP" "-MQ" "[^"]*/OUTPUTNAME" "-remap" "-dD" "-H" "-D__STATIC__" "-D_REENTRANT" "-D" "ARG4" "-U" "ARG5" "-A" "ARG6" "-D" "ARG7" "-U" "ARG8" "-A" "ARG9" "-include" "ARG10" ".*darwin-cc.c" "-D_MUDFLAP" "-include" "mf-runtime.h" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-std=c99" "-trigraphs" "-Werror" "-pedantic" "-Wmost" "-w" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-O2" "-undef" "-fpch-preprocess" "-o" ".*darwin-cc.i"}}
+// CHECK: {{ ".*cc1.*" "-fpreprocessed" ".*darwin-cc.i" "-O3" "-dumpbase" ".*darwin-cc.c" "-dA" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-aFOO" "-auxbase-strip" "[^"]*/OUTPUTNAME" "-g" "-g0" "-g" "-g3" "-O2" "-Werror" "-pedantic" "-Wmost" "-w" "-ansi" "-std=c99" "-trigraphs" "-version" "-p" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-undef" "-fno-ident" "-o" "[^"]*/OUTPUTNAME" "--param" "a=b" "-fno-builtin" "-fno-merge-constants" "-fprofile-arcs" "-ftest-coverage"}}
diff --git a/test/Driver/darwin-dsymutil.c b/test/Driver/darwin-dsymutil.c
index f1ffcdc589d4..afb41a9db28b 100644
--- a/test/Driver/darwin-dsymutil.c
+++ b/test/Driver/darwin-dsymutil.c
@@ -36,3 +36,10 @@
// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -o foo %t.o -g 2> %t
// RUN: grep "Dsymutil" %t | count 0
+
+// Check that we put the .dSYM in the right place.
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: -o bar/foo %s -g 2> %t
+// RUN: FileCheck -check-prefix=CHECK-LOCATION < %t %s
+
+// CHECK-LOCATION: "x86_64-apple-darwin10" - "darwin::Dsymutil", inputs: ["bar/foo"], output: "bar/foo.dSYM"
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 206e665a2cf3..3f2b69185a58 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -18,8 +18,8 @@
//
// Note that at conception, this exactly matches gcc.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -miphoneos-version-min=2.0 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
-// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-LARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-FARG1"' %t.log
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
+// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-LARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-FARG1"' %t.log
// Check linker changes that came with new linkedit format.
// RUN: touch %t.o
diff --git a/test/Driver/darwin-version.c b/test/Driver/darwin-version.c
index 84533a625246..d9c5c5ed3f7b 100644
--- a/test/Driver/darwin-version.c
+++ b/test/Driver/darwin-version.c
@@ -21,3 +21,11 @@
#error Invalid version
#endif
#endif
+
+// RUN: env MACOSX_DEPLOYMENT_TARGET=10.4.10 \
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST3 -E %s
+#ifdef TEST3
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1049
+#error Invalid version
+#endif
+#endif
diff --git a/test/Driver/darwin-xarch.c b/test/Driver/darwin-xarch.c
index d2fb43e68caf..d16d5318f7f8 100644
--- a/test/Driver/darwin-xarch.c
+++ b/test/Driver/darwin-xarch.c
@@ -4,8 +4,8 @@
// RUN: -c %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-COMPILE < %t %s
//
-// CHECK-COMPILE: clang{{.*}}" "-cc1" "-triple" "i386-apple-darwin8.0.0"
-// CHECK-COMPILE: clang{{.*}}" "-cc1" "-triple" "x86_64-apple-darwin9.0.0"
+// CHECK-COMPILE: clang{{.*}}" "-cc1" "-triple" "i386-apple-macosx10.4.0"
+// CHECK-COMPILE: clang{{.*}}" "-cc1" "-triple" "x86_64-apple-macosx10.5.0"
// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### \
// RUN: -arch i386 -Xarch_i386 -Wl,-some-linker-arg -filelist X 2> %t
diff --git a/test/Driver/exceptions.m b/test/Driver/exceptions.m
new file mode 100644
index 000000000000..7d85fe30aefa
--- /dev/null
+++ b/test/Driver/exceptions.m
@@ -0,0 +1,19 @@
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin9 \
+// RUN: -fsyntax-only -fno-exceptions %s
+
+void f1() {
+ @throw @"A";
+}
+
+void f0() {
+ @try {
+ f1();
+ } @catch (id x) {
+ ;
+ }
+}
+
+int main() {
+ f0();
+ return 0;
+}
diff --git a/test/Driver/hello.c b/test/Driver/hello.c
index da628724d6d9..c2260e53eb38 100644
--- a/test/Driver/hello.c
+++ b/test/Driver/hello.c
@@ -1,9 +1,9 @@
-// RUN: %clang -ccc-echo -o %t %s 2> %t.log
+// RUN: %clang -ccc-echo -o %t.exe %s 2> %t.log
// Make sure we used clang.
-// RUN: grep 'clang" -cc1 .*hello.c' %t.log
+// RUN: grep 'clang\(-[0-9.]\+\)\?\(\.[Ee][Xx][Ee]\)\?" -cc1 .*hello.c' %t.log
-// RUN: %t > %t.out
+// RUN: %t.exe > %t.out
// RUN: grep "I'm a little driver, short and stout." %t.out
// FIXME: We don't have a usable assembler on Windows, so we can't build real
diff --git a/test/Driver/sysroot-flags.c b/test/Driver/sysroot-flags.c
index 461c451e1293..044a86f6331b 100644
--- a/test/Driver/sysroot-flags.c
+++ b/test/Driver/sysroot-flags.c
@@ -2,27 +2,27 @@
// RUN: %clang -### -fsyntax-only -isysroot /foo/bar %s 2>&1 | \
// RUN: FileCheck %s -check-prefix=ISYSROOT
-// ISYSROOT: "-isysroot" "/foo/bar"
+// ISYSROOT: "-isysroot" "{{[^"]*}}/foo/bar"
// Check that we get both isysroot for headers, and pass --sysroot on to GCC to
// produce the final binary.
// RUN: %clang -### -ccc-host-triple x86_64-unknown-linux-gnu \
// RUN: --sysroot=/foo/bar -o /dev/null %s 2>&1 | \
// RUN: FileCheck %s -check-prefix=SYSROOT_EQ
-// SYSROOT_EQ: "-isysroot" "/foo/bar"
-// SYSROOT_EQ: "--sysroot{{" "|=}}/foo/bar"
+// SYSROOT_EQ: "-isysroot" "{{[^"]*}}/foo/bar"
+// SYSROOT_EQ: "--sysroot{{" "|=}}{{[^"]*}}/foo/bar"
// Check for overriding the header sysroot by providing both --sysroot and
// -isysroot.
// RUN: %clang -### -ccc-host-triple x86_64-unknown-linux-gnu -isysroot /baz \
// RUN: --sysroot=/foo/bar -o /dev/null %s 2>&1 | FileCheck %s \
// RUN: -check-prefix=ISYSROOT_AND_SYSROOT
-// ISYSROOT_AND_SYSROOT: "-isysroot" "/baz"
-// ISYSROOT_AND_SYSROOT: "--sysroot{{" "|=}}/foo/bar"
+// ISYSROOT_AND_SYSROOT: "-isysroot" "{{[^"]*}}/baz"
+// ISYSROOT_AND_SYSROOT: "--sysroot{{" "|=}}{{[^"]*}}/foo/bar"
// Check that omitting the equals works as well.
// RUN: %clang -### -ccc-host-triple x86_64-unknown-linux-gnu \
// RUN: --sysroot /foo/bar -o /dev/null %s 2>&1 | \
// RUN: FileCheck %s -check-prefix=SYSROOT_SEPARATE
-// SYSROOT_SEPARATE: "-isysroot" "/foo/bar"
-// SYSROOT_SEPARATE: "--sysroot{{" "|=}}/foo/bar"
+// SYSROOT_SEPARATE: "-isysroot" "{{[^"]*}}/foo/bar"
+// SYSROOT_SEPARATE: "--sysroot{{" "|=}}{{[^"]*}}/foo/bar"
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index d8a858d9da74..90bf9f5c1880 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -14,3 +14,6 @@ void x() {
}
}
+using ::T = void; // expected-error {{name defined in alias declaration must be an identifier}}
+using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}
+using typename ::V = void; // expected-error {{name defined in alias declaration must be an identifier}}
diff --git a/test/FixIt/fixit-unrecoverable.c b/test/FixIt/fixit-unrecoverable.c
index 8052beb5591c..fb6c4e2104be 100644
--- a/test/FixIt/fixit-unrecoverable.c
+++ b/test/FixIt/fixit-unrecoverable.c
@@ -5,6 +5,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// FIXME: Sadly, the following doesn't work within a function.
-
unsinged x = 17; // expected-error{{unknown type name 'unsinged'; did you mean 'unsigned'?}}
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index 9c7443594283..1a6ef635570a 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -48,3 +48,9 @@ enum Color {
Green = 17 // expected-error{{missing ',' between enumerators}}
Blue,
};
+
+// rdar://9295072
+struct test_struct {
+ // CHECK: struct test_struct *struct_ptr;
+ test_struct *struct_ptr; // expected-error {{must use 'struct' tag to refer to type 'test_struct'}}
+};
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 41b187b0718c..ac749859ea05 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -78,3 +78,22 @@ void f() {
}
}
+template <class A>
+class F1 {
+public:
+ template <int B>
+ class Iterator {
+ };
+};
+
+template<class T>
+class F2 {
+ typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-error {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+};
+
+template <class T>
+void f(){
+ typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-error {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+}
+
+
diff --git a/test/FixIt/no-macro-fixit.c b/test/FixIt/no-macro-fixit.c
new file mode 100644
index 000000000000..b6a9285e22f0
--- /dev/null
+++ b/test/FixIt/no-macro-fixit.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -pedantic -fixit -x c %s
+// rdar://9091893
+
+#define va_arg(ap, type) __builtin_va_arg(ap, type)
+typedef __builtin_va_list va_list;
+
+void myFunc() {
+ va_list values;
+
+ int value;
+
+ while (value = va_arg(values, int)) { // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note {{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note {{place parentheses around the assignment to silence this warning}}
+ }
+}
diff --git a/test/FixIt/typo.c b/test/FixIt/typo.c
index 01ff3a09cf3e..88d9dc62a1f2 100644
--- a/test/FixIt/typo.c
+++ b/test/FixIt/typo.c
@@ -1,7 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: cp %s %t
-// RUN: %clang_cc1 -fsyntax-only -fixit -x c %t || true
+// RUN: not %clang_cc1 -fsyntax-only -fixit -x c %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c %t
+// RUN: grep "Rectangle" %t
struct Point {
float x, y;
};
@@ -23,3 +24,14 @@ struct Window window = {
topleft.x = 3.14, // expected-error{{field designator 'topleft' does not refer to any field in type 'struct Rectangle'; did you mean 'top_left'?}}
2.71818, 5.0, 6.0, Red
};
+
+void test() {
+ Rectangle r1; // expected-error{{must use 'struct' tag to refer to type 'Rectangle'}}
+ r1.top_left.x = 0;
+
+ typedef struct Rectangle Rectangle; // expected-note{{'Rectangle' declared here}}
+ rectangle *r2 = &r1; // expected-error{{ unknown type name 'rectangle'; did you mean 'Rectangle'?}}
+ r2->top_left.y = 0;
+ unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
+ *ptr = 17;
+}
diff --git a/test/FixIt/typo.cpp b/test/FixIt/typo.cpp
index d1e732fd1dba..f8b5352374f3 100644
--- a/test/FixIt/typo.cpp
+++ b/test/FixIt/typo.cpp
@@ -1,7 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: cp %s %t
-// RUN: %clang_cc1 -fsyntax-only -fixit -x c++ %t || true
+// RUN: not %clang_cc1 -fsyntax-only -fixit -x c++ %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t
+// RUN: grep test_string %t
namespace std {
template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}}
@@ -64,3 +65,12 @@ struct Derived : public Base { // expected-note{{base class 'Base' specified her
int &Derived::getMember() {
return ember; // expected-error{{use of undeclared identifier 'ember'; did you mean 'member'?}}
}
+
+typedef int Integer; // expected-note{{'Integer' declared here}}
+int global_value; // expected-note{{'global_value' declared here}}
+
+int foo() {
+ integer * i = 0; // expected-error{{unknown type name 'integer'; did you mean 'Integer'?}}
+ unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
+ return *i + *ptr + global_val; // expected-error{{use of undeclared identifier 'global_val'; did you mean 'global_value'?}}
+}
diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m
index 8a474ab16879..ecb207ee3917 100644
--- a/test/FixIt/typo.m
+++ b/test/FixIt/typo.m
@@ -1,22 +1,16 @@
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -DNON_FIXITS -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -x objective-c -E -P %s -o %t
-// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fixit %t || true
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -x objective-c -fsyntax-only -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fixit %t
// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-nonfragile-abi -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -pedantic -Werror %t
-// RUN: false
-// XFAIL: *
+// RUN: grep "@implementation Sub3" %t
-
-@interface NSString // expected-note{{'NSString' declared here}}
+@interface NSString // expected-note 2{{'NSString' declared here}}
+ (int)method:(int)x;
@end
-#ifdef NON_FIXITS
void test() {
- // FIXME: not providing fix-its
- NSstring *str = @"A string"; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}} \
- // expected-error{{use of undeclared identifier 'str'}}
+ NSstring *str = @"A string"; // expected-error{{unknown type name 'NSstring'; did you mean 'NSString'?}}
}
-#endif
@protocol P1
@optional
@@ -166,7 +160,7 @@ void f(A *a) {
@implementation Sub3
- (int)method3 {
- int x = super; // expected-note{{use of undeclared identifier 'super'}}
+ int x = super; // expected-error{{use of undeclared identifier 'super'}}
return 0;
}
@end
diff --git a/test/Frontend/dependency-gen.c b/test/Frontend/dependency-gen.c
index bad84938296a..0f8adabc85aa 100644
--- a/test/Frontend/dependency-gen.c
+++ b/test/Frontend/dependency-gen.c
@@ -8,7 +8,8 @@
// RUN: grep 'dependency-gen.c' %t.d
// PR8974
-// XFAIL: win32
+// REQUIRES: shell
+// "cd %t.dir" requires shell.
// RUN: rm -rf %t.dir
// RUN: mkdir -p %t.dir/a/b
// RUN: echo > %t.dir/a/b/x.h
diff --git a/test/Frontend/dependency-generation-crash.c b/test/Frontend/dependency-generation-crash.c
new file mode 100644
index 000000000000..181bb71f1b09
--- /dev/null
+++ b/test/Frontend/dependency-generation-crash.c
@@ -0,0 +1,4 @@
+// RUN: touch %t
+// RUN: chmod 0 %t
+// %clang -E -dependency-file bla -MT %t -MP -o %t -x c /dev/null
+// rdar://9286457
diff --git a/test/Frontend/diagnostic-name.c b/test/Frontend/diagnostic-name.c
new file mode 100644
index 000000000000..7f43f65d718e
--- /dev/null
+++ b/test/Frontend/diagnostic-name.c
@@ -0,0 +1,5 @@
+// RUN: %clang -Wunused-parameter -fdiagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 1
+// RUN: %clang -Wunused-parameter -fno-diagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 0
+int main(int argc, char *argv[]) {
+ return argc;
+}
diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m
index 1aa26ac77c12..2e11191dca63 100644
--- a/test/Index/TestClassDecl.m
+++ b/test/Index/TestClassDecl.m
@@ -28,6 +28,6 @@ void function(Foo * arg)
// CHECK-scan: [14:1 - 16:2] UnexposedStmt=
// CHECK-load: TestClassDecl.m:10:12: ObjCInterfaceDecl=Foo:10:12 Extent=[10:1 - 11:5]
-// CHECK-load: TestClassDecl.m:13:6: FunctionDecl=function:13:6 (Definition) Extent=[13:6 - 16:2]
+// CHECK-load: TestClassDecl.m:13:6: FunctionDecl=function:13:6 (Definition) Extent=[13:1 - 16:2]
// CHECK-load: TestClassDecl.m:13:21: ParmDecl=arg:13:21 (Definition) Extent=[13:15 - 13:24]
diff --git a/test/Index/annotate-context-sensitive.cpp b/test/Index/annotate-context-sensitive.cpp
new file mode 100644
index 000000000000..307bced59f9b
--- /dev/null
+++ b/test/Index/annotate-context-sensitive.cpp
@@ -0,0 +1,42 @@
+class Base {
+public:
+ virtual void f();
+};
+
+class Derived final : public Base {
+ virtual void f() override final;
+
+ struct final { };
+};
+
+typedef int override;
+struct Base2 {
+ virtual int override();
+};
+
+struct Derived2 : Base2 {
+ ::override override() override;
+};
+
+// RUN: c-index-test -test-annotate-tokens=%s:6:1:19:1 %s | FileCheck -check-prefix=CHECK-OVERRIDE-FINAL %s
+
+// CHECK-OVERRIDE-FINAL: Keyword: "class" [6:1 - 6:6] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Identifier: "Derived" [6:7 - 6:14] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Keyword: "final" [6:15 - 6:20] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Punctuation: ":" [6:21 - 6:22] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Keyword: "public" [6:23 - 6:29] C++ base class specifier=class Base:1:7 [access=public isVirtual=false]
+// CHECK-OVERRIDE-FINAL: Identifier: "Base" [6:30 - 6:34] TypeRef=class Base:1:7
+// CHECK-OVERRIDE-FINAL: Punctuation: "{" [6:35 - 6:36] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Keyword: "virtual" [7:3 - 7:10] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Keyword: "void" [7:11 - 7:15] CXXMethod=f:7:16 [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Identifier: "f" [7:16 - 7:17] CXXMethod=f:7:16 [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Punctuation: "(" [7:17 - 7:18] CXXMethod=f:7:16 [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Punctuation: ")" [7:18 - 7:19] CXXMethod=f:7:16 [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Keyword: "override" [7:20 - 7:28] CXXMethod=f:7:16 [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Keyword: "final" [7:29 - 7:34] CXXMethod=f:7:16 [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Punctuation: ";" [7:34 - 7:35] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Keyword: "struct" [9:3 - 9:9] StructDecl=final:9:10 (Definition)
+// CHECK-OVERRIDE-FINAL: Identifier: "final" [9:10 - 9:15] StructDecl=final:9:10 (Definition)
+// CHECK-OVERRIDE-FINAL: Punctuation: "{" [9:16 - 9:17] StructDecl=final:9:10 (Definition)
+// CHECK-OVERRIDE-FINAL: Punctuation: "}" [9:18 - 9:19] StructDecl=final:9:10 (Definition)
+// CHECK-OVERRIDE-FINAL: Punctuation: ";" [9:19 - 9:20] ClassDecl=Derived:6:7 (Definition)
diff --git a/test/Index/annotate-nested-name-specifier.cpp b/test/Index/annotate-nested-name-specifier.cpp
index 70d84889e996..7c83740f0888 100644
--- a/test/Index/annotate-nested-name-specifier.cpp
+++ b/test/Index/annotate-nested-name-specifier.cpp
@@ -58,7 +58,86 @@ struct X3 {
}
};
-// RUN: c-index-test -test-annotate-tokens=%s:13:1:60:1 %s | FileCheck %s
+namespace outer {
+ namespace inner {
+ void f(int);
+ void f(double);
+ }
+}
+
+template<typename T>
+struct X4 {
+ typedef T type;
+ void g(int);
+ void g(float);
+
+ void h(T t) {
+ ::outer_alias::inner::f(t);
+ ::X4<type>::g(t);
+ this->::X4<type>::g(t);
+ }
+};
+
+typedef int Integer;
+template<>
+struct X4<Integer> {
+ typedef Integer type;
+
+ void g(int);
+ void g(float);
+
+ void h(type t) {
+ ::outer_alias::inner::f(t);
+ ::X4<type>::g(t);
+ this->::X4<type>::g(t);
+ }
+};
+
+
+template<typename T>
+struct X5 {
+ typedef T type;
+ typedef typename outer_alias::inner::vector<type>::iterator iter_type;
+ typedef typename outer_alias::inner::vector<int>::iterator int_ptr_type;
+};
+
+template<typename T>
+struct X6 {
+ typedef T* type;
+ typedef typename outer_alias::inner::vector<type>::template rebind<type> type1;
+ typedef typename outer_alias::inner::vector<type>::template rebind<type>::other type2;
+ typedef class outer_alias::inner::vector<type>::template rebind<type> type3;
+ typedef class outer_alias::inner::vector<type>::template rebind<type>::other type4;
+};
+
+namespace outer {
+ namespace inner {
+ template<typename T, template<class> class TT>
+ struct apply_meta {
+ typedef typename TT<T>::type type;
+ };
+ }
+}
+
+template<typename T, typename U>
+struct X7 {
+ typedef T T_type;
+ typedef U U_type;
+ typedef outer_alias::inner::apply_meta<T_type, U_type::template apply> type;
+};
+
+struct X8 {
+ void f();
+};
+
+struct X9 : X8 {
+ typedef X8 inherited;
+ void f() {
+ inherited::f();
+ }
+};
+
+// RUN: c-index-test -test-annotate-tokens=%s:13:1:137:1 %s | FileCheck %s
// CHECK: Keyword: "using" [14:1 - 14:6] UsingDeclaration=vector[4:12]
// CHECK: Identifier: "outer_alias" [14:7 - 14:18] NamespaceRef=outer_alias:10:11
@@ -67,7 +146,18 @@ struct X3 {
// CHECK: Punctuation: "::" [14:25 - 14:27] UsingDeclaration=vector[4:12]
// CHECK: Identifier: "vector" [14:27 - 14:33] OverloadedDeclRef=vector[4:12]
// CHECK: Punctuation: ";" [14:33 - 14:34]
-// FIXME: Base specifiers, too
+
+// Base specifiers
+// CHECK: Identifier: "outer_alias" [16:19 - 16:30] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [16:30 - 16:32] C++ base class specifier=outer_alias::inner::vector<X>:4:12 [access=public isVirtual=false]
+// CHECK: Identifier: "inner" [16:32 - 16:37] NamespaceRef=inner:2:13
+// CHECK: Punctuation: "::" [16:37 - 16:39] C++ base class specifier=outer_alias::inner::vector<X>:4:12 [access=public isVirtual=false]
+// CHECK: Identifier: "vector" [16:39 - 16:45] TemplateRef=vector:4:12
+// CHECK: Punctuation: "<" [16:45 - 16:46] C++ base class specifier=outer_alias::inner::vector<X>:4:12 [access=public isVirtual=false]
+// CHECK: Identifier: "X" [16:46 - 16:47] TypeRef=struct X:12:8
+// CHECK: Punctuation: ">" [16:47 - 16:48] C++ base class specifier=outer_alias::inner::vector<X>:4:12 [access=public isVirtual=false]
+
+
// CHECK: Keyword: "using" [17:3 - 17:8] UsingDeclaration=iterator[5:18]
// CHECK: Identifier: "outer_alias" [17:9 - 17:20] NamespaceRef=outer_alias:10:11
// CHECK: Punctuation: "::" [17:20 - 17:22] UsingDeclaration=iterator[5:18]
@@ -80,7 +170,38 @@ struct X3 {
// CHECK: Punctuation: "::" [17:38 - 17:40] UsingDeclaration=iterator[5:18]
// CHECK: Identifier: "iterator" [17:40 - 17:48] OverloadedDeclRef=iterator[5:18]
-// FIXME: Check nested-name-specifiers on VarDecl, CXXMethodDecl.
+// CHECK: Keyword: "void" [31:1 - 31:5] CXXMethod=foo:31:33 (Definition)
+// CHECK: Identifier: "outer" [31:6 - 31:11] NamespaceRef=outer:20:11
+// CHECK: Punctuation: "::" [31:11 - 31:13] CXXMethod=foo:31:33 (Definition)
+// CHECK: Identifier: "inner" [31:13 - 31:18] NamespaceRef=inner:21:13
+// CHECK: Punctuation: "::" [31:18 - 31:20] CXXMethod=foo:31:33 (Definition)
+// CHECK: Identifier: "array" [31:20 - 31:25] TemplateRef=array:23:12
+// CHECK: Punctuation: "<" [31:25 - 31:26] CXXMethod=foo:31:33 (Definition)
+// CHECK: Identifier: "T" [31:26 - 31:27] TypeRef=T:30:19
+// CHECK: Punctuation: "," [31:27 - 31:28] CXXMethod=foo:31:33 (Definition)
+// CHECK: Identifier: "N" [31:29 - 31:30] DeclRefExpr=N:30:31
+// CHECK: Punctuation: ">" [31:30 - 31:31] CXXMethod=foo:31:33 (Definition)
+// CHECK: Punctuation: "::" [31:31 - 31:33] CXXMethod=foo:31:33 (Definition)
+// CHECK: Identifier: "foo" [31:33 - 31:36] CXXMethod=foo:31:33 (Definition)
+// CHECK: Punctuation: "(" [31:36 - 31:37] CXXMethod=foo:31:33 (Definition)
+// CHECK: Punctuation: ")" [31:37 - 31:38] CXXMethod=foo:31:33 (Definition)
+
+// CHECK: Keyword: "int" [35:1 - 35:4] VarDecl=max_size:35:32 (Definition)
+// CHECK: Identifier: "outer" [35:5 - 35:10] NamespaceRef=outer:20:11
+// CHECK: Punctuation: "::" [35:10 - 35:12] VarDecl=max_size:35:32 (Definition)
+// CHECK: Identifier: "inner" [35:12 - 35:17] NamespaceRef=inner:21:13
+// CHECK: Punctuation: "::" [35:17 - 35:19] VarDecl=max_size:35:32 (Definition)
+// CHECK: Identifier: "array" [35:19 - 35:24] TemplateRef=array:23:12
+// CHECK: Punctuation: "<" [35:24 - 35:25] VarDecl=max_size:35:32 (Definition)
+// CHECK: Identifier: "T" [35:25 - 35:26] TypeRef=T:34:19
+// CHECK: Punctuation: "," [35:26 - 35:27] VarDecl=max_size:35:32 (Definition)
+// CHECK: Identifier: "N" [35:28 - 35:29] DeclRefExpr=N:34:31
+// CHECK: Punctuation: ">" [35:29 - 35:30] VarDecl=max_size:35:32 (Definition)
+// CHECK: Punctuation: "::" [35:30 - 35:32] VarDecl=max_size:35:32 (Definition)
+// CHECK: Identifier: "max_size" [35:32 - 35:40] VarDecl=max_size:35:32 (Definition)
+// CHECK: Punctuation: "=" [35:41 - 35:42] VarDecl=max_size:35:32 (Definition)
+// CHECK: Literal: "17" [35:43 - 35:45] UnexposedExpr=
+// CHECK: Punctuation: ";" [35:45 - 35:46]
// CHECK: Keyword: "using" [40:3 - 40:8] UsingDeclaration=iterator:40:46
// CHECK: Keyword: "typename" [40:9 - 40:17] UsingDeclaration=iterator:40:46
@@ -138,13 +259,208 @@ struct X3 {
// CHECK: Keyword: "template" [57:30 - 57:38] UnexposedExpr=
// CHECK: Identifier: "vector" [57:39 - 57:45] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [57:45 - 57:46] UnexposedExpr=
-// CHECK: Identifier: "T" [57:46 - 57:47] UnexposedExpr=
+// CHECK: Identifier: "T" [57:46 - 57:47] TypeRef=T:54:19
// CHECK: Punctuation: ">" [57:47 - 57:48] UnexposedExpr=
// CHECK: Punctuation: "::" [57:48 - 57:50] UnexposedExpr=
// CHECK: Punctuation: "~" [57:50 - 57:51] UnexposedExpr=
// CHECK: Identifier: "vector" [57:51 - 57:57] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [57:57 - 57:58] UnexposedExpr=
-// CHECK: Identifier: "T" [57:58 - 57:59] UnexposedExpr=
-// CHECK: Punctuation: ">" [57:59 - 57:60] UnexposedExpr=
+// CHECK: Identifier: "T" [57:58 - 57:59] TypeRef=T:54:19
+// CHECK: Punctuation: ">" [57:59 - 57:60] CallExpr=
// CHECK: Punctuation: "(" [57:60 - 57:61] CallExpr=
// CHECK: Punctuation: ")" [57:61 - 57:62] CallExpr=
+
+// Unresolved member and non-member references
+// CHECK: Punctuation: "::" [75:5 - 75:7] UnexposedExpr=[63:10, 64:10]
+// CHECK: Identifier: "outer_alias" [75:7 - 75:18] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [75:18 - 75:20] UnexposedExpr=[63:10, 64:10]
+// CHECK: Identifier: "inner" [75:20 - 75:25] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [75:25 - 75:27] UnexposedExpr=[63:10, 64:10]
+// CHECK: Identifier: "f" [75:27 - 75:28] OverloadedDeclRef=f[63:10, 64:10]
+// CHECK: Punctuation: "(" [75:28 - 75:29] CallExpr=
+// CHECK: Identifier: "t" [75:29 - 75:30] DeclRefExpr=t:74:12
+// CHECK: Punctuation: ")" [75:30 - 75:31] CallExpr=
+// CHECK: Punctuation: "::" [76:5 - 76:7] UnexposedExpr=[71:8, 72:8]
+// CHECK: Identifier: "X4" [76:7 - 76:9] TemplateRef=X4:69:8
+// CHECK: Punctuation: "<" [76:9 - 76:10] UnexposedExpr=[71:8, 72:8]
+// CHECK: Identifier: "type" [76:10 - 76:14] TypeRef=type:70:13
+// CHECK: Punctuation: ">" [76:14 - 76:15] UnexposedExpr=[71:8, 72:8]
+// CHECK: Punctuation: "::" [76:15 - 76:17] UnexposedExpr=[71:8, 72:8]
+// CHECK: Identifier: "g" [76:17 - 76:18] OverloadedDeclRef=g[71:8, 72:8]
+// CHECK: Punctuation: "(" [76:18 - 76:19] CallExpr=
+// CHECK: Identifier: "t" [76:19 - 76:20] DeclRefExpr=t:74:12
+// CHECK: Punctuation: ")" [76:20 - 76:21] CallExpr=
+// CHECK: Punctuation: ";" [76:21 - 76:22] UnexposedStmt=
+// CHECK: Keyword: "this" [77:5 - 77:9] UnexposedExpr=
+// CHECK: Punctuation: "->" [77:9 - 77:11] UnexposedExpr=
+// CHECK: Punctuation: "::" [77:11 - 77:13] UnexposedExpr=
+// CHECK: Identifier: "X4" [77:13 - 77:15] TemplateRef=X4:69:8
+// CHECK: Punctuation: "<" [77:15 - 77:16] UnexposedExpr=
+// CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=type:70:13
+// CHECK: Punctuation: ">" [77:20 - 77:21] UnexposedExpr=
+// CHECK: Punctuation: "::" [77:21 - 77:23] UnexposedExpr=
+// CHECK: Identifier: "g" [77:23 - 77:24] UnexposedExpr=
+// CHECK: Punctuation: "(" [77:24 - 77:25] CallExpr=
+// CHECK: Identifier: "t" [77:25 - 77:26] DeclRefExpr=t:74:12
+// CHECK: Punctuation: ")" [77:26 - 77:27] CallExpr=
+
+// Resolved member and non-member references
+// CHECK: Punctuation: "::" [90:5 - 90:7] DeclRefExpr=f:63:10
+// CHECK: Identifier: "outer_alias" [90:7 - 90:18] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [90:18 - 90:20] DeclRefExpr=f:63:10
+// CHECK: Identifier: "inner" [90:20 - 90:25] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [90:25 - 90:27] DeclRefExpr=f:63:10
+// CHECK: Identifier: "f" [90:27 - 90:28] DeclRefExpr=f:63:10
+// CHECK: Punctuation: "(" [90:28 - 90:29] CallExpr=f:63:10
+// CHECK: Identifier: "t" [90:29 - 90:30] DeclRefExpr=t:89:15
+// CHECK: Punctuation: ")" [90:30 - 90:31] CallExpr=f:63:10
+// CHECK: Punctuation: ";" [90:31 - 90:32] UnexposedStmt=
+// CHECK: Punctuation: "::" [91:5 - 91:7] MemberRefExpr=g:86:8
+// CHECK: Identifier: "X4" [91:7 - 91:9] TemplateRef=X4:69:8
+// CHECK: Punctuation: "<" [91:9 - 91:10] MemberRefExpr=g:86:8
+// CHECK: Identifier: "type" [91:10 - 91:14] TypeRef=type:84:19
+// CHECK: Punctuation: ">" [91:14 - 91:15] MemberRefExpr=g:86:8
+// CHECK: Punctuation: "::" [91:15 - 91:17] MemberRefExpr=g:86:8
+// CHECK: Identifier: "g" [91:17 - 91:18] MemberRefExpr=g:86:8
+// CHECK: Punctuation: "(" [91:18 - 91:19] CallExpr=g:86:8
+// CHECK: Identifier: "t" [91:19 - 91:20] DeclRefExpr=t:89:15
+// CHECK: Punctuation: ")" [91:20 - 91:21] CallExpr=g:86:8
+// CHECK: Punctuation: ";" [91:21 - 91:22] UnexposedStmt=
+// CHECK: Keyword: "this" [92:5 - 92:9] UnexposedExpr=
+// CHECK: Punctuation: "->" [92:9 - 92:11] MemberRefExpr=g:86:8
+// CHECK: Punctuation: "::" [92:11 - 92:13] MemberRefExpr=g:86:8
+// CHECK: Identifier: "X4" [92:13 - 92:15] TemplateRef=X4:69:8
+// CHECK: Punctuation: "<" [92:15 - 92:16] MemberRefExpr=g:86:8
+// CHECK: Identifier: "type" [92:16 - 92:20] TypeRef=type:84:19
+// CHECK: Punctuation: ">" [92:20 - 92:21] MemberRefExpr=g:86:8
+// CHECK: Punctuation: "::" [92:21 - 92:23] MemberRefExpr=g:86:8
+// CHECK: Identifier: "g" [92:23 - 92:24] MemberRefExpr=g:86:8
+// CHECK: Punctuation: "(" [92:24 - 92:25] CallExpr=g:86:8
+// CHECK: Identifier: "t" [92:25 - 92:26] DeclRefExpr=t:89:15
+// CHECK: Punctuation: ")" [92:26 - 92:27] CallExpr=g:86:8
+
+// Dependent name type
+// CHECK: Keyword: "typedef" [100:3 - 100:10] ClassTemplate=X5:98:8 (Definition)
+// CHECK: Keyword: "typename" [100:11 - 100:19] TypedefDecl=iter_type:100:63 (Definition)
+// CHECK: Identifier: "outer_alias" [100:20 - 100:31] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [100:31 - 100:33] TypedefDecl=iter_type:100:63 (Definition)
+// CHECK: Identifier: "inner" [100:33 - 100:38] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [100:38 - 100:40] TypedefDecl=iter_type:100:63 (Definition)
+// CHECK: Identifier: "vector" [100:40 - 100:46] TemplateRef=vector:4:12
+// CHECK: Punctuation: "<" [100:46 - 100:47] TypedefDecl=iter_type:100:63 (Definition)
+// CHECK: Identifier: "type" [100:47 - 100:51] TypeRef=type:99:13
+// CHECK: Punctuation: ">" [100:51 - 100:52] TypedefDecl=iter_type:100:63 (Definition)
+// CHECK: Punctuation: "::" [100:52 - 100:54] TypedefDecl=iter_type:100:63 (Definition)
+// CHECK: Identifier: "iterator" [100:54 - 100:62] TypedefDecl=iter_type:100:63 (Definition)
+// CHECK: Identifier: "iter_type" [100:63 - 100:72] TypedefDecl=iter_type:100:63 (Definition)
+
+// CHECK: Keyword: "typedef" [101:3 - 101:10] ClassTemplate=X5:98:8 (Definition)
+// CHECK: Keyword: "typename" [101:11 - 101:19] TypedefDecl=int_ptr_type:101:62 (Definition)
+// CHECK: Identifier: "outer_alias" [101:20 - 101:31] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [101:31 - 101:33] TypedefDecl=int_ptr_type:101:62 (Definition)
+// CHECK: Identifier: "inner" [101:33 - 101:38] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [101:38 - 101:40] TypedefDecl=int_ptr_type:101:62 (Definition)
+// CHECK: Identifier: "vector" [101:40 - 101:46] TemplateRef=vector:4:12
+// CHECK: Punctuation: "<" [101:46 - 101:47] TypedefDecl=int_ptr_type:101:62 (Definition)
+// CHECK: Keyword: "int" [101:47 - 101:50] TypedefDecl=int_ptr_type:101:62 (Definition)
+// CHECK: Punctuation: ">" [101:50 - 101:51] TypedefDecl=int_ptr_type:101:62 (Definition)
+// CHECK: Punctuation: "::" [101:51 - 101:53] TypedefDecl=int_ptr_type:101:62 (Definition)
+// CHECK: Identifier: "iterator" [101:53 - 101:61] TypeRef=iterator:5:18
+// CHECK: Identifier: "int_ptr_type" [101:62 - 101:74] TypedefDecl=int_ptr_type:101:62 (Definition)
+
+// Dependent template specialization types
+// CHECK: Keyword: "typename" [107:11 - 107:19] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Identifier: "outer_alias" [107:20 - 107:31] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [107:31 - 107:33] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Identifier: "inner" [107:33 - 107:38] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [107:38 - 107:40] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Identifier: "vector" [107:40 - 107:46] TemplateRef=vector:4:12
+// CHECK: Punctuation: "<" [107:46 - 107:47] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Identifier: "type" [107:47 - 107:51] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [107:51 - 107:52] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Punctuation: "::" [107:52 - 107:54] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Keyword: "template" [107:54 - 107:62] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Identifier: "rebind" [107:63 - 107:69] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Punctuation: "<" [107:69 - 107:70] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Identifier: "type" [107:70 - 107:74] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [107:74 - 107:75] TypedefDecl=type1:107:76 (Definition)
+// CHECK: Identifier: "type1" [107:76 - 107:81] TypedefDecl=type1:107:76 (Definition)
+
+// CHECK: Keyword: "typedef" [108:3 - 108:10] ClassTemplate=X6:105:8 (Definition)
+// CHECK: Keyword: "typename" [108:11 - 108:19] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "outer_alias" [108:20 - 108:31] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [108:31 - 108:33] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "inner" [108:33 - 108:38] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [108:38 - 108:40] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "vector" [108:40 - 108:46] TemplateRef=vector:4:12
+// CHECK: Punctuation: "<" [108:46 - 108:47] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "type" [108:47 - 108:51] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [108:51 - 108:52] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Punctuation: "::" [108:52 - 108:54] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Keyword: "template" [108:54 - 108:62] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "rebind" [108:63 - 108:69] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Punctuation: "<" [108:69 - 108:70] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "type" [108:70 - 108:74] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [108:74 - 108:75] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Punctuation: "::" [108:75 - 108:77] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "other" [108:77 - 108:82] TypedefDecl=type2:108:83 (Definition)
+// CHECK: Identifier: "type2" [108:83 - 108:88] TypedefDecl=type2:108:83 (Definition)
+
+// CHECK: Keyword: "typedef" [109:3 - 109:10] ClassTemplate=X6:105:8 (Definition)
+// CHECK: Keyword: "class" [109:11 - 109:16] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Identifier: "outer_alias" [109:17 - 109:28] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [109:28 - 109:30] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Identifier: "inner" [109:30 - 109:35] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [109:35 - 109:37] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Identifier: "vector" [109:37 - 109:43] TemplateRef=vector:4:12
+// CHECK: Punctuation: "<" [109:43 - 109:44] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Identifier: "type" [109:44 - 109:48] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [109:48 - 109:49] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Punctuation: "::" [109:49 - 109:51] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Keyword: "template" [109:51 - 109:59] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Identifier: "rebind" [109:60 - 109:66] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Punctuation: "<" [109:66 - 109:67] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Identifier: "type" [109:67 - 109:71] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [109:71 - 109:72] TypedefDecl=type3:109:73 (Definition)
+// CHECK: Identifier: "type3" [109:73 - 109:78] TypedefDecl=type3:109:73 (Definition)
+
+// CHECK: Keyword: "class" [110:11 - 110:16] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "outer_alias" [110:17 - 110:28] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [110:28 - 110:30] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "inner" [110:30 - 110:35] NamespaceRef=inner:62:13
+// CHECK: Punctuation: "::" [110:35 - 110:37] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "vector" [110:37 - 110:43] TemplateRef=vector:4:12
+// CHECK: Punctuation: "<" [110:43 - 110:44] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "type" [110:44 - 110:48] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [110:48 - 110:49] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Punctuation: "::" [110:49 - 110:51] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Keyword: "template" [110:51 - 110:59] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "rebind" [110:60 - 110:66] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Punctuation: "<" [110:66 - 110:67] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "type" [110:67 - 110:71] TypeRef=type:106:14
+// CHECK: Punctuation: ">" [110:71 - 110:72] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Punctuation: "::" [110:72 - 110:74] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "other" [110:74 - 110:79] TypedefDecl=type4:110:80 (Definition)
+// CHECK: Identifier: "type4" [110:80 - 110:85] TypedefDecl=type4:110:80 (Definition)
+
+// Template template arguments
+// CHECK: Keyword: "typedef" [126:3 - 126:10] ClassTemplate=X7:123:8 (Definition)
+// CHECK: Identifier: "outer_alias" [126:11 - 126:22] NamespaceRef=outer_alias:10:11
+// CHECK: Punctuation: "::" [126:22 - 126:24] TypedefDecl=type:126:74 (Definition)
+// CHECK: Identifier: "inner" [126:24 - 126:29] NamespaceRef=inner:114:13
+// CHECK: Punctuation: "::" [126:29 - 126:31] TypedefDecl=type:126:74 (Definition)
+// CHECK: Identifier: "apply_meta" [126:31 - 126:41] TemplateRef=apply_meta:116:12
+// CHECK: Punctuation: "<" [126:41 - 126:42] TypedefDecl=type:126:74 (Definition)
+// CHECK: Identifier: "T_type" [126:42 - 126:48] TypeRef=T_type:124:13
+// CHECK: Punctuation: "," [126:48 - 126:49] TypedefDecl=type:126:74 (Definition)
+// CHECK: Identifier: "U_type" [126:50 - 126:56] TypeRef=U_type:125:13
+// CHECK: Punctuation: "::" [126:56 - 126:58] TypedefDecl=type:126:74 (Definition)
+// CHECK: Keyword: "template" [126:58 - 126:66] TypedefDecl=type:126:74 (Definition)
+// CHECK: Identifier: "apply" [126:67 - 126:72] TypedefDecl=type:126:74 (Definition)
+// CHECK: Punctuation: ">" [126:72 - 126:73] TypedefDecl=type:126:74 (Definition)
+// CHECK: Identifier: "type" [126:74 - 126:78] TypedefDecl=type:126:74 (Definition)
+
+// Member access expressions
+// CHECK: Identifier: "inherited" [136:5 - 136:14] TypeRef=inherited:134:14
+// CHECK: Punctuation: "::" [136:14 - 136:16] MemberRefExpr=f:130:8
+// CHECK: Identifier: "f" [136:16 - 136:17] MemberRefExpr=f:130:8
diff --git a/test/Index/annotate-tokens.c b/test/Index/annotate-tokens.c
index d692bd3bbac6..162a224ed684 100644
--- a/test/Index/annotate-tokens.c
+++ b/test/Index/annotate-tokens.c
@@ -8,9 +8,9 @@ void f(void *ptr) {
void *xx = ptr ? : &x;
const char * hello = "Hello";
}
-
+enum Color { Red, Green, Blue };
typedef int Int;
-void g(int i, ...) {
+enum Color g(int i, ...) {
__builtin_va_list va;
(void)__builtin_va_arg(va, Int);
(void)__builtin_types_compatible_p(Int, Int);
@@ -19,9 +19,21 @@ void g(int i, ...) {
do {
x.a++;
} while (x.a < 10);
+
+ enum Color c;
+ switch (c) {
+ case Red:
+ return Green;
+
+ case Green:
+ return Blue;
+
+ case Blue:
+ return Red;
+ }
}
-// RUN: c-index-test -test-annotate-tokens=%s:4:1:22:1 %s | FileCheck %s
+// RUN: c-index-test -test-annotate-tokens=%s:4:1:34:1 %s | FileCheck %s
// CHECK: Identifier: "T" [4:3 - 4:4] TypeRef=T:1:13
// CHECK: Punctuation: "*" [4:4 - 4:5] VarDecl=t_ptr:4:6 (Definition)
// CHECK: Identifier: "t_ptr" [4:6 - 4:11] VarDecl=t_ptr:4:6 (Definition)
@@ -41,7 +53,7 @@ void g(int i, ...) {
// CHECK: Punctuation: ")" [5:17 - 5:18] UnexposedExpr=
// CHECK: Punctuation: ";" [5:18 - 5:19] UnexposedStmt=
// CHECK: Comment: "/* A comment */" [6:3 - 6:18] UnexposedStmt=
-// CHECK: Keyword: "struct" [7:3 - 7:9] UnexposedStmt=
+// CHECK: Keyword: "struct" [7:3 - 7:9] VarDecl=x:7:12 (Definition)
// CHECK: Identifier: "X" [7:10 - 7:11] TypeRef=struct X:2:8
// CHECK: Identifier: "x" [7:12 - 7:13] VarDecl=x:7:12 (Definition)
// CHECK: Punctuation: "=" [7:14 - 7:15] VarDecl=x:7:12 (Definition)
@@ -79,7 +91,7 @@ void g(int i, ...) {
// CHECK: Identifier: "Int" [16:38 - 16:41] TypeRef=Int:12:13
// CHECK: Punctuation: "," [16:41 - 16:42] UnexposedExpr=
// CHECK: Identifier: "Int" [16:43 - 16:46] TypeRef=Int:12:13
-// CHECK: Keyword: "struct" [18:3 - 18:9] UnexposedStmt=
+// CHECK: Keyword: "struct" [18:3 - 18:9] VarDecl=x:18:12 (Definition)
// CHECK: Identifier: "X" [18:10 - 18:11] TypeRef=struct X:2:8
// CHECK: Identifier: "x" [18:12 - 18:13] VarDecl=x:18:12 (Definition)
// CHECK: Keyword: "do" [19:3 - 19:5] UnexposedStmt=
@@ -95,5 +107,33 @@ void g(int i, ...) {
// CHECK: Punctuation: "." [21:13 - 21:14] MemberRefExpr=a:2:16
// CHECK: Identifier: "a" [21:14 - 21:15] MemberRefExpr=a:2:16
+// CHECK: Keyword: "enum" [23:3 - 23:7] VarDecl=c:23:14 (Definition)
+// CHECK: Identifier: "Color" [23:8 - 23:13] TypeRef=enum Color:11:6
+// CHECK: Identifier: "c" [23:14 - 23:15] VarDecl=c:23:14 (Definition)
+// CHECK: Punctuation: ";" [23:15 - 23:16] UnexposedStmt=
+// CHECK: Keyword: "switch" [24:3 - 24:9] UnexposedStmt=
+// CHECK: Punctuation: "(" [24:10 - 24:11] UnexposedStmt=
+// CHECK: Identifier: "c" [24:11 - 24:12] DeclRefExpr=c:23:14
+// CHECK: Punctuation: ")" [24:12 - 24:13] UnexposedStmt=
+// CHECK: Punctuation: "{" [24:14 - 24:15] UnexposedStmt=
+// CHECK: Keyword: "case" [25:3 - 25:7] UnexposedStmt=
+// CHECK: Identifier: "Red" [25:8 - 25:11] DeclRefExpr=Red:11:14
+// CHECK: Punctuation: ":" [25:11 - 25:12] UnexposedStmt=
+// CHECK: Keyword: "return" [26:5 - 26:11] UnexposedStmt=
+// CHECK: Identifier: "Green" [26:12 - 26:17] DeclRefExpr=Green:11:19
+// CHECK: Punctuation: ";" [26:17 - 26:18] UnexposedStmt=
+// CHECK: Keyword: "case" [28:3 - 28:7] UnexposedStmt=
+// CHECK: Identifier: "Green" [28:8 - 28:13] DeclRefExpr=Green:11:19
+// CHECK: Punctuation: ":" [28:13 - 28:14] UnexposedStmt=
+// CHECK: Keyword: "return" [29:5 - 29:11] UnexposedStmt=
+// CHECK: Identifier: "Blue" [29:12 - 29:16] DeclRefExpr=Blue:11:26
+// CHECK: Punctuation: ";" [29:16 - 29:17] UnexposedStmt=
+// CHECK: Keyword: "case" [31:3 - 31:7] UnexposedStmt=
+// CHECK: Identifier: "Blue" [31:8 - 31:12] DeclRefExpr=Blue:11:26
+// CHECK: Punctuation: ":" [31:12 - 31:13] UnexposedStmt=
+// CHECK: Keyword: "return" [32:5 - 32:11] UnexposedStmt=
+// CHECK: Identifier: "Red" [32:12 - 32:15] DeclRefExpr=Red:11:14
+// CHECK: Punctuation: ";" [32:15 - 32:16] UnexposedStmt=
+
// RUN: c-index-test -test-annotate-tokens=%s:4:1:165:32 %s | FileCheck %s
// RUN: c-index-test -test-annotate-tokens=%s:4:1:165:38 %s | FileCheck %s
diff --git a/test/Index/annotate-tokens.cpp b/test/Index/annotate-tokens.cpp
index 3138babf0aaf..ccc9e9602843 100644
--- a/test/Index/annotate-tokens.cpp
+++ b/test/Index/annotate-tokens.cpp
@@ -4,7 +4,22 @@ void test(bonk X) {
__is_base_of(bonk, bonk);
}
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:6:5 %s | FileCheck %s
+struct X {
+ X operator++();
+ X operator++(int);
+};
+void test2(X x) {
+ ++(x);
+ (x)++;
+}
+
+struct S1 { void f(); };
+struct S2 { S1 *operator->(); };
+void test3(S2 s2) {
+ s2->f();
+}
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:20:1 %s | FileCheck %s
// CHECK: Keyword: "struct" [1:1 - 1:7] StructDecl=bonk:1:8 (Definition)
// CHECK: Identifier: "bonk" [1:8 - 1:12] StructDecl=bonk:1:8 (Definition)
// CHECK: Punctuation: "{" [1:13 - 1:14] StructDecl=bonk:1:8 (Definition)
@@ -29,3 +44,75 @@ void test(bonk X) {
// CHECK: Punctuation: ")" [4:28 - 4:29] UnexposedExpr=
// CHECK: Punctuation: ";" [4:29 - 4:30] UnexposedStmt=
// CHECK: Punctuation: "}" [5:1 - 5:2] UnexposedStmt=
+// CHECK: Keyword: "struct" [7:1 - 7:7] StructDecl=X:7:8 (Definition)
+// CHECK: Identifier: "X" [7:8 - 7:9] StructDecl=X:7:8 (Definition)
+// CHECK: Punctuation: "{" [7:10 - 7:11] StructDecl=X:7:8 (Definition)
+// CHECK: Identifier: "X" [8:3 - 8:4] TypeRef=struct X:7:8
+// CHECK: Keyword: "operator" [8:5 - 8:13] CXXMethod=operator++:8:5
+// CHECK: Punctuation: "++" [8:13 - 8:15] CXXMethod=operator++:8:5
+// CHECK: Punctuation: "(" [8:15 - 8:16] CXXMethod=operator++:8:5
+// CHECK: Punctuation: ")" [8:16 - 8:17] CXXMethod=operator++:8:5
+// CHECK: Punctuation: ";" [8:17 - 8:18] StructDecl=X:7:8 (Definition)
+// CHECK: Identifier: "X" [9:3 - 9:4] TypeRef=struct X:7:8
+// CHECK: Keyword: "operator" [9:5 - 9:13] CXXMethod=operator++:9:5
+// CHECK: Punctuation: "++" [9:13 - 9:15] CXXMethod=operator++:9:5
+// CHECK: Punctuation: "(" [9:15 - 9:16] CXXMethod=operator++:9:5
+// CHECK: Keyword: "int" [9:16 - 9:19] ParmDecl=:9:19 (Definition)
+// CHECK: Punctuation: ")" [9:19 - 9:20] ParmDecl=:9:19 (Definition)
+// CHECK: Punctuation: ";" [9:20 - 9:21] StructDecl=X:7:8 (Definition)
+// CHECK: Punctuation: "}" [10:1 - 10:2] StructDecl=X:7:8 (Definition)
+// CHECK: Punctuation: ";" [10:2 - 10:3]
+// CHECK: Keyword: "void" [11:1 - 11:5] FunctionDecl=test2:11:6 (Definition)
+// CHECK: Identifier: "test2" [11:6 - 11:11] FunctionDecl=test2:11:6 (Definition)
+// CHECK: Punctuation: "(" [11:11 - 11:12] FunctionDecl=test2:11:6 (Definition)
+// CHECK: Identifier: "X" [11:12 - 11:13] TypeRef=struct X:7:8
+// CHECK: Identifier: "x" [11:14 - 11:15] ParmDecl=x:11:14 (Definition)
+// CHECK: Punctuation: ")" [11:15 - 11:16] FunctionDecl=test2:11:6 (Definition)
+// CHECK: Punctuation: "{" [11:17 - 11:18] UnexposedStmt=
+// CHECK: Punctuation: "++" [12:3 - 12:5] CallExpr=operator++:8:5
+// CHECK: Punctuation: "(" [12:5 - 12:6] UnexposedExpr=
+// CHECK: Identifier: "x" [12:6 - 12:7] DeclRefExpr=x:11:14
+// CHECK: Punctuation: ")" [12:7 - 12:8] UnexposedExpr=
+// CHECK: Punctuation: ";" [12:8 - 12:9] UnexposedStmt=
+// CHECK: Punctuation: "(" [13:3 - 13:4] UnexposedExpr=
+// CHECK: Identifier: "x" [13:4 - 13:5] DeclRefExpr=x:11:14
+// CHECK: Punctuation: ")" [13:5 - 13:6] UnexposedExpr=
+// CHECK: Punctuation: "++" [13:6 - 13:8] CallExpr=operator++:9:5
+// CHECK: Punctuation: ";" [13:8 - 13:9] UnexposedStmt=
+// CHECK: Punctuation: "}" [14:1 - 14:2] UnexposedStmt=
+// CHECK: Keyword: "struct" [16:1 - 16:7] StructDecl=S1:16:8 (Definition)
+// CHECK: Identifier: "S1" [16:8 - 16:10] StructDecl=S1:16:8 (Definition)
+// CHECK: Punctuation: "{" [16:11 - 16:12] StructDecl=S1:16:8 (Definition)
+// CHECK: Keyword: "void" [16:13 - 16:17] CXXMethod=f:16:18
+// CHECK: Identifier: "f" [16:18 - 16:19] CXXMethod=f:16:18
+// CHECK: Punctuation: "(" [16:19 - 16:20] CXXMethod=f:16:18
+// CHECK: Punctuation: ")" [16:20 - 16:21] CXXMethod=f:16:18
+// CHECK: Punctuation: ";" [16:21 - 16:22] StructDecl=S1:16:8 (Definition)
+// CHECK: Punctuation: "}" [16:23 - 16:24] StructDecl=S1:16:8 (Definition)
+// CHECK: Punctuation: ";" [16:24 - 16:25]
+// CHECK: Keyword: "struct" [17:1 - 17:7] StructDecl=S2:17:8 (Definition)
+// CHECK: Identifier: "S2" [17:8 - 17:10] StructDecl=S2:17:8 (Definition)
+// CHECK: Punctuation: "{" [17:11 - 17:12] StructDecl=S2:17:8 (Definition)
+// CHECK: Identifier: "S1" [17:13 - 17:15] TypeRef=struct S1:16:8
+// CHECK: Punctuation: "*" [17:16 - 17:17] CXXMethod=operator->:17:17
+// CHECK: Keyword: "operator" [17:17 - 17:25] CXXMethod=operator->:17:17
+// CHECK: Punctuation: "->" [17:25 - 17:27] CXXMethod=operator->:17:17
+// CHECK: Punctuation: "(" [17:27 - 17:28] CXXMethod=operator->:17:17
+// CHECK: Punctuation: ")" [17:28 - 17:29] CXXMethod=operator->:17:17
+// CHECK: Punctuation: ";" [17:29 - 17:30] StructDecl=S2:17:8 (Definition)
+// CHECK: Punctuation: "}" [17:31 - 17:32] StructDecl=S2:17:8 (Definition)
+// CHECK: Punctuation: ";" [17:32 - 17:33]
+// CHECK: Keyword: "void" [18:1 - 18:5] FunctionDecl=test3:18:6 (Definition)
+// CHECK: Identifier: "test3" [18:6 - 18:11] FunctionDecl=test3:18:6 (Definition)
+// CHECK: Punctuation: "(" [18:11 - 18:12] FunctionDecl=test3:18:6 (Definition)
+// CHECK: Identifier: "S2" [18:12 - 18:14] TypeRef=struct S2:17:8
+// CHECK: Identifier: "s2" [18:15 - 18:17] ParmDecl=s2:18:15 (Definition)
+// CHECK: Punctuation: ")" [18:17 - 18:18] FunctionDecl=test3:18:6 (Definition)
+// CHECK: Punctuation: "{" [18:19 - 18:20] UnexposedStmt=
+// CHECK: Identifier: "s2" [19:3 - 19:5] DeclRefExpr=s2:18:15
+// CHECK: Punctuation: "->" [19:5 - 19:7] MemberRefExpr=f:16:18
+// CHECK: Identifier: "f" [19:7 - 19:8] MemberRefExpr=f:16:18
+// CHECK: Punctuation: "(" [19:8 - 19:9] CallExpr=f:16:18
+// CHECK: Punctuation: ")" [19:9 - 19:10] CallExpr=f:16:18
+// CHECK: Punctuation: ";" [19:10 - 19:11] UnexposedStmt=
+// CHECK: Punctuation: "}" [20:1 - 20:2] UnexposedStmt=
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index f4d47ac4ae55..f977e5c3dfe8 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -30,12 +30,12 @@ typedef int * barType;
// Since there are no source ranges for attributes, we currently don't
// annotate them.
@interface IBActionTests
-- (IBAction) actionMethod:(id)arg;
+- (IBAction) actionMethod:(in id)arg;
- (void)foo:(int)x;
@end
extern int ibaction_test(void);
@implementation IBActionTests
-- (IBAction) actionMethod:(id)arg
+- (IBAction) actionMethod:(in id)arg
{
ibaction_test();
[self foo:0];
@@ -231,10 +231,11 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "actionMethod" [33:14 - 33:26] ObjCInstanceMethodDecl=actionMethod::33:1
// CHECK: Punctuation: ":" [33:26 - 33:27] ObjCInstanceMethodDecl=actionMethod::33:1
// CHECK: Punctuation: "(" [33:27 - 33:28] ObjCInstanceMethodDecl=actionMethod::33:1
-// CHECK: Identifier: "id" [33:28 - 33:30] TypeRef=id:0:0
-// CHECK: Punctuation: ")" [33:30 - 33:31] ParmDecl=arg:33:31 (Definition)
-// CHECK: Identifier: "arg" [33:31 - 33:34] ParmDecl=arg:33:31 (Definition)
-// CHECK: Punctuation: ";" [33:34 - 33:35] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Keyword: "in" [33:28 - 33:30] ObjCInstanceMethodDecl=actionMethod::33:1
+// CHECK: Identifier: "id" [33:31 - 33:33] TypeRef=id:0:0
+// CHECK: Punctuation: ")" [33:33 - 33:34] ParmDecl=arg:33:34 (Definition)
+// CHECK: Identifier: "arg" [33:34 - 33:37] ParmDecl=arg:33:34 (Definition)
+// CHECK: Punctuation: ";" [33:37 - 33:38] ObjCInstanceMethodDecl=actionMethod::33:1
// CHECK: Punctuation: "-" [34:1 - 34:2] ObjCInstanceMethodDecl=foo::34:1
// CHECK: Punctuation: "(" [34:3 - 34:4] ObjCInstanceMethodDecl=foo::34:1
// CHECK: Keyword: "void" [34:4 - 34:8] ObjCInstanceMethodDecl=foo::34:1
@@ -264,10 +265,10 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: ")" [38:12 - 38:13] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
// CHECK: Identifier: "actionMethod" [38:14 - 38:26] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
// CHECK: Punctuation: ":" [38:26 - 38:27] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
-// CHECK: Punctuation: "(" [38:27 - 38:28] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
-// CHECK: Identifier: "id" [38:28 - 38:30] TypeRef=id:0:0
-// CHECK: Punctuation: ")" [38:30 - 38:31] ParmDecl=arg:38:31 (Definition)
-// CHECK: Identifier: "arg" [38:31 - 38:34] ParmDecl=arg:38:31 (Definition)
+// CHECK: Keyword: "in" [38:28 - 38:30] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) [Overrides @33:1]
+// CHECK: Identifier: "id" [38:31 - 38:33] TypeRef=id:0:0
+// CHECK: Punctuation: ")" [38:33 - 38:34] ParmDecl=arg:38:34 (Definition)
+// CHECK: Identifier: "arg" [38:34 - 38:37] ParmDecl=arg:38:34 (Definition)
// CHECK: Punctuation: "{" [39:1 - 39:2] UnexposedStmt=
// CHECK: Identifier: "ibaction_test" [40:5 - 40:18] DeclRefExpr=ibaction_test:36:12
// CHECK: Punctuation: "(" [40:18 - 40:19] CallExpr=ibaction_test:36:12
@@ -484,16 +485,16 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "@" [110:1 - 110:2] ObjCPropertyDecl=foo:110:33
// CHECK: Keyword: "property" [110:2 - 110:10] ObjCPropertyDecl=foo:110:33
// CHECK: Punctuation: "(" [110:11 - 110:12] ObjCPropertyDecl=foo:110:33
-// CHECK: Identifier: "readonly" [110:12 - 110:20] ObjCPropertyDecl=foo:110:33
+// CHECK: Keyword: "readonly" [110:12 - 110:20] ObjCPropertyDecl=foo:110:33
// CHECK: Punctuation: "," [110:20 - 110:21] ObjCPropertyDecl=foo:110:33
-// CHECK: Identifier: "copy" [110:22 - 110:26] ObjCPropertyDecl=foo:110:33
+// CHECK: Keyword: "copy" [110:22 - 110:26] ObjCPropertyDecl=foo:110:33
// CHECK: Punctuation: ")" [110:26 - 110:27] ObjCPropertyDecl=foo:110:33
// CHECK: Identifier: "Foo" [110:28 - 110:31] ObjCClassRef=Foo:1:12
// CHECK: Punctuation: "*" [110:32 - 110:33] ObjCPropertyDecl=foo:110:33
// CHECK: Identifier: "foo" [110:33 - 110:36] ObjCPropertyDecl=foo:110:33
// CHECK: Keyword: "property" [111:2 - 111:10] ObjCPropertyDecl=foo2:111:27
// CHECK: Punctuation: "(" [111:11 - 111:12] ObjCPropertyDecl=foo2:111:27
-// CHECK: Identifier: "readonly" [111:12 - 111:20] ObjCPropertyDecl=foo2:111:27
+// CHECK: Keyword: "readonly" [111:12 - 111:20] ObjCPropertyDecl=foo2:111:27
// CHECK: Punctuation: ")" [111:20 - 111:21] ObjCPropertyDecl=foo2:111:27
// CHECK: Identifier: "Foo" [111:22 - 111:25] ObjCClassRef=Foo:1:12
// CHECK: Punctuation: "*" [111:26 - 111:27] ObjCPropertyDecl=foo2:111:27
@@ -539,9 +540,9 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [136:1 - 136:2] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Keyword: "property" [136:2 - 136:10] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: "(" [136:11 - 136:12] ObjCPropertyDecl=blah:136:38
-// CHECK-PROP-AFTER-METHOD: Identifier: "readonly" [136:12 - 136:20] ObjCPropertyDecl=blah:136:38
+// CHECK-PROP-AFTER-METHOD: Keyword: "readonly" [136:12 - 136:20] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: "," [136:20 - 136:21] ObjCPropertyDecl=blah:136:38
-// CHECK-PROP-AFTER-METHOD: Identifier: "nonatomic" [136:22 - 136:31] ObjCPropertyDecl=blah:136:38
+// CHECK-PROP-AFTER-METHOD: Keyword: "nonatomic" [136:22 - 136:31] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: ")" [136:31 - 136:32] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Identifier: "Foo" [136:33 - 136:36] ObjCClassRef=Foo:1:12
// CHECK-PROP-AFTER-METHOD: Punctuation: "*" [136:37 - 136:38] ObjCPropertyDecl=blah:136:38
diff --git a/test/Index/blocks.c b/test/Index/blocks.c
index a8965d2aa670..633e171ffa37 100644
--- a/test/Index/blocks.c
+++ b/test/Index/blocks.c
@@ -9,17 +9,17 @@ void test() {
^ int_t(struct foo *foo) { return (int_t) foo->x + i; }(&_foo);
}
-// CHECK: blocks.c:6:6: FunctionDecl=test:6:6 (Definition) Extent=[6:6 - 10:2]
+// CHECK: blocks.c:6:6: FunctionDecl=test:6:6 (Definition) Extent=[6:1 - 10:2]
// CHECK: blocks.c:6:13: UnexposedStmt= Extent=[6:13 - 10:2]
// CHECK: blocks.c:7:3: UnexposedStmt= Extent=[7:3 - 7:26]
-// CHECK: blocks.c:7:21: VarDecl=_foo:7:21 (Definition) Extent=[7:17 - 7:25]
+// CHECK: blocks.c:7:21: VarDecl=_foo:7:21 (Definition) Extent=[7:3 - 7:25]
// CHECK: blocks.c:7:17: TypeRef=struct foo:4:8 Extent=[7:17 - 7:20]
-// CHECK: blocks.c:8:11: VarDecl=i:8:11 (Definition) Extent=[8:11 - 8:16]
+// CHECK: blocks.c:8:11: VarDecl=i:8:11 (Definition) Extent=[8:3 - 8:16]
// CHECK: blocks.c:8:15: UnexposedExpr= Extent=[8:15 - 8:16]
// CHECK: blocks.c:9:3: CallExpr= Extent=[9:3 - 9:65]
// CHECK: blocks.c:9:3: UnexposedExpr= Extent=[9:3 - 9:58]
// CHECK: blocks.c:9:5: TypeRef=int_t:3:13 Extent=[9:5 - 9:10]
-// CHECK: blocks.c:9:23: ParmDecl=foo:9:23 (Definition) Extent=[9:18 - 9:26]
+// CHECK: blocks.c:9:23: ParmDecl=foo:9:23 (Definition) Extent=[9:11 - 9:26]
// CHECK: blocks.c:9:18: TypeRef=struct foo:4:8 Extent=[9:18 - 9:21]
// CHECK: blocks.c:9:28: UnexposedStmt= Extent=[9:28 - 9:58]
// CHECK: blocks.c:9:30: UnexposedStmt= Extent=[9:30 - 9:55]
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index f34593f3e85e..98a41d837fdc 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -71,7 +71,7 @@ struct X0;
struct X0 {};
// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5]
-// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:32 - 6:40]
+// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:3 - 6:40]
// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
// CHECK: c-index-api-loadTU-test.m:6:29: TypeRef=id:0:0 Extent=[6:29 - 6:31]
// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=myMessage::8:1 Extent=[8:1 - 8:54]
@@ -95,14 +95,14 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:33:12: ObjCInterfaceDecl=Baz:33:12 Extent=[33:1 - 40:5]
// CHECK: c-index-api-loadTU-test.m:33:18: ObjCSuperClassRef=Bar:14:12 Extent=[33:18 - 33:21]
// CHECK: c-index-api-loadTU-test.m:33:23: ObjCProtocolRef=SubP:29:1 Extent=[33:23 - 33:27]
-// CHECK: c-index-api-loadTU-test.m:35:9: ObjCIvarDecl=_anIVar:35:9 (Definition) Extent=[35:9 - 35:16]
+// CHECK: c-index-api-loadTU-test.m:35:9: ObjCIvarDecl=_anIVar:35:9 (Definition) Extent=[35:5 - 35:16]
// CHECK: c-index-api-loadTU-test.m:38:1: ObjCInstanceMethodDecl=bazMethod:38:1 Extent=[38:1 - 38:21]
// CHECK: c-index-api-loadTU-test.m:38:4: ObjCClassRef=Foo:4:12 Extent=[38:4 - 38:7]
// CHECK: c-index-api-loadTU-test.m:42:1: EnumDecl=:42:1 (Definition) Extent=[42:1 - 44:2]
// CHECK: c-index-api-loadTU-test.m:43:3: EnumConstantDecl=someEnum:43:3 (Definition) Extent=[43:3 - 43:11]
-// CHECK: c-index-api-loadTU-test.m:46:5: FunctionDecl=main:46:5 (Definition) Extent=[46:5 - 55:2]
+// CHECK: c-index-api-loadTU-test.m:46:5: FunctionDecl=main:46:5 (Definition) Extent=[46:1 - 55:2]
// CHECK: c-index-api-loadTU-test.m:46:15: ParmDecl=argc:46:15 (Definition) Extent=[46:11 - 46:19]
-// CHECK: c-index-api-loadTU-test.m:46:34: ParmDecl=argv:46:34 (Definition) Extent=[46:27 - 46:38]
+// CHECK: c-index-api-loadTU-test.m:46:34: ParmDecl=argv:46:34 (Definition) Extent=[46:21 - 46:40]
// CHECK: c-index-api-loadTU-test.m:47:8: VarDecl=bee:47:8 (Definition) Extent=[47:2 - 47:11]
// CHECK: c-index-api-loadTU-test.m:47:2: ObjCClassRef=Baz:33:12 Extent=[47:2 - 47:5]
// CHECK: c-index-api-loadTU-test.m:48:5: VarDecl=a:48:5 (Definition) Extent=[48:2 - 48:18]
@@ -135,9 +135,9 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:54:18: UnexposedExpr=bee:47:8 Extent=[54:18 - 54:36]
// CHECK: c-index-api-loadTU-test.m:54:33: DeclRefExpr=bee:47:8 Extent=[54:33 - 54:36]
// CHECK: c-index-api-loadTU-test.m:62:12: ObjCInterfaceDecl=TestAttributes:62:12 Extent=[62:1 - 67:5]
-// CHECK: c-index-api-loadTU-test.m:63:19: ObjCIvarDecl=anOutlet:63:19 (Definition) Extent=[63:19 - 63:27]
+// CHECK: c-index-api-loadTU-test.m:63:19: ObjCIvarDecl=anOutlet:63:19 (Definition) Extent=[58:18 - 63:27]
// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
-// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[64:29 - 64:47]
+// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[59:39 - 64:47]
// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)= [IBOutletCollection=ObjCObjectPointer]
// CHECK: c-index-api-loadTU-test.m:64:26: TypeRef=id:0:0 Extent=[64:26 - 64:28]
// CHECK: c-index-api-loadTU-test.m:66:1: ObjCInstanceMethodDecl=actionMethod::66:1 Extent=[66:1 - 66:35]
@@ -145,7 +145,7 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:66:31: ParmDecl=arg:66:31 (Definition) Extent=[66:28 - 66:34]
// CHECK: c-index-api-loadTU-test.m:66:28: TypeRef=id:0:0 Extent=[66:28 - 66:30]
// CHECK: c-index-api-loadTU-test.m:69:16: StructDecl=X0:69:16 Extent=[69:9 - 69:18]
-// CHECK: c-index-api-loadTU-test.m:69:19: TypedefDecl=X1:69:19 (Definition) Extent=[69:19 - 69:21]
+// CHECK: c-index-api-loadTU-test.m:69:19: TypedefDecl=X1:69:19 (Definition) Extent=[69:1 - 69:21]
// CHECK: c-index-api-loadTU-test.m:69:16: TypeRef=struct X0:71:8 Extent=[69:16 - 69:18]
// CHECK: c-index-api-loadTU-test.m:70:8: StructDecl=X0:70:8 Extent=[70:1 - 70:10]
// CHECK: c-index-api-loadTU-test.m:71:8: StructDecl=X0:71:8 (Definition) Extent=[71:1 - 71:14]
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index 91482eb798a4..c2ff6963c9ff 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -108,9 +108,9 @@ void f() {
// CHECK: [42:2 - 44:1] Invalid Cursor => NoDeclFound
// CHECK: [44:1 - 44:11] FunctionDecl=main:44:5 (Definition)
// CHECK: [44:11 - 44:19] ParmDecl=argc:44:15 (Definition)
-// CHECK: [44:19 - 44:27] FunctionDecl=main:44:5 (Definition)
-// CHECK: [44:27 - 44:38] ParmDecl=argv:44:34 (Definition)
-// CHECK: [44:38 - 44:42] FunctionDecl=main:44:5 (Definition)
+// CHECK: [44:19 - 44:21] FunctionDecl=main:44:5 (Definition)
+// CHECK: [44:21 - 44:40] ParmDecl=argv:44:34 (Definition)
+// CHECK: [44:40 - 44:42] FunctionDecl=main:44:5 (Definition)
// CHECK: [44:42 - 45:2] UnexposedStmt=
// CHECK: [45:2 - 45:5] ObjCClassRef=Baz:31:12
// CHECK: [45:5 - 45:11] VarDecl=bee:45:8 (Definition)
diff --git a/test/Index/cindex-on-invalid.m b/test/Index/cindex-on-invalid.m
index d2d952d8b19e..6eff24baf808 100644
--- a/test/Index/cindex-on-invalid.m
+++ b/test/Index/cindex-on-invalid.m
@@ -1,6 +1,21 @@
// RUN: c-index-test -test-load-source local %s 2>&1 | FileCheck %s
+// <rdar://problem/9123493>
+void test() {
+ goto exit;
+}
+
int foo;
+
+#define NO 0
+
+void f(int y) {
+ if (y = NO);
+}
+
int
-// CHECK: cindex-on-invalid.m:6:70: error: expected identifier or '(' \ No newline at end of file
+// CHECK: cindex-on-invalid.m:5:8: error: use of undeclared label 'exit'
+// CHECK: cindex-on-invalid.m:13:9:{13:7-13:13}
+// CHECK: cindex-on-invalid.m:21:1: error: expected identifier or '('
+
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index 0658d53c651b..0ea33850560e 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -175,6 +175,12 @@ void test_missing_open_more() {
A *a = A class_method3];
}
+void test_block_invoke(A *(^block1)(int),
+ int (^block2)(int),
+ id (^block3)(int)) {
+ [block1(5) init];
+}
+
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText categoryClassMethod}
// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)}
@@ -285,6 +291,12 @@ void test_missing_open_more() {
// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method3} (35)
// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method4} (35)
+// RUN: c-index-test -code-completion-at=%s:181:4 %s | FileCheck -check-prefix=CHECK-BLOCK-RECEIVER %s
+// CHECK-BLOCK-RECEIVER: ObjCInterfaceDecl:{TypedText A} (50)
+// CHECK-BLOCK-RECEIVER: ObjCInterfaceDecl:{TypedText B} (50)
+// CHECK-BLOCK-RECEIVER: ParmDecl:{ResultType A *(^)(int)}{TypedText block1} (34)
+// CHECK-BLOCK-RECEIVER-NEXT: ParmDecl:{ResultType id (^)(int)}{TypedText block3} (34)
+
// Test code completion with a missing opening bracket:
// RUN: c-index-test -code-completion-at=%s:135:5 %s | FileCheck -check-prefix=CHECK-CCI %s
// RUN: c-index-test -code-completion-at=%s:139:7 %s | FileCheck -check-prefix=CHECK-CC7 %s
diff --git a/test/Index/complete-properties.m b/test/Index/complete-properties.m
index 725f180f7c29..ce1870e6511b 100644
--- a/test/Index/complete-properties.m
+++ b/test/Index/complete-properties.m
@@ -29,6 +29,22 @@ id test(I3 *i3) {
return i3.Prop3;
}
+@interface I4
+@property id Prop2;
+@end
+
+@interface I4 () {
+ I4 *Prop1;
+}
+@end
+
+@implementation I4 {
+ id Prop2_;
+}
+
+@synthesize Prop2 = Prop2_;
+@end
+
// RUN: c-index-test -code-completion-at=%s:20:13 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText Prop0}
// CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText Prop1}
@@ -41,8 +57,10 @@ id test(I3 *i3) {
// CHECK-CC2-NEXT: ObjCPropertyDecl:{ResultType id}{TypedText Prop3}
// CHECK-CC2: ObjCPropertyDecl:{ResultType id}{TypedText Prop4}
// RUN: c-index-test -code-completion-at=%s:20:35 %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: ObjCIvarDecl:{ResultType int}{TypedText RandomIVar}
-// CHECK-CC3: ObjCIvarDecl:{ResultType id}{TypedText StoredProp3}
+// CHECK-CC3: ObjCIvarDecl:{ResultType id}{TypedText _Prop3} (36)
+// CHECK-CC3: ObjCIvarDecl:{ResultType int}{TypedText RandomIVar} (35)
+// CHECK-CC3: ObjCIvarDecl:{ResultType id}{TypedText StoredProp3} (8)
+
// RUN: c-index-test -code-completion-at=%s:21:10 %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: ObjCPropertyDecl:{ResultType int}{TypedText Prop0}
// CHECK-CC4-NEXT: ObjCPropertyDecl:{ResultType id}{TypedText Prop4}
@@ -57,3 +75,8 @@ id test(I3 *i3) {
// RUN: c-index-test -code-completion-at=%s:9:11 %s | FileCheck -check-prefix=CHECK-CC6 %s
// CHECK-CC6: ObjCInterfaceDecl:{TypedText MyClass} (50)
+
+// RUN: c-index-test -code-completion-at=%s:45:21 -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC7 %s
+// CHECK-CC7-NOT: ObjCIvarDecl:{ResultType id}{TypedText _Prop2}
+// CHECK-CC7: ObjCIvarDecl:{ResultType I4 *}{TypedText Prop1} (17)
+// CHECK-CC7: ObjCIvarDecl:{ResultType id}{TypedText Prop2_} (7)
diff --git a/test/Index/index-templates.cpp b/test/Index/index-templates.cpp
index 3def6001a10a..abc95545c53b 100644
--- a/test/Index/index-templates.cpp
+++ b/test/Index/index-templates.cpp
@@ -102,7 +102,7 @@ struct SuperPair : Pair<int, int>, Pair<T, U> { };
// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-LOAD %s
// CHECK-LOAD: index-templates.cpp:4:6: FunctionTemplate=f:4:6 Extent=[3:1 - 4:22]
-// CHECK-LOAD: index-templates.cpp:3:19: TemplateTypeParameter=T:3:19 (Definition) Extent=[3:19 - 3:20]
+// CHECK-LOAD: index-templates.cpp:3:19: TemplateTypeParameter=T:3:19 (Definition) Extent=[3:10 - 3:20]
// CHECK-LOAD: index-templates.cpp:3:24: NonTypeTemplateParameter=Value:3:24 (Definition) Extent=[3:22 - 3:29]
// FIXME: Need the template type parameter here
// CHECK-LOAD: index-templates.cpp:3:66: TemplateTemplateParameter=X:3:66 (Definition) Extent=[3:31 - 3:67]
@@ -111,49 +111,49 @@ struct SuperPair : Pair<int, int>, Pair<T, U> { };
// FIXME: Need the template type parameter here
// CHECK-LOAD: index-templates.cpp:4:13: DeclRefExpr=Value:3:24 Extent=[4:13 - 4:18]
// CHECK-LOAD: index-templates.cpp:6:28: ClassTemplate=allocator:6:28 Extent=[6:1 - 6:37]
-// CHECK-LOAD: index-templates.cpp:6:19: TemplateTypeParameter=T:6:19 (Definition) Extent=[6:19 - 6:20]
+// CHECK-LOAD: index-templates.cpp:6:19: TemplateTypeParameter=T:6:19 (Definition) Extent=[6:10 - 6:20]
// CHECK-LOAD: index-templates.cpp:9:7: ClassTemplate=vector:9:7 (Definition) Extent=[8:1 - 11:2]
-// CHECK-LOAD: index-templates.cpp:8:19: TemplateTypeParameter=T:8:19 (Definition) Extent=[8:19 - 8:20]
-// CHECK-LOAD: index-templates.cpp:8:31: TemplateTypeParameter=Alloc:8:31 (Definition) Extent=[8:31 - 8:36]
+// CHECK-LOAD: index-templates.cpp:8:19: TemplateTypeParameter=T:8:19 (Definition) Extent=[8:10 - 8:20]
+// CHECK-LOAD: index-templates.cpp:8:31: TemplateTypeParameter=Alloc:8:31 (Definition) Extent=[8:22 - 8:51]
// CHECK-LOAD: index-templates.cpp:8:39: TemplateRef=allocator:6:28 Extent=[8:39 - 8:48]
-// CHECK-LOAD: index-templates.cpp:10:8: CXXMethod=clear:10:8 Extent=[10:8 - 10:15]
+// CHECK-LOAD: index-templates.cpp:10:8: CXXMethod=clear:10:8 Extent=[10:3 - 10:15]
// CHECK-LOAD: index-templates.cpp:14:7: ClassTemplatePartialSpecialization=vector:14:7 (Definition) [Specialization of vector:9:7] Extent=[13:1 - 14:21]
-// CHECK-LOAD: index-templates.cpp:13:19: TemplateTypeParameter=T:13:19 (Definition) Extent=[13:19 - 13:20]
+// CHECK-LOAD: index-templates.cpp:13:19: TemplateTypeParameter=T:13:19 (Definition) Extent=[13:10 - 13:20]
// CHECK-LOAD: index-templates.cpp:16:8: StructDecl=Z1:16:8 (Definition) Extent=[16:1 - 16:14]
-// CHECK-LOAD: index-templates.cpp:18:16: ClassDecl=vector:18:16 (Definition) [Specialization of vector:9:7] Extent=[18:1 - 18:22]
+// CHECK-LOAD: index-templates.cpp:18:16: ClassDecl=vector:18:16 (Definition) [Specialization of vector:9:7] Extent=[18:1 - 18:26]
// CHECK-LOAD: index-templates.cpp:18:23: TypeRef=struct Z1:16:8 Extent=[18:23 - 18:25]
// CHECK-LOAD-NOT: CXXMethod=clear
// CHECK-LOAD: index-templates.cpp:20:8: StructDecl=Z2:20:8 (Definition) Extent=[20:1 - 20:14]
// CHECK-LOAD: index-templates.cpp:23:7: ClassDecl=vector:23:7 (Definition) [Specialization of vector:9:7] Extent=[22:1 - 25:2]
// CHECK-LOAD: index-templates.cpp:23:14: TypeRef=struct Z2:20:8 Extent=[23:14 - 23:16]
-// CHECK-LOAD: index-templates.cpp:24:8: CXXMethod=clear:24:8 Extent=[24:8 - 24:15]
+// CHECK-LOAD: index-templates.cpp:24:8: CXXMethod=clear:24:8 Extent=[24:3 - 24:15]
// CHECK-LOAD: index-templates.cpp:28:8: ClassTemplate=Y:28:8 (Definition) Extent=[27:1 - 31:2]
-// CHECK-LOAD: index-templates.cpp:27:19: TemplateTypeParameter=T:27:19 (Definition) Extent=[27:19 - 27:20]
-// CHECK-LOAD: index-templates.cpp:27:31: TemplateTypeParameter=U:27:31 (Definition) Extent=[27:31 - 27:32]
+// CHECK-LOAD: index-templates.cpp:27:19: TemplateTypeParameter=T:27:19 (Definition) Extent=[27:10 - 27:20]
+// CHECK-LOAD: index-templates.cpp:27:31: TemplateTypeParameter=U:27:31 (Definition) Extent=[27:22 - 27:32]
// CHECK-LOAD: index-templates.cpp:29:21: UsingDeclaration=type:29:21 Extent=[29:3 - 29:25]
// CHECK-LOAD: index-templates.cpp:30:12: UsingDeclaration=operator Z2:30:12 Extent=[30:3 - 30:23]
// CHECK-LOAD: index-templates.cpp:30:21: TypeRef=struct Z2:20:8 Extent=[30:21 - 30:23]
-// CHECK-LOAD: index-templates.cpp:35:16: VarDecl=OneDimension:35:16 (Definition) Extent=[35:7 - 35:32]
+// CHECK-LOAD: index-templates.cpp:35:16: VarDecl=OneDimension:35:16 (Definition) Extent=[35:1 - 35:32]
// CHECK-LOAD: index-templates.cpp:35:31: UnexposedExpr= Extent=[35:31 - 35:32]
// CHECK-LOAD: index-templates.cpp:35:31: UnexposedExpr= Extent=[35:31 - 35:32]
// CHECK-LOAD: index-templates.cpp:37:8: ClassTemplate=array:37:8 (Definition) Extent=[36:1 - 37:17]
-// CHECK-LOAD: index-templates.cpp:36:19: TemplateTypeParameter=T:36:19 (Definition) Extent=[36:19 - 36:20]
-// CHECK-LOAD: index-templates.cpp:36:31: NonTypeTemplateParameter=Dimensions:36:31 (Definition) Extent=[36:22 - 36:41]
+// CHECK-LOAD: index-templates.cpp:36:19: TemplateTypeParameter=T:36:19 (Definition) Extent=[36:10 - 36:20]
+// CHECK-LOAD: index-templates.cpp:36:31: NonTypeTemplateParameter=Dimensions:36:31 (Definition) Extent=[36:22 - 36:56]
// CHECK-LOAD: index-templates.cpp:36:44: DeclRefExpr=OneDimension:35:16 Extent=[36:44 - 36:56]
// CHECK-LOAD: index-templates.cpp:40:8: ClassTemplate=storage:40:8 (Definition) Extent=[39:1 - 40:19]
// CHECK-LOAD: index-templates.cpp:39:45: TemplateTemplateParameter=DataStructure:39:45 (Definition) Extent=[39:10 - 39:66]
// CHECK-LOAD: index-templates.cpp:39:19: TemplateTypeParameter=:39:19 (Definition) Extent=[39:19 - 39:27]
// CHECK-LOAD: index-templates.cpp:39:37: NonTypeTemplateParameter=:39:37 (Definition) Extent=[39:29 - 39:38]
// CHECK-LOAD: index-templates.cpp:39:61: TemplateRef=array:37:8 Extent=[39:61 - 39:66]
-// CHECK-LOAD: index-templates.cpp:42:18: TypedefDecl=Unsigned:42:18 (Definition) Extent=[42:18 - 42:26]
+// CHECK-LOAD: index-templates.cpp:42:18: TypedefDecl=Unsigned:42:18 (Definition) Extent=[42:1 - 42:26]
// CHECK-LOAD: index-templates.cpp:45:8: ClassTemplate=value_c:45:8 Extent=[44:1 - 45:15]
-// CHECK-LOAD: index-templates.cpp:44:19: TemplateTypeParameter=T:44:19 (Definition) Extent=[44:19 - 44:20]
+// CHECK-LOAD: index-templates.cpp:44:19: TemplateTypeParameter=T:44:19 (Definition) Extent=[44:10 - 44:20]
// CHECK-LOAD: index-templates.cpp:44:31: NonTypeTemplateParameter=Value:44:31 (Definition) Extent=[44:22 - 44:36]
// CHECK-LOAD: index-templates.cpp:44:22: TypeRef=Unsigned:42:18 Extent=[44:22 - 44:30]
-// CHECK-LOAD: index-templates.cpp:47:16: ClassDecl=vector:47:16 (Definition) [Specialization of vector:14:7] Extent=[47:1 - 47:22]
+// CHECK-LOAD: index-templates.cpp:47:16: ClassDecl=vector:47:16 (Definition) [Specialization of vector:14:7] Extent=[47:1 - 47:28]
// CHECK-LOAD: index-templates.cpp:49:8: StructDecl=Z4:49:8 (Definition) Extent=[49:1 - 51:2]
// CHECK-LOAD: index-templates.cpp:50:26: FunctionTemplate=getAs:50:26 Extent=[50:3 - 50:33]
-// CHECK-LOAD: index-templates.cpp:50:21: TemplateTypeParameter=T:50:21 (Definition) Extent=[50:21 - 50:22]
+// CHECK-LOAD: index-templates.cpp:50:21: TemplateTypeParameter=T:50:21 (Definition) Extent=[50:12 - 50:22]
// CHECK-LOAD: index-templates.cpp:53:6: FunctionDecl=template_exprs:53:6 (Definition)
// CHECK-LOAD: index-templates.cpp:54:3: CallExpr=f:4:6 Extent=[54:3 - 54:68]
// CHECK-LOAD: index-templates.cpp:54:3: UnexposedExpr=f:4:6 Extent=[54:3 - 54:35]
@@ -174,34 +174,34 @@ struct SuperPair : Pair<int, int>, Pair<T, U> { };
// CHECK-LOAD: index-templates.cpp:85:23: TypeRef=second_type:83:13 Extent=[85:23 - 85:34]
// CHECK-LOAD: index-templates.cpp:85:35: DeclRefExpr=u:82:23 Extent=[85:35 - 85:36]
// CHECK-LOAD: index-templates.cpp:101:8: ClassTemplate=SuperPair:101:8 (Definition) Extent=[100:1 - 101:50]
-// CHECK-LOAD: index-templates.cpp:100:19: TemplateTypeParameter=T:100:19 (Definition) Extent=[100:19 - 100:20]
-// CHECK-LOAD: index-templates.cpp:100:31: TemplateTypeParameter=U:100:31 (Definition) Extent=[100:31 - 100:32]
+// CHECK-LOAD: index-templates.cpp:100:19: TemplateTypeParameter=T:100:19 (Definition) Extent=[100:10 - 100:20]
+// CHECK-LOAD: index-templates.cpp:100:31: TemplateTypeParameter=U:100:31 (Definition) Extent=[100:22 - 100:32]
// CHECK-LOAD: index-templates.cpp:101:20: C++ base class specifier=Pair<int, int>:98:16 [access=public isVirtual=false] Extent=[101:20 - 101:34]
// CHECK-LOAD: index-templates.cpp:101:36: C++ base class specifier=Pair<T, U>:76:8 [access=public isVirtual=false] Extent=[101:36 - 101:46]
// RUN: c-index-test -test-load-source-usrs all %s | FileCheck -check-prefix=CHECK-USRS %s
// CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_# Extent=[3:1 - 4:22]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@79 Extent=[3:19 - 3:20]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@70 Extent=[3:10 - 3:20]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@82 Extent=[3:22 - 3:29]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@91 Extent=[3:31 - 3:67]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@136@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_#@x Extent=[4:8 - 4:21]
// CHECK-USRS: index-templates.cpp c:@CT>1#T@allocator Extent=[6:1 - 6:37]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@171 Extent=[6:19 - 6:20]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@162 Extent=[6:10 - 6:20]
// CHECK-USRS: index-templates.cpp c:@CT>2#T#T@vector Extent=[8:1 - 11:2]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@210 Extent=[8:19 - 8:20]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@222 Extent=[8:31 - 8:36]
-// CHECK-USRS: index-templates.cpp c:@CT>2#T#T@vector@F@clear# Extent=[10:8 - 10:15]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@201 Extent=[8:10 - 8:20]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@213 Extent=[8:22 - 8:51]
+// CHECK-USRS: index-templates.cpp c:@CT>2#T#T@vector@F@clear# Extent=[10:3 - 10:15]
// CHECK-USRS: index-templates.cpp c:@CP>1#T@vector>#*t0.0#>@CT>1#T@allocator1S0_ Extent=[13:1 - 14:21]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@298 Extent=[13:19 - 13:20]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@289 Extent=[13:10 - 13:20]
// CHECK-USRS: index-templates.cpp c:@S@Z1 Extent=[16:1 - 16:14]
-// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z1#$@C@allocator>#S0_ Extent=[18:1 - 18:22]
+// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z1#$@C@allocator>#S0_ Extent=[18:1 - 18:26]
// CHECK-USRS: index-templates.cpp c:@S@Z2 Extent=[20:1 - 20:14]
// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z2#$@C@allocator>#S0_ Extent=[22:1 - 25:2]
-// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z2#$@C@allocator>#S0_@F@clear# Extent=[24:8 - 24:15]
+// CHECK-USRS: index-templates.cpp c:@C@vector>#$@S@Z2#$@C@allocator>#S0_@F@clear# Extent=[24:3 - 24:15]
// CHECK-USRS: index-templates.cpp c:@ST>2#T#T@Y Extent=[27:1 - 31:2]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@452 Extent=[27:19 - 27:20]
-// CHECK-USRS: index-templates.cpp c:index-templates.cpp@464 Extent=[27:31 - 27:32]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@443 Extent=[27:10 - 27:20]
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@455 Extent=[27:22 - 27:32]
// CHECK-USRS-NOT: type
// CHECK-USRS: index-templates.cpp c:@S@Z3 Extent=[33:1 - 33:14]
// CHECK-USRS: index-templates.cpp c:@F@f#$@S@map>#$@S@Z4#$@S@Pair>#I#S1_#$@S@compare>#$@S@Pair>#S1_#S2_#$@C@allocator>#S4_#
diff --git a/test/Index/initializer-memory.cpp b/test/Index/initializer-memory.cpp
new file mode 100644
index 000000000000..f085c3562438
--- /dev/null
+++ b/test/Index/initializer-memory.cpp
@@ -0,0 +1,16 @@
+// RUN: c-index-test -test-load-source-memory-usage none %s 2>&1 | FileCheck %s
+
+// rdar://9275920 - We would create millions of Exprs to fill out the initializer.
+
+double data[1000000] = {0};
+double data_empty_init[1000000] = {};
+
+struct S {
+ S(int);
+ S();
+};
+
+S data2[1000000] = {0};
+S data_empty_init2[1000000] = {};
+
+// CHECK: TOTAL = {{.*}} (0.{{.*}} MBytes)
diff --git a/test/Index/invalid-rdar-8236270.cpp b/test/Index/invalid-rdar-8236270.cpp
index 6fd088dcc813..4593b512ee24 100644
--- a/test/Index/invalid-rdar-8236270.cpp
+++ b/test/Index/invalid-rdar-8236270.cpp
@@ -6,6 +6,6 @@ struct abc *P;
int main(
// CHECK: StructDecl=abc:5:8 Extent=[5:1 - 5:11]
-// CHECK: VarDecl=P:5:13 (Definition) Extent=[5:8 - 5:14]
+// CHECK: VarDecl=P:5:13 (Definition) Extent=[5:1 - 5:14]
// CHECK: VarDecl=main:6:5 (Definition) Extent=[6:1 - 6:9]
diff --git a/test/Index/load-classes.cpp b/test/Index/load-classes.cpp
index 349ebdecd750..58770191ea99 100644
--- a/test/Index/load-classes.cpp
+++ b/test/Index/load-classes.cpp
@@ -17,12 +17,12 @@ X::X(int value) {
// CHECK: load-classes.cpp:4:9: ParmDecl=value:4:9 (Definition) Extent=[4:5 - 4:14]
// CHECK: load-classes.cpp:5:3: CXXConstructor=X:5:3 Extent=[5:3 - 5:16]
// FIXME: missing TypeRef in the constructor name
-// CHECK: load-classes.cpp:5:14: ParmDecl=x:5:14 (Definition) Extent=[5:11 - 5:15]
+// CHECK: load-classes.cpp:5:14: ParmDecl=x:5:14 (Definition) Extent=[5:5 - 5:15]
// CHECK: load-classes.cpp:5:11: TypeRef=struct X:3:8 Extent=[5:11 - 5:12]
// CHECK: load-classes.cpp:6:3: CXXDestructor=~X:6:3 Extent=[6:3 - 6:7]
// FIXME: missing TypeRef in the destructor name
// CHECK: load-classes.cpp:7:3: CXXConversion=operator struct X *:7:3 Extent=[7:3 - 7:16]
// CHECK: load-classes.cpp:7:12: TypeRef=struct X:3:8 Extent=[7:12 - 7:13]
-// CHECK: load-classes.cpp:10:4: CXXConstructor=X:10:4 (Definition) Extent=[10:4 - 11:2]
+// CHECK: load-classes.cpp:10:4: CXXConstructor=X:10:4 (Definition) Extent=[10:1 - 11:2]
// CHECK: load-classes.cpp:10:1: TypeRef=struct X:3:8 Extent=[10:1 - 10:2]
// CHECK: load-classes.cpp:10:10: ParmDecl=value:10:10 (Definition) Extent=[10:6 - 10:15]
diff --git a/test/Index/load-exprs.c b/test/Index/load-exprs.c
index 01adf62aff49..a4723d88ef85 100644
--- a/test/Index/load-exprs.c
+++ b/test/Index/load-exprs.c
@@ -32,30 +32,30 @@ void test_members(int aval, int bval) {
}
// RUN: c-index-test -test-load-source all %s -fblocks | FileCheck %s
-
-// CHECK: load-exprs.c:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:13 - 1:14]
+// CHECK: macro definition=__clang__
+// CHECK: load-exprs.c:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:1 - 1:14]
// CHECK: load-exprs.c:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23]
-// CHECK: load-exprs.c:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:16 - 2:17]
-// CHECK: load-exprs.c:2:19: FieldDecl=b:2:19 (Definition) Extent=[2:19 - 2:20]
-// CHECK: load-exprs.c:3:6: FunctionDecl=f:3:6 (Definition) Extent=[3:6 - 8:2]
+// CHECK: load-exprs.c:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:12 - 2:17]
+// CHECK: load-exprs.c:2:19: FieldDecl=b:2:19 (Definition) Extent=[2:12 - 2:20]
+// CHECK: load-exprs.c:3:6: FunctionDecl=f:3:6 (Definition) Extent=[3:1 - 8:2]
// CHECK: load-exprs.c:3:14: ParmDecl=ptr:3:14 (Definition) Extent=[3:8 - 3:17]
// CHECK: load-exprs.c:4:6: VarDecl=t_ptr:4:6 (Definition) Extent=[4:3 - 4:22]
// CHECK: load-exprs.c:4:3: TypeRef=T:1:13 Extent=[4:3 - 4:4]
// CHECK: load-exprs.c:4:15: TypeRef=T:1:13 Extent=[4:15 - 4:16]
// CHECK: load-exprs.c:4:19: DeclRefExpr=ptr:3:14 Extent=[4:19 - 4:22]
// CHECK: load-exprs.c:5:16: TypeRef=T:1:13 Extent=[5:16 - 5:17]
-// CHECK: load-exprs.c:6:12: VarDecl=x:6:12 (Definition) Extent=[6:10 - 6:32]
+// CHECK: load-exprs.c:6:12: VarDecl=x:6:12 (Definition) Extent=[6:3 - 6:32]
// CHECK: load-exprs.c:6:10: TypeRef=struct X:2:8 Extent=[6:10 - 6:11]
// CHECK: load-exprs.c:6:24: TypeRef=struct X:2:8 Extent=[6:24 - 6:25]
// CHECK: load-exprs.c:7:9: VarDecl=xx:7:9 (Definition) Extent=[7:3 - 7:24]
// CHECK: load-exprs.c:7:14: DeclRefExpr=ptr:3:14 Extent=[7:14 - 7:17]
// CHECK: load-exprs.c:7:23: DeclRefExpr=x:6:12 Extent=[7:23 - 7:24]
-// CHECK: load-exprs.c:10:5: FunctionDecl=test_blocks:10:5 (Definition) Extent=[10:5 - 21:2]
+// CHECK: load-exprs.c:10:5: FunctionDecl=test_blocks:10:5 (Definition) Extent=[10:1 - 21:2]
// CHECK: load-exprs.c:10:21: ParmDecl=x:10:21 (Definition) Extent=[10:17 - 10:22]
-// CHECK: load-exprs.c:11:15: VarDecl=y:11:15 (Definition) Extent=[11:11 - 11:20]
+// CHECK: load-exprs.c:11:15: VarDecl=y:11:15 (Definition) Extent=[11:3 - 11:20]
// CHECK: load-exprs.c:11:19: DeclRefExpr=x:10:21 Extent=[11:19 - 11:20]
// CHECK: load-exprs.c:12:3: CallExpr= Extent=[12:3 - 19:7]
-// CHECK: load-exprs.c:13:17: VarDecl=z:13:17 (Definition) Extent=[13:13 - 13:22]
+// CHECK: load-exprs.c:13:17: VarDecl=z:13:17 (Definition) Extent=[13:6 - 13:22]
// CHECK: load-exprs.c:14:6: DeclRefExpr=y:11:15 Extent=[14:6 - 14:7]
// CHECK: load-exprs.c:14:13: DeclRefExpr=z:13:17 Extent=[14:13 - 14:14]
// CHECK: load-exprs.c:14:18: DeclRefExpr=x:10:21 Extent=[14:18 - 14:19]
@@ -64,7 +64,7 @@ void test_members(int aval, int bval) {
// CHECK: load-exprs.c:17:10: DeclRefExpr=y:11:15 Extent=[17:10 - 17:11]
// CHECK: load-exprs.c:20:10: DeclRefExpr=y:11:15 Extent=[20:10 - 20:11]
// CHECK: load-exprs.c:29:6: FunctionDecl=test_members:29:6 (Definition)
-// CHECK: load-exprs.c:30:12: VarDecl=y0:30:12 (Definition) Extent=[30:10 - 30:77]
+// CHECK: load-exprs.c:30:12: VarDecl=y0:30:12 (Definition) Extent=[30:3 - 30:77]
// CHECK: load-exprs.c:30:10: TypeRef=struct Y:23:8 Extent=[30:10 - 30:11]
// CHECK: load-exprs.c:30:20: MemberRef=array:24:12 Extent=[30:20 - 30:25]
// CHECK: load-exprs.c:30:26: DeclRefExpr=StartIndex:27:8 Extent=[30:26 - 30:36]
diff --git a/test/Index/load-namespaces.cpp b/test/Index/load-namespaces.cpp
index 931a1dc79d2c..49de66a81d36 100644
--- a/test/Index/load-namespaces.cpp
+++ b/test/Index/load-namespaces.cpp
@@ -27,23 +27,23 @@ void std::g() {
namespace my_rel_ops = std::rel_ops;
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// CHECK: load-namespaces.cpp:3:11: Namespace=std:3:11 (Definition) Extent=[3:11 - 7:2]
-// CHECK: load-namespaces.cpp:4:13: Namespace=rel_ops:4:13 (Definition) Extent=[4:13 - 6:4]
-// CHECK: load-namespaces.cpp:5:10: FunctionDecl=f:5:10 Extent=[5:10 - 5:13]
-// CHECK: load-namespaces.cpp:9:11: Namespace=std:9:11 (Definition) Extent=[9:11 - 11:2]
-// CHECK: load-namespaces.cpp:10:8: FunctionDecl=g:10:8 Extent=[10:8 - 10:11]
+// CHECK: load-namespaces.cpp:3:11: Namespace=std:3:11 (Definition) Extent=[3:1 - 7:2]
+// CHECK: load-namespaces.cpp:4:13: Namespace=rel_ops:4:13 (Definition) Extent=[4:3 - 6:4]
+// CHECK: load-namespaces.cpp:5:10: FunctionDecl=f:5:10 Extent=[5:5 - 5:13]
+// CHECK: load-namespaces.cpp:9:11: Namespace=std:9:11 (Definition) Extent=[9:1 - 11:2]
+// CHECK: load-namespaces.cpp:10:8: FunctionDecl=g:10:8 Extent=[10:3 - 10:11]
// CHECK: load-namespaces.cpp:13:11: NamespaceAlias=std98:13:11 Extent=[13:1 - 13:22]
// CHECK: load-namespaces.cpp:13:19: NamespaceRef=std:3:11 Extent=[13:19 - 13:22]
// CHECK: load-namespaces.cpp:14:11: NamespaceAlias=std0x:14:11 Extent=[14:1 - 14:24]
// CHECK: load-namespaces.cpp:14:19: NamespaceRef=std98:13:11 Extent=[14:19 - 14:24]
// CHECK: load-namespaces.cpp:16:17: UsingDirective=:16:17 Extent=[16:1 - 16:22]
// CHECK: load-namespaces.cpp:16:17: NamespaceRef=std0x:14:11 Extent=[16:17 - 16:22]
-// CHECK: load-namespaces.cpp:18:11: Namespace=std:18:11 (Definition) Extent=[18:11 - 20:2]
-// CHECK: load-namespaces.cpp:19:7: FunctionDecl=g:19:7 Extent=[19:7 - 19:13]
+// CHECK: load-namespaces.cpp:18:11: Namespace=std:18:11 (Definition) Extent=[18:1 - 20:2]
+// CHECK: load-namespaces.cpp:19:7: FunctionDecl=g:19:7 Extent=[19:3 - 19:13]
// CHECK: load-namespaces.cpp:19:12: ParmDecl=:19:12 (Definition) Extent=[19:9 - 19:13]
// CHECK: load-namespaces.cpp:22:12: UsingDeclaration=g[19:7, 10:8] Extent=[22:1 - 22:13]
// CHECK: load-namespaces.cpp:22:7: NamespaceRef=std:18:11 Extent=[22:7 - 22:10]
-// CHECK: load-namespaces.cpp:24:11: FunctionDecl=g:24:11 (Definition) Extent=[24:11 - 25:2]
+// CHECK: load-namespaces.cpp:24:11: FunctionDecl=g:24:11 (Definition) Extent=[24:1 - 25:2]
// CHECK: load-namespaces.cpp:24:6: NamespaceRef=std:18:11 Extent=[24:6 - 24:9]
// CHECK: load-namespaces.cpp:27:11: NamespaceAlias=my_rel_ops:27:11 Extent=[27:1 - 27:36]
// CHECK: load-namespaces.cpp:27:24: NamespaceRef=std:18:11 Extent=[27:24 - 27:27]
diff --git a/test/Index/load-stmts.cpp b/test/Index/load-stmts.cpp
index 323b778faf23..cb9d3f2b609f 100644
--- a/test/Index/load-stmts.cpp
+++ b/test/Index/load-stmts.cpp
@@ -118,11 +118,11 @@ void casts(int *ip) {
}
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// CHECK: load-stmts.cpp:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:13 - 1:14]
+// CHECK: load-stmts.cpp:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:1 - 1:14]
// CHECK: load-stmts.cpp:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23]
-// CHECK: load-stmts.cpp:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:16 - 2:17]
-// CHECK: load-stmts.cpp:2:19: FieldDecl=b:2:19 (Definition) Extent=[2:19 - 2:20]
-// CHECK: load-stmts.cpp:3:6: FunctionDecl=f:3:6 (Definition) Extent=[3:6 - 11:2]
+// CHECK: load-stmts.cpp:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:12 - 2:17]
+// CHECK: load-stmts.cpp:2:19: FieldDecl=b:2:19 (Definition) Extent=[2:12 - 2:20]
+// CHECK: load-stmts.cpp:3:6: FunctionDecl=f:3:6 (Definition) Extent=[3:1 - 11:2]
// CHECK: load-stmts.cpp:3:12: ParmDecl=x:3:12 (Definition) Extent=[3:8 - 3:13]
// CHECK: load-stmts.cpp:4:10: VarDecl=y:4:10 (Definition) Extent=[4:8 - 4:15]
// CHECK: load-stmts.cpp:4:8: TypeRef=T:1:13 Extent=[4:8 - 4:9]
@@ -152,13 +152,13 @@ void casts(int *ip) {
// CHECK: load-stmts.cpp:8:13: DeclRefExpr=z4:8:13 Extent=[8:13 - 8:15]
// CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10]
// CHECK: load-stmts.cpp:14:7: ClassDecl=A:14:7 (Definition) Extent=[14:1 - 16:2]
-// CHECK: load-stmts.cpp:15:8: CXXMethod=doA:15:8 Extent=[15:8 - 15:13]
+// CHECK: load-stmts.cpp:15:8: CXXMethod=doA:15:8 Extent=[15:3 - 15:13]
// CHECK: load-stmts.cpp:18:7: ClassDecl=B:18:7 (Definition) Extent=[18:1 - 20:2]
-// CHECK: load-stmts.cpp:19:8: CXXMethod=doB:19:8 Extent=[19:8 - 19:13]
+// CHECK: load-stmts.cpp:19:8: CXXMethod=doB:19:8 Extent=[19:3 - 19:13]
// CHECK: load-stmts.cpp:22:7: ClassDecl=C:22:7 (Definition) Extent=[22:1 - 24:2]
// CHECK: load-stmts.cpp:22:18: C++ base class specifier=class A:14:7 [access=public isVirtual=false]
// CHECK: load-stmts.cpp:22:29: C++ base class specifier=class B:18:7 [access=private isVirtual=false]
-// CHECK: load-stmts.cpp:23:8: CXXMethod=doC:23:8 Extent=[23:8 - 23:13]
+// CHECK: load-stmts.cpp:23:8: CXXMethod=doC:23:8 Extent=[23:3 - 23:13]
// CHECK: load-stmts.cpp:26:7: ClassDecl=D:26:7 (Definition) Extent=[26:1 - 26:49]
// CHECK: load-stmts.cpp:26:26: C++ base class specifier=class C:22:7 [access=public isVirtual=true]
// CHECK: load-stmts.cpp:26:45: C++ base class specifier=class A:14:7 [access=private isVirtual=true]
@@ -174,7 +174,7 @@ void casts(int *ip) {
// CHECK: load-stmts.cpp:51:3: CallExpr= Extent=[51:3 - 51:10]
// CHECK: load-stmts.cpp:51:3: NamespaceRef=N:41:11 Extent=[51:3 - 51:4]
// CHECK: load-stmts.cpp:51:8: DeclRefExpr=t:50:29 Extent=[51:8 - 51:9]
-// CHECK: load-stmts.cpp:52:13: TypedefDecl=type:52:13 (Definition) Extent=[52:13 - 52:17]
+// CHECK: load-stmts.cpp:52:13: TypedefDecl=type:52:13 (Definition) Extent=[52:3 - 52:17]
// CHECK: load-stmts.cpp:53:3: CallExpr= Extent=[53:3 - 53:16]
// CHECK: load-stmts.cpp:53:3: NamespaceRef=N:41:11 Extent=[53:3 - 53:4]
// CHECK: load-stmts.cpp:53:8: TypeRef=type:52:13 Extent=[53:8 - 53:12]
diff --git a/test/Index/local-symbols.m b/test/Index/local-symbols.m
index af3b601465a8..3a479522944e 100644
--- a/test/Index/local-symbols.m
+++ b/test/Index/local-symbols.m
@@ -27,7 +27,7 @@
@end
// CHECK: local-symbols.m:6:12: ObjCInterfaceDecl=Foo:6:12 Extent=[6:1 - 10:5]
-// CHECK: local-symbols.m:7:6: ObjCIvarDecl=x:7:6 (Definition) Extent=[7:6 - 7:7]
+// CHECK: local-symbols.m:7:6: ObjCIvarDecl=x:7:6 (Definition) Extent=[7:3 - 7:7]
// CHECK: local-symbols.m:7:3: TypeRef=id:0:0 Extent=[7:3 - 7:5]
// CHECK: local-symbols.m:9:1: ObjCInstanceMethodDecl=bar:9:1 Extent=[9:1 - 9:12]
// CHECK: local-symbols.m:9:4: TypeRef=id:0:0 Extent=[9:4 - 9:6]
diff --git a/test/Index/nested-binaryoperators.cpp b/test/Index/nested-binaryoperators.cpp
index d263b9ddbc21..db5efe2cc8c2 100644
--- a/test/Index/nested-binaryoperators.cpp
+++ b/test/Index/nested-binaryoperators.cpp
@@ -161,8 +161,8 @@ int foo(uint c) {
}
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// CHECK: 1:22: TypedefDecl=uint:1:22 (Definition) Extent=[1:22 - 1:26]
-// CHECK: 2:5: FunctionDecl=foo:2:5 (Definition) Extent=[2:5 - 161:2]
+// CHECK: 1:22: TypedefDecl=uint:1:22 (Definition) Extent=[1:1 - 1:26]
+// CHECK: 2:5: FunctionDecl=foo:2:5 (Definition) Extent=[2:1 - 161:2]
// CHECK: 2:14: ParmDecl=c:2:14 (Definition) Extent=[2:9 - 2:15]
// CHECK: 2:9: TypeRef=uint:1:22 Extent=[2:9 - 2:13]
// CHECK: 2:17: UnexposedStmt= Extent=[2:17 - 161:2]
diff --git a/test/Index/overrides.cpp b/test/Index/overrides.cpp
index 3dee607e4318..ed24cc5cf59b 100644
--- a/test/Index/overrides.cpp
+++ b/test/Index/overrides.cpp
@@ -16,5 +16,5 @@ struct D : C {
};
// RUN: c-index-test -test-load-source local %s | FileCheck %s
-// CHECK: overrides.cpp:11:16: CXXMethod=g:11:16 [Overrides @7:16] Extent=[11:16 - 11:19]
-// CHECK: overrides.cpp:15:16: CXXMethod=f:15:16 [Overrides @2:16, @6:16] Extent=[15:16 - 15:22]
+// CHECK: overrides.cpp:11:16: CXXMethod=g:11:16 [Overrides @7:16] Extent=[11:3 - 11:19]
+// CHECK: overrides.cpp:15:16: CXXMethod=f:15:16 [Overrides @2:16, @6:16] Extent=[15:3 - 15:22]
diff --git a/test/Index/pragma-diag-reparse.c b/test/Index/pragma-diag-reparse.c
new file mode 100644
index 000000000000..efe59b177841
--- /dev/null
+++ b/test/Index/pragma-diag-reparse.c
@@ -0,0 +1,13 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local %s | FileCheck %s
+
+int main (int argc, const char * argv[])
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ int x;
+#pragma clang diagnostic pop
+
+ return 0;
+}
+
+// CHECK: pragma-diag-reparse.c:7:7: VarDecl=x:7:7 (Definition) Extent=[7:3 - 7:8]
diff --git a/test/Index/preamble-reparse-chained.c b/test/Index/preamble-reparse-chained.c
index 5be3b12f01db..5cc28f705464 100644
--- a/test/Index/preamble-reparse-chained.c
+++ b/test/Index/preamble-reparse-chained.c
@@ -6,5 +6,5 @@
A a;
B b;
-// CHECK: a.h:3:13: TypedefDecl=A:3:13 (Definition) Extent=[3:13 - 3:14]
-// CHECK: b.h:1:15: TypedefDecl=B:1:15 (Definition) Extent=[1:15 - 1:16]
+// CHECK: a.h:3:13: TypedefDecl=A:3:13 (Definition) Extent=[3:1 - 3:14]
+// CHECK: b.h:1:15: TypedefDecl=B:1:15 (Definition) Extent=[1:1 - 1:16]
diff --git a/test/Index/preamble.c b/test/Index/preamble.c
index fb784b389d0a..119bdb58e759 100644
--- a/test/Index/preamble.c
+++ b/test/Index/preamble.c
@@ -8,13 +8,13 @@ void f(int x) {
// RUN: c-index-test -write-pch %t.pch -x c-header %S/Inputs/prefix.h
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck %s
// RUN: FileCheck -check-prefix CHECK-DIAG %s < %t.stderr.txt
-// CHECK: preamble.h:1:12: FunctionDecl=bar:1:12 (Definition) Extent=[1:12 - 6:2]
+// CHECK: preamble.h:1:12: FunctionDecl=bar:1:12 (Definition) Extent=[1:1 - 6:2]
// CHECK: preamble.h:4:3: UnexposedExpr= Extent=[4:3 - 4:13]
// CHECK: preamble.h:4:3: DeclRefExpr=ptr:2:8 Extent=[4:3 - 4:6]
// CHECK: preamble.h:4:9: UnexposedExpr=ptr1:3:10 Extent=[4:9 - 4:13]
// CHECK: preamble.h:4:9: DeclRefExpr=ptr1:3:10 Extent=[4:9 - 4:13]
// CHECK: preamble.h:5:10: UnexposedExpr= Extent=[5:10 - 5:11]
-// CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:5 - 3:16]
+// CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:1 - 3:16]
// CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16]
// CHECK-DIAG: preamble.h:4:7:{4:9-4:13}: warning: incompatible pointer types assigning to 'int *' from 'float *'
// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:6:1 -I %S/Inputs -include %t %s 2> %t.stderr.txt | FileCheck -check-prefix CHECK-CC %s
diff --git a/test/Index/rdar-8288645-invalid-code.mm b/test/Index/rdar-8288645-invalid-code.mm
index 3405f0a93270..74e2365edcfe 100644
--- a/test/Index/rdar-8288645-invalid-code.mm
+++ b/test/Index/rdar-8288645-invalid-code.mm
@@ -5,4 +5,4 @@
extern "C" { @implementation Foo - (id)initWithBar:(Baz<WozBar>)pepper {
// CHECK: warning: cannot find interface declaration for 'Foo'
-// CHECK: warning: '@end' is missing in implementation context
+// CHECK: error: '@end' is missing in implementation context
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index 1707491af03e..6170fdcb81d7 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -201,16 +201,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "{" [3:15 - 3:16] Namespace=std:3:11 (Definition)
// CHECK-tokens: Keyword: "template" [4:3 - 4:11] ClassTemplate=pair:4:44 (Definition)
// CHECK-tokens: Punctuation: "<" [4:12 - 4:13] ClassTemplate=pair:4:44 (Definition)
-// CHECK-tokens: Keyword: "class" [4:14 - 4:19] ClassTemplate=pair:4:44 (Definition)
+// CHECK-tokens: Keyword: "class" [4:14 - 4:19] TemplateTypeParameter=_T1:4:20 (Definition)
// CHECK-tokens: Identifier: "_T1" [4:20 - 4:23] TemplateTypeParameter=_T1:4:20 (Definition)
// CHECK-tokens: Punctuation: "," [4:23 - 4:24] ClassTemplate=pair:4:44 (Definition)
-// CHECK-tokens: Keyword: "class" [4:25 - 4:30] ClassTemplate=pair:4:44 (Definition)
+// CHECK-tokens: Keyword: "class" [4:25 - 4:30] TemplateTypeParameter=_T2:4:31 (Definition)
// CHECK-tokens: Identifier: "_T2" [4:31 - 4:34] TemplateTypeParameter=_T2:4:31 (Definition)
// CHECK-tokens: Punctuation: ">" [4:35 - 4:36] ClassTemplate=pair:4:44 (Definition)
// CHECK-tokens: Keyword: "struct" [4:37 - 4:43] ClassTemplate=pair:4:44 (Definition)
// CHECK-tokens: Identifier: "pair" [4:44 - 4:48] ClassTemplate=pair:4:44 (Definition)
// CHECK-tokens: Punctuation: "{" [4:49 - 4:50] ClassTemplate=pair:4:44 (Definition)
-// CHECK-tokens: Identifier: "_T2" [4:51 - 4:54] FieldDecl=second:4:55 (Definition)
+// CHECK-tokens: Identifier: "_T2" [4:51 - 4:54] TypeRef=_T2:4:31
// CHECK-tokens: Identifier: "second" [4:55 - 4:61] FieldDecl=second:4:55 (Definition)
// CHECK-tokens: Punctuation: ";" [4:61 - 4:62] ClassTemplate=pair:4:44 (Definition)
// CHECK-tokens: Punctuation: "}" [4:63 - 4:64] ClassTemplate=pair:4:44 (Definition)
@@ -429,8 +429,8 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ":" [39:7 - 39:8] UnexposedDecl=:39:1 (Definition)
// CHECK-tokens: Keyword: "typedef" [40:3 - 40:10] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Keyword: "const" [40:11 - 40:16] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Keyword: "char" [40:17 - 40:21] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Punctuation: "*" [40:22 - 40:23] ClassDecl=StringRef:38:7 (Definition)
+// CHECK-tokens: Keyword: "char" [40:17 - 40:21] TypedefDecl=iterator:40:23 (Definition)
+// CHECK-tokens: Punctuation: "*" [40:22 - 40:23] TypedefDecl=iterator:40:23 (Definition)
// CHECK-tokens: Identifier: "iterator" [40:23 - 40:31] TypedefDecl=iterator:40:23 (Definition)
// CHECK-tokens: Punctuation: ";" [40:31 - 40:32] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Keyword: "static" [41:3 - 41:9] ClassDecl=StringRef:38:7 (Definition)
@@ -679,16 +679,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Keyword: "const" [68:30 - 68:35] CXXMethod=getNameStart:68:15 (Definition)
// CHECK-tokens: Punctuation: "{" [68:36 - 68:37] UnexposedStmt=
// CHECK-tokens: Keyword: "typedef" [69:5 - 69:12] UnexposedStmt=
-// CHECK-tokens: Identifier: "std" [69:13 - 69:16] UnexposedStmt=
-// CHECK-tokens: Punctuation: "::" [69:16 - 69:18] UnexposedStmt=
-// CHECK-tokens: Identifier: "pair" [69:18 - 69:22] UnexposedStmt=
-// CHECK-tokens: Punctuation: "<" [69:23 - 69:24] UnexposedStmt=
-// CHECK-tokens: Identifier: "IdentifierInfo" [69:25 - 69:39] UnexposedStmt=
-// CHECK-tokens: Punctuation: "," [69:39 - 69:40] UnexposedStmt=
-// CHECK-tokens: Keyword: "const" [69:41 - 69:46] UnexposedStmt=
-// CHECK-tokens: Keyword: "char" [69:47 - 69:51] UnexposedStmt=
-// CHECK-tokens: Punctuation: "*" [69:52 - 69:53] UnexposedStmt=
-// CHECK-tokens: Punctuation: ">" [69:53 - 69:54] UnexposedStmt=
+// CHECK-tokens: Identifier: "std" [69:13 - 69:16] NamespaceRef=std:3:11
+// CHECK-tokens: Punctuation: "::" [69:16 - 69:18] TypedefDecl=actualtype:69:54 (Definition)
+// CHECK-tokens: Identifier: "pair" [69:18 - 69:22] TemplateRef=pair:4:44
+// CHECK-tokens: Punctuation: "<" [69:23 - 69:24] TypedefDecl=actualtype:69:54 (Definition)
+// CHECK-tokens: Identifier: "IdentifierInfo" [69:25 - 69:39] TypeRef=class clang::IdentifierInfo:66:7
+// CHECK-tokens: Punctuation: "," [69:39 - 69:40] TypedefDecl=actualtype:69:54 (Definition)
+// CHECK-tokens: Keyword: "const" [69:41 - 69:46] TypedefDecl=actualtype:69:54 (Definition)
+// CHECK-tokens: Keyword: "char" [69:47 - 69:51] TypedefDecl=actualtype:69:54 (Definition)
+// CHECK-tokens: Punctuation: "*" [69:52 - 69:53] TypedefDecl=actualtype:69:54 (Definition)
+// CHECK-tokens: Punctuation: ">" [69:53 - 69:54] TypedefDecl=actualtype:69:54 (Definition)
// CHECK-tokens: Identifier: "actualtype" [69:54 - 69:64] TypedefDecl=actualtype:69:54 (Definition)
// CHECK-tokens: Punctuation: ";" [69:64 - 69:65] UnexposedStmt=
// CHECK-tokens: Keyword: "return" [70:5 - 70:11] UnexposedStmt=
@@ -711,16 +711,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Keyword: "const" [72:24 - 72:29] CXXMethod=getLength:72:12 (Definition)
// CHECK-tokens: Punctuation: "{" [72:30 - 72:31] UnexposedStmt=
// CHECK-tokens: Keyword: "typedef" [73:5 - 73:12] UnexposedStmt=
-// CHECK-tokens: Identifier: "std" [73:13 - 73:16] UnexposedStmt=
-// CHECK-tokens: Punctuation: "::" [73:16 - 73:18] UnexposedStmt=
-// CHECK-tokens: Identifier: "pair" [73:18 - 73:22] UnexposedStmt=
-// CHECK-tokens: Punctuation: "<" [73:23 - 73:24] UnexposedStmt=
-// CHECK-tokens: Identifier: "IdentifierInfo" [73:25 - 73:39] UnexposedStmt=
-// CHECK-tokens: Punctuation: "," [73:39 - 73:40] UnexposedStmt=
-// CHECK-tokens: Keyword: "const" [73:41 - 73:46] UnexposedStmt=
-// CHECK-tokens: Keyword: "char" [73:47 - 73:51] UnexposedStmt=
-// CHECK-tokens: Punctuation: "*" [73:52 - 73:53] UnexposedStmt=
-// CHECK-tokens: Punctuation: ">" [73:53 - 73:54] UnexposedStmt=
+// CHECK-tokens: Identifier: "std" [73:13 - 73:16] NamespaceRef=std:3:11
+// CHECK-tokens: Punctuation: "::" [73:16 - 73:18] TypedefDecl=actualtype:73:54 (Definition)
+// CHECK-tokens: Identifier: "pair" [73:18 - 73:22] TemplateRef=pair:4:44
+// CHECK-tokens: Punctuation: "<" [73:23 - 73:24] TypedefDecl=actualtype:73:54 (Definition)
+// CHECK-tokens: Identifier: "IdentifierInfo" [73:25 - 73:39] TypeRef=class clang::IdentifierInfo:66:7
+// CHECK-tokens: Punctuation: "," [73:39 - 73:40] TypedefDecl=actualtype:73:54 (Definition)
+// CHECK-tokens: Keyword: "const" [73:41 - 73:46] TypedefDecl=actualtype:73:54 (Definition)
+// CHECK-tokens: Keyword: "char" [73:47 - 73:51] TypedefDecl=actualtype:73:54 (Definition)
+// CHECK-tokens: Punctuation: "*" [73:52 - 73:53] TypedefDecl=actualtype:73:54 (Definition)
+// CHECK-tokens: Punctuation: ">" [73:53 - 73:54] TypedefDecl=actualtype:73:54 (Definition)
// CHECK-tokens: Identifier: "actualtype" [73:54 - 73:64] TypedefDecl=actualtype:73:54 (Definition)
// CHECK-tokens: Punctuation: ";" [73:64 - 73:65] UnexposedStmt=
// CHECK-tokens: Keyword: "const" [74:5 - 74:10] UnexposedStmt=
@@ -771,18 +771,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Literal: "1" [75:61 - 75:62] UnexposedExpr=
// CHECK-tokens: Punctuation: ";" [75:62 - 75:63] UnexposedStmt=
// CHECK-tokens: Punctuation: "}" [76:3 - 76:4] UnexposedStmt=
-// CHECK-tokens: Identifier: "llvm" [77:3 - 77:7] CXXMethod=getName:77:19 (Definition)
+// CHECK-tokens: Identifier: "llvm" [77:3 - 77:7] NamespaceRef=llvm:37:11
// CHECK-tokens: Punctuation: "::" [77:7 - 77:9] CXXMethod=getName:77:19 (Definition)
-// CHECK-tokens: Identifier: "StringRef" [77:9 - 77:18] CXXMethod=getName:77:19 (Definition)
+// CHECK-tokens: Identifier: "StringRef" [77:9 - 77:18] TypeRef=class llvm::StringRef:38:7
// CHECK-tokens: Identifier: "getName" [77:19 - 77:26] CXXMethod=getName:77:19 (Definition)
// CHECK-tokens: Punctuation: "(" [77:26 - 77:27] CXXMethod=getName:77:19 (Definition)
// CHECK-tokens: Punctuation: ")" [77:27 - 77:28] CXXMethod=getName:77:19 (Definition)
// CHECK-tokens: Keyword: "const" [77:29 - 77:34] CXXMethod=getName:77:19 (Definition)
// CHECK-tokens: Punctuation: "{" [77:35 - 77:36] UnexposedStmt=
// CHECK-tokens: Keyword: "return" [78:5 - 78:11] UnexposedStmt=
-// CHECK-tokens: Identifier: "llvm" [78:12 - 78:16] CallExpr=StringRef:49:3
+// CHECK-tokens: Identifier: "llvm" [78:12 - 78:16] NamespaceRef=llvm:37:11
// CHECK-tokens: Punctuation: "::" [78:16 - 78:18] CallExpr=StringRef:49:3
-// CHECK-tokens: Identifier: "StringRef" [78:18 - 78:27] CallExpr=StringRef:49:3
+// CHECK-tokens: Identifier: "StringRef" [78:18 - 78:27] TypeRef=class llvm::StringRef:38:7
// CHECK-tokens: Punctuation: "(" [78:27 - 78:28] CallExpr=StringRef:49:3
// CHECK-tokens: Identifier: "getNameStart" [78:28 - 78:40] MemberRefExpr=getNameStart:68:15
// CHECK-tokens: Punctuation: "(" [78:40 - 78:41] CallExpr=getNameStart:68:15
@@ -802,13 +802,13 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "{" [82:16 - 82:17] Namespace=llvm:82:11 (Definition)
// CHECK-tokens: Keyword: "template" [83:1 - 83:9] ClassTemplate=StringSwitch:83:47 (Definition)
// CHECK-tokens: Punctuation: "<" [83:10 - 83:11] ClassTemplate=StringSwitch:83:47 (Definition)
-// CHECK-tokens: Keyword: "typename" [83:12 - 83:20] ClassTemplate=StringSwitch:83:47 (Definition)
+// CHECK-tokens: Keyword: "typename" [83:12 - 83:20] TemplateTypeParameter=T:83:21 (Definition)
// CHECK-tokens: Identifier: "T" [83:21 - 83:22] TemplateTypeParameter=T:83:21 (Definition)
// CHECK-tokens: Punctuation: "," [83:22 - 83:23] ClassTemplate=StringSwitch:83:47 (Definition)
-// CHECK-tokens: Keyword: "typename" [83:24 - 83:32] ClassTemplate=StringSwitch:83:47 (Definition)
+// CHECK-tokens: Keyword: "typename" [83:24 - 83:32] TemplateTypeParameter=R:83:33 (Definition)
// CHECK-tokens: Identifier: "R" [83:33 - 83:34] TemplateTypeParameter=R:83:33 (Definition)
-// CHECK-tokens: Punctuation: "=" [83:35 - 83:36] ClassTemplate=StringSwitch:83:47 (Definition)
-// CHECK-tokens: Identifier: "T" [83:37 - 83:38] ClassTemplate=StringSwitch:83:47 (Definition)
+// CHECK-tokens: Punctuation: "=" [83:35 - 83:36] TemplateTypeParameter=R:83:33 (Definition)
+// CHECK-tokens: Identifier: "T" [83:37 - 83:38] TypeRef=T:83:21
// CHECK-tokens: Punctuation: ">" [83:39 - 83:40] ClassTemplate=StringSwitch:83:47 (Definition)
// CHECK-tokens: Keyword: "class" [83:41 - 83:46] ClassTemplate=StringSwitch:83:47 (Definition)
// CHECK-tokens: Identifier: "StringSwitch" [83:47 - 83:59] ClassTemplate=StringSwitch:83:47 (Definition)
@@ -817,13 +817,13 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "Str" [84:13 - 84:16] FieldDecl=Str:84:13 (Definition)
// CHECK-tokens: Punctuation: ";" [84:16 - 84:17] ClassTemplate=StringSwitch:83:47 (Definition)
// CHECK-tokens: Keyword: "const" [85:3 - 85:8] ClassTemplate=StringSwitch:83:47 (Definition)
-// CHECK-tokens: Identifier: "T" [85:9 - 85:10] FieldDecl=Result:85:12 (Definition)
+// CHECK-tokens: Identifier: "T" [85:9 - 85:10] TypeRef=T:83:21
// CHECK-tokens: Punctuation: "*" [85:11 - 85:12] FieldDecl=Result:85:12 (Definition)
// CHECK-tokens: Identifier: "Result" [85:12 - 85:18] FieldDecl=Result:85:12 (Definition)
// CHECK-tokens: Punctuation: ";" [85:18 - 85:19] ClassTemplate=StringSwitch:83:47 (Definition)
// CHECK-tokens: Keyword: "public" [86:1 - 86:7] UnexposedDecl=:86:1 (Definition)
// CHECK-tokens: Punctuation: ":" [86:7 - 86:8] UnexposedDecl=:86:1 (Definition)
-// CHECK-tokens: Keyword: "explicit" [87:3 - 87:11] ClassTemplate=StringSwitch:83:47 (Definition)
+// CHECK-tokens: Keyword: "explicit" [87:3 - 87:11] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Identifier: "StringSwitch" [87:12 - 87:24] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Punctuation: "(" [87:24 - 87:25] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Identifier: "StringRef" [87:25 - 87:34] TypeRef=class llvm::StringRef:38:7
@@ -858,10 +858,10 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [88:61 - 88:62] ParmDecl=S:88:60 (Definition)
// CHECK-tokens: Punctuation: "[" [88:62 - 88:63] ParmDecl=S:88:60 (Definition)
// CHECK-tokens: Identifier: "N" [88:63 - 88:64] DeclRefExpr=N:88:23
-// CHECK-tokens: Punctuation: "]" [88:64 - 88:65] FunctionTemplate=Case:88:42 (Definition)
+// CHECK-tokens: Punctuation: "]" [88:64 - 88:65] ParmDecl=S:88:60 (Definition)
// CHECK-tokens: Punctuation: "," [88:65 - 88:66] FunctionTemplate=Case:88:42 (Definition)
// CHECK-tokens: Keyword: "const" [89:47 - 89:52] FunctionTemplate=Case:88:42 (Definition)
-// CHECK-tokens: Identifier: "T" [89:53 - 89:54] ParmDecl=Value:89:57 (Definition)
+// CHECK-tokens: Identifier: "T" [89:53 - 89:54] TypeRef=T:83:21
// CHECK-tokens: Punctuation: "&" [89:55 - 89:56] ParmDecl=Value:89:57 (Definition)
// CHECK-tokens: Identifier: "Value" [89:57 - 89:62] ParmDecl=Value:89:57 (Definition)
// CHECK-tokens: Punctuation: ")" [89:62 - 89:63] FunctionTemplate=Case:88:42 (Definition)
@@ -871,11 +871,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Keyword: "this" [90:13 - 90:17] UnexposedExpr=
// CHECK-tokens: Punctuation: ";" [90:17 - 90:18] UnexposedStmt=
// CHECK-tokens: Punctuation: "}" [91:3 - 91:4] UnexposedStmt=
-// CHECK-tokens: Identifier: "R" [92:3 - 92:4] CXXMethod=Default:92:5 (Definition)
+// CHECK-tokens: Identifier: "R" [92:3 - 92:4] TypeRef=R:83:33
// CHECK-tokens: Identifier: "Default" [92:5 - 92:12] CXXMethod=Default:92:5 (Definition)
// CHECK-tokens: Punctuation: "(" [92:12 - 92:13] CXXMethod=Default:92:5 (Definition)
// CHECK-tokens: Keyword: "const" [92:13 - 92:18] CXXMethod=Default:92:5 (Definition)
-// CHECK-tokens: Identifier: "T" [92:19 - 92:20] ParmDecl=Value:92:23 (Definition)
+// CHECK-tokens: Identifier: "T" [92:19 - 92:20] TypeRef=T:83:21
// CHECK-tokens: Punctuation: "&" [92:21 - 92:22] ParmDecl=Value:92:23 (Definition)
// CHECK-tokens: Identifier: "Value" [92:23 - 92:28] ParmDecl=Value:92:23 (Definition)
// CHECK-tokens: Punctuation: ")" [92:28 - 92:29] CXXMethod=Default:92:5 (Definition)
@@ -892,9 +892,9 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Keyword: "namespace" [98:7 - 98:16] UsingDirective=:98:17
// CHECK-tokens: Identifier: "clang" [98:17 - 98:22] NamespaceRef=clang:10:17
// CHECK-tokens: Punctuation: ";" [98:22 - 98:23]
-// CHECK-tokens: Identifier: "AttributeList" [100:1 - 100:14] CXXMethod=getKind:100:36 (Definition)
+// CHECK-tokens: Identifier: "AttributeList" [100:1 - 100:14] TypeRef=class clang::AttributeList:12:9
// CHECK-tokens: Punctuation: "::" [100:14 - 100:16] CXXMethod=getKind:100:36 (Definition)
-// CHECK-tokens: Identifier: "Kind" [100:16 - 100:20] CXXMethod=getKind:100:36 (Definition)
+// CHECK-tokens: Identifier: "Kind" [100:16 - 100:20] TypeRef=enum clang::AttributeList::Kind:13:10
// CHECK-tokens: Identifier: "AttributeList" [100:21 - 100:34] TypeRef=class clang::AttributeList:12:9
// CHECK-tokens: Punctuation: "::" [100:34 - 100:36] CXXMethod=getKind:100:36 (Definition)
// CHECK-tokens: Identifier: "getKind" [100:36 - 100:43] CXXMethod=getKind:100:36 (Definition)
@@ -905,9 +905,9 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "Name" [100:67 - 100:71] ParmDecl=Name:100:67 (Definition)
// CHECK-tokens: Punctuation: ")" [100:71 - 100:72] CXXMethod=getKind:100:36 (Definition)
// CHECK-tokens: Punctuation: "{" [100:73 - 100:74] UnexposedStmt=
-// CHECK-tokens: Identifier: "llvm" [101:3 - 101:7] VarDecl=AttrName:101:19 (Definition)
+// CHECK-tokens: Identifier: "llvm" [101:3 - 101:7] NamespaceRef=llvm:82:11
// CHECK-tokens: Punctuation: "::" [101:7 - 101:9] VarDecl=AttrName:101:19 (Definition)
-// CHECK-tokens: Identifier: "StringRef" [101:9 - 101:18] VarDecl=AttrName:101:19 (Definition)
+// CHECK-tokens: Identifier: "StringRef" [101:9 - 101:18] TypeRef=class llvm::StringRef:38:7
// CHECK-tokens: Identifier: "AttrName" [101:19 - 101:27] VarDecl=AttrName:101:19 (Definition)
// CHECK-tokens: Punctuation: "=" [101:28 - 101:29] VarDecl=AttrName:101:19 (Definition)
// CHECK-tokens: Identifier: "Name" [101:30 - 101:34] DeclRefExpr=Name:100:67
@@ -950,13 +950,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [103:54 - 103:55] CallExpr=substr:60:13
// CHECK-tokens: Punctuation: ";" [103:55 - 103:56] UnexposedStmt=
// CHECK-tokens: Keyword: "return" [105:3 - 105:9] UnexposedStmt=
-// CHECK-tokens: Identifier: "llvm" [105:10 - 105:14] UnexposedStmt=
-// CHECK-tokens: Punctuation: "::" [105:14 - 105:16] UnexposedStmt=
+// FIXME: Missing "llvm" namespace reference below
+// CHECK-tokens: Identifier: "llvm" [105:10 - 105:14] NamespaceRef=llvm:82:11
+// CHECK-tokens: Punctuation: "::" [105:14 - 105:16] UnexposedExpr=StringSwitch:87:12
// CHECK-tokens: Identifier: "StringSwitch" [105:16 - 105:28] TemplateRef=StringSwitch:83:47
-// CHECK-tokens: Punctuation: "<" [105:29 - 105:30] CallExpr=StringSwitch:87:12
-// CHECK-tokens: Identifier: "AttributeList" [105:31 - 105:44] CallExpr=StringSwitch:87:12
-// CHECK-tokens: Punctuation: "::" [105:44 - 105:46] CallExpr=StringSwitch:87:12
-// CHECK-tokens: Identifier: "Kind" [105:46 - 105:50] CallExpr=StringSwitch:87:12
+// CHECK-tokens: Punctuation: "<" [105:29 - 105:30] UnexposedExpr=StringSwitch:87:12
+// CHECK-tokens: Identifier: "AttributeList" [105:31 - 105:44] TypeRef=class clang::AttributeList:12:9
+// CHECK-tokens: Punctuation: "::" [105:44 - 105:46] UnexposedExpr=StringSwitch:87:12
+// CHECK-tokens: Identifier: "Kind" [105:46 - 105:50] TypeRef=enum clang::AttributeList::Kind:13:10
// CHECK-tokens: Punctuation: ">" [105:51 - 105:52] CallExpr=StringSwitch:87:12
// CHECK-tokens: Punctuation: "(" [105:53 - 105:54] CallExpr=StringSwitch:87:12
// CHECK-tokens: Identifier: "AttrName" [105:54 - 105:62] DeclRefExpr=AttrName:101:19
@@ -1523,24 +1524,24 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "}" [186:1 - 186:2] UnexposedStmt=
// RUN: c-index-test -test-load-source all %s 2>&1 | FileCheck %s
-// CHECK: 1:27: TypedefDecl=__darwin_size_t:1:27 (Definition) Extent=[1:27 - 1:42]
-// CHECK: 2:25: TypedefDecl=size_t:2:25 (Definition) Extent=[2:25 - 2:31]
+// CHECK: 1:27: TypedefDecl=__darwin_size_t:1:27 (Definition) Extent=[1:1 - 1:42]
+// CHECK: 2:25: TypedefDecl=size_t:2:25 (Definition) Extent=[2:1 - 2:31]
// CHECK: 2:9: TypeRef=__darwin_size_t:1:27 Extent=[2:9 - 2:24]
-// CHECK: 3:11: Namespace=std:3:11 (Definition) Extent=[3:11 - 5:2]
+// CHECK: 3:11: Namespace=std:3:11 (Definition) Extent=[3:1 - 5:2]
// CHECK: 4:44: ClassTemplate=pair:4:44 (Definition) Extent=[4:3 - 4:64]
-// CHECK: 4:20: TemplateTypeParameter=_T1:4:20 (Definition) Extent=[4:20 - 4:23]
-// CHECK: 4:31: TemplateTypeParameter=_T2:4:31 (Definition) Extent=[4:31 - 4:34]
-// CHECK: 4:55: FieldDecl=second:4:55 (Definition) Extent=[4:55 - 4:61]
-// CHECK: 6:8: UnexposedDecl=:6:8 (Definition) Extent=[6:8 - 6:11]
-// CHECK: 7:7: FunctionDecl=memcmp:7:7 Extent=[7:7 - 7:49]
-// CHECK: 7:26: ParmDecl=:7:26 (Definition) Extent=[7:20 - 7:27]
-// CHECK: 7:40: ParmDecl=:7:40 (Definition) Extent=[7:34 - 7:41]
+// CHECK: 4:20: TemplateTypeParameter=_T1:4:20 (Definition) Extent=[4:14 - 4:23]
+// CHECK: 4:31: TemplateTypeParameter=_T2:4:31 (Definition) Extent=[4:25 - 4:34]
+// CHECK: 4:55: FieldDecl=second:4:55 (Definition) Extent=[4:51 - 4:61]
+// CHECK: 6:8: UnexposedDecl=:6:8 (Definition) Extent=[6:1 - 9:2]
+// CHECK: 7:7: FunctionDecl=memcmp:7:7 Extent=[7:3 - 7:49]
+// CHECK: 7:26: ParmDecl=:7:26 (Definition) Extent=[7:14 - 7:27]
+// CHECK: 7:40: ParmDecl=:7:40 (Definition) Extent=[7:28 - 7:41]
// CHECK: 7:48: ParmDecl=:7:48 (Definition) Extent=[7:42 - 7:49]
// CHECK: 7:42: TypeRef=size_t:2:25 Extent=[7:42 - 7:48]
-// CHECK: 8:10: FunctionDecl=strlen:8:10 Extent=[8:10 - 8:30]
+// CHECK: 8:10: FunctionDecl=strlen:8:10 Extent=[8:3 - 8:30]
// CHECK: 8:3: TypeRef=size_t:2:25 Extent=[8:3 - 8:9]
-// CHECK: 8:29: ParmDecl=:8:29 (Definition) Extent=[8:23 - 8:30]
-// CHECK: 10:17: Namespace=clang:10:17 (Definition) Extent=[10:17 - 35:2]
+// CHECK: 8:29: ParmDecl=:8:29 (Definition) Extent=[8:17 - 8:30]
+// CHECK: 10:17: Namespace=clang:10:17 (Definition) Extent=[10:1 - 35:2]
// CHECK: 11:9: ClassDecl=IdentifierInfo:11:9 Extent=[11:3 - 11:23]
// CHECK: 12:9: ClassDecl=AttributeList:12:9 (Definition) Extent=[12:3 - 34:4]
// CHECK: 13:10: EnumDecl=Kind:13:10 (Definition) Extent=[13:5 - 32:6]
@@ -1615,18 +1616,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 30:40: EnumConstantDecl=AT_init_priority:30:40 (Definition) Extent=[30:40 - 30:56]
// CHECK: 31:7: EnumConstantDecl=IgnoredAttribute:31:7 (Definition) Extent=[31:7 - 31:23]
// CHECK: 31:25: EnumConstantDecl=UnknownAttribute:31:25 (Definition) Extent=[31:25 - 31:41]
-// CHECK: 33:17: CXXMethod=getKind:33:17 Extent=[33:17 - 33:53]
+// CHECK: 33:17: CXXMethod=getKind:33:17 Extent=[33:5 - 33:53]
// CHECK: 33:12: TypeRef=enum clang::AttributeList::Kind:13:10 Extent=[33:12 - 33:16]
-// CHECK: 33:48: ParmDecl=Name:33:48 (Definition) Extent=[33:31 - 33:52]
+// CHECK: 33:48: ParmDecl=Name:33:48 (Definition) Extent=[33:25 - 33:52]
// CHECK: 33:31: TypeRef=class clang::IdentifierInfo:66:7 Extent=[33:31 - 33:45]
-// CHECK: 36:8: FunctionDecl=magic_length:36:8 Extent=[36:8 - 36:35]
+// CHECK: 36:8: FunctionDecl=magic_length:36:8 Extent=[36:1 - 36:35]
// CHECK: 36:1: TypeRef=size_t:2:25 Extent=[36:1 - 36:7]
-// CHECK: 36:33: ParmDecl=s:36:33 (Definition) Extent=[36:27 - 36:34]
-// CHECK: 37:11: Namespace=llvm:37:11 (Definition) Extent=[37:11 - 64:2]
+// CHECK: 36:33: ParmDecl=s:36:33 (Definition) Extent=[36:21 - 36:34]
+// CHECK: 37:11: Namespace=llvm:37:11 (Definition) Extent=[37:1 - 64:2]
// CHECK: 38:7: ClassDecl=StringRef:38:7 (Definition) Extent=[38:1 - 63:2]
// CHECK: 39:1: UnexposedDecl=:39:1 (Definition) Extent=[39:1 - 39:8]
-// CHECK: 40:23: TypedefDecl=iterator:40:23 (Definition) Extent=[40:23 - 40:31]
-// CHECK: 41:23: VarDecl=npos:41:23 Extent=[41:16 - 41:40]
+// CHECK: 40:23: TypedefDecl=iterator:40:23 (Definition) Extent=[40:3 - 40:31]
+// CHECK: 41:23: VarDecl=npos:41:23 Extent=[41:3 - 41:40]
// CHECK: 41:16: TypeRef=size_t:2:25 Extent=[41:16 - 41:22]
// CHECK: 41:30: UnexposedExpr= Extent=[41:30 - 41:40]
// CHECK: 41:31: UnexposedExpr= Extent=[41:31 - 41:40]
@@ -1634,10 +1635,10 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 41:38: UnexposedExpr= Extent=[41:38 - 41:39]
// CHECK: 41:38: UnexposedExpr= Extent=[41:38 - 41:39]
// CHECK: 42:1: UnexposedDecl=:42:1 (Definition) Extent=[42:1 - 42:9]
-// CHECK: 43:15: FieldDecl=Data:43:15 (Definition) Extent=[43:15 - 43:19]
-// CHECK: 44:10: FieldDecl=Length:44:10 (Definition) Extent=[44:10 - 44:16]
+// CHECK: 43:15: FieldDecl=Data:43:15 (Definition) Extent=[43:3 - 43:19]
+// CHECK: 44:10: FieldDecl=Length:44:10 (Definition) Extent=[44:3 - 44:16]
// CHECK: 44:3: TypeRef=size_t:2:25 Extent=[44:3 - 44:9]
-// CHECK: 45:17: CXXMethod=min:45:17 (Definition) Extent=[45:17 - 45:66]
+// CHECK: 45:17: CXXMethod=min:45:17 (Definition) Extent=[45:3 - 45:66]
// CHECK: 45:10: TypeRef=size_t:2:25 Extent=[45:10 - 45:16]
// CHECK: 45:28: ParmDecl=a:45:28 (Definition) Extent=[45:21 - 45:29]
// CHECK: 45:21: TypeRef=size_t:2:25 Extent=[45:21 - 45:27]
@@ -1661,7 +1662,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 47:32: UnexposedExpr= Extent=[47:32 - 47:33]
// CHECK: 47:35: UnexposedStmt= Extent=[47:35 - 47:37]
// CHECK: 48:3: CXXConstructor=StringRef:48:3 (Definition) Extent=[48:3 - 48:71]
-// CHECK: 48:25: ParmDecl=Str:48:25 (Definition) Extent=[48:19 - 48:28]
+// CHECK: 48:25: ParmDecl=Str:48:25 (Definition) Extent=[48:13 - 48:28]
// CHECK: 48:32: MemberRef=Data:43:15 Extent=[48:32 - 48:36]
// CHECK: 48:37: DeclRefExpr=Str:48:25 Extent=[48:37 - 48:40]
// CHECK: 48:43: MemberRef=Length:44:10 Extent=[48:43 - 48:49]
@@ -1671,7 +1672,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 48:63: DeclRefExpr=Str:48:25 Extent=[48:63 - 48:66]
// CHECK: 48:69: UnexposedStmt= Extent=[48:69 - 48:71]
// CHECK: 49:3: CXXConstructor=StringRef:49:3 (Definition) Extent=[49:3 - 49:77]
-// CHECK: 49:25: ParmDecl=data:49:25 (Definition) Extent=[49:19 - 49:29]
+// CHECK: 49:25: ParmDecl=data:49:25 (Definition) Extent=[49:13 - 49:29]
// CHECK: 49:38: ParmDecl=length:49:38 (Definition) Extent=[49:31 - 49:44]
// CHECK: 49:31: TypeRef=size_t:2:25 Extent=[49:31 - 49:37]
// CHECK: 49:48: MemberRef=Data:43:15 Extent=[49:48 - 49:52]
@@ -1679,17 +1680,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 49:60: MemberRef=Length:44:10 Extent=[49:60 - 49:66]
// CHECK: 49:67: DeclRefExpr=length:49:38 Extent=[49:67 - 49:73]
// CHECK: 49:75: UnexposedStmt= Extent=[49:75 - 49:77]
-// CHECK: 50:12: CXXMethod=end:50:12 (Definition) Extent=[50:12 - 50:40]
+// CHECK: 50:12: CXXMethod=end:50:12 (Definition) Extent=[50:3 - 50:40]
// CHECK: 50:3: TypeRef=iterator:40:23 Extent=[50:3 - 50:11]
// CHECK: 50:24: UnexposedStmt= Extent=[50:24 - 50:40]
// CHECK: 50:26: UnexposedStmt= Extent=[50:26 - 50:37]
// CHECK: 50:33: MemberRefExpr=Data:43:15 Extent=[50:33 - 50:37]
-// CHECK: 51:10: CXXMethod=size:51:10 (Definition) Extent=[51:10 - 51:41]
+// CHECK: 51:10: CXXMethod=size:51:10 (Definition) Extent=[51:3 - 51:41]
// CHECK: 51:3: TypeRef=size_t:2:25 Extent=[51:3 - 51:9]
// CHECK: 51:23: UnexposedStmt= Extent=[51:23 - 51:41]
// CHECK: 51:25: UnexposedStmt= Extent=[51:25 - 51:38]
// CHECK: 51:32: MemberRefExpr=Length:44:10 Extent=[51:32 - 51:38]
-// CHECK: 52:8: CXXMethod=startswith:52:8 (Definition) Extent=[52:8 - 55:4]
+// CHECK: 52:8: CXXMethod=startswith:52:8 (Definition) Extent=[52:3 - 55:4]
// CHECK: 52:29: ParmDecl=Prefix:52:29 (Definition) Extent=[52:19 - 52:35]
// CHECK: 52:19: TypeRef=class llvm::StringRef:38:7 Extent=[52:19 - 52:28]
// CHECK: 52:43: UnexposedStmt= Extent=[52:43 - 55:4]
@@ -1712,7 +1713,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 54:44: MemberRefExpr=Length:44:10 Extent=[54:37 - 54:50]
// CHECK: 54:37: DeclRefExpr=Prefix:52:29 Extent=[54:37 - 54:43]
// CHECK: 54:55: UnexposedExpr= Extent=[54:55 - 54:56]
-// CHECK: 56:8: CXXMethod=endswith:56:8 (Definition) Extent=[56:8 - 59:4]
+// CHECK: 56:8: CXXMethod=endswith:56:8 (Definition) Extent=[56:3 - 59:4]
// CHECK: 56:27: ParmDecl=Suffix:56:27 (Definition) Extent=[56:17 - 56:33]
// CHECK: 56:17: TypeRef=class llvm::StringRef:38:7 Extent=[56:17 - 56:26]
// CHECK: 56:41: UnexposedStmt= Extent=[56:41 - 59:4]
@@ -1739,7 +1740,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 58:57: MemberRefExpr=Length:44:10 Extent=[58:50 - 58:63]
// CHECK: 58:50: DeclRefExpr=Suffix:56:27 Extent=[58:50 - 58:56]
// CHECK: 58:68: UnexposedExpr= Extent=[58:68 - 58:69]
-// CHECK: 60:13: CXXMethod=substr:60:13 (Definition) Extent=[60:13 - 62:4]
+// CHECK: 60:13: CXXMethod=substr:60:13 (Definition) Extent=[60:3 - 62:4]
// CHECK: 60:3: TypeRef=class llvm::StringRef:38:7 Extent=[60:3 - 60:12]
// CHECK: 60:27: ParmDecl=Start:60:27 (Definition) Extent=[60:20 - 60:32]
// CHECK: 60:20: TypeRef=size_t:2:25 Extent=[60:20 - 60:26]
@@ -1764,14 +1765,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 61:43: UnexposedExpr=Length:44:10 Extent=[61:43 - 61:49]
// CHECK: 61:43: MemberRefExpr=Length:44:10 Extent=[61:43 - 61:49]
// CHECK: 61:52: DeclRefExpr=Start:60:27 Extent=[61:52 - 61:57]
-// CHECK: 65:11: Namespace=clang:65:11 (Definition) Extent=[65:11 - 81:2]
+// CHECK: 65:11: Namespace=clang:65:11 (Definition) Extent=[65:1 - 81:2]
// CHECK: 66:7: ClassDecl=IdentifierInfo:66:7 (Definition) Extent=[66:1 - 80:2]
// CHECK: 67:1: UnexposedDecl=:67:1 (Definition) Extent=[67:1 - 67:8]
// CHECK: 67:8: CXXConstructor=IdentifierInfo:67:8 Extent=[67:8 - 67:24]
-// CHECK: 68:15: CXXMethod=getNameStart:68:15 (Definition) Extent=[68:15 - 71:4]
+// CHECK: 68:15: CXXMethod=getNameStart:68:15 (Definition) Extent=[68:3 - 71:4]
// CHECK: 68:36: UnexposedStmt= Extent=[68:36 - 71:4]
// CHECK: 69:5: UnexposedStmt= Extent=[69:5 - 69:65]
-// CHECK: 69:54: TypedefDecl=actualtype:69:54 (Definition) Extent=[69:54 - 69:64]
+// CHECK: 69:54: TypedefDecl=actualtype:69:54 (Definition) Extent=[69:5 - 69:64]
// CHECK: 69:18: TemplateRef=pair:4:44 Extent=[69:18 - 69:22]
// CHECK: 69:25: TypeRef=class clang::IdentifierInfo:66:7 Extent=[69:25 - 69:39]
// CHECK: 70:5: UnexposedStmt= Extent=[70:5 - 70:47]
@@ -1780,14 +1781,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 70:13: UnexposedExpr= Extent=[70:13 - 70:38]
// CHECK: 70:20: TypeRef=actualtype:69:54 Extent=[70:20 - 70:30]
// CHECK: 70:34: UnexposedExpr= Extent=[70:34 - 70:38]
-// CHECK: 72:12: CXXMethod=getLength:72:12 (Definition) Extent=[72:12 - 76:4]
+// CHECK: 72:12: CXXMethod=getLength:72:12 (Definition) Extent=[72:3 - 76:4]
// CHECK: 72:30: UnexposedStmt= Extent=[72:30 - 76:4]
// CHECK: 73:5: UnexposedStmt= Extent=[73:5 - 73:65]
-// CHECK: 73:54: TypedefDecl=actualtype:73:54 (Definition) Extent=[73:54 - 73:64]
+// CHECK: 73:54: TypedefDecl=actualtype:73:54 (Definition) Extent=[73:5 - 73:64]
// CHECK: 73:18: TemplateRef=pair:4:44 Extent=[73:18 - 73:22]
// CHECK: 73:25: TypeRef=class clang::IdentifierInfo:66:7 Extent=[73:25 - 73:39]
// CHECK: 74:5: UnexposedStmt= Extent=[74:5 - 74:61]
-// CHECK: 74:17: VarDecl=p:74:17 (Definition) Extent=[74:11 - 74:60]
+// CHECK: 74:17: VarDecl=p:74:17 (Definition) Extent=[74:5 - 74:60]
// CHECK: 74:21: UnexposedExpr= Extent=[74:21 - 74:60]
// CHECK: 74:21: UnexposedExpr=second:4:55 Extent=[74:21 - 74:56]
// CHECK: 74:50: MemberRefExpr=second:4:55 Extent=[74:21 - 74:56]
@@ -1819,7 +1820,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 75:55: UnexposedExpr= Extent=[75:55 - 75:56]
// CHECK: 75:61: UnexposedExpr= Extent=[75:61 - 75:62]
// CHECK: 75:61: UnexposedExpr= Extent=[75:61 - 75:62]
-// CHECK: 77:19: CXXMethod=getName:77:19 (Definition) Extent=[77:19 - 79:4]
+// CHECK: 77:19: CXXMethod=getName:77:19 (Definition) Extent=[77:3 - 79:4]
// CHECK: 77:35: UnexposedStmt= Extent=[77:35 - 79:4]
// CHECK: 78:5: UnexposedStmt= Extent=[78:5 - 78:56]
// CHECK: 78:12: CallExpr= Extent=[78:12 - 78:56]
@@ -1830,15 +1831,15 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 78:44: UnexposedExpr=getLength:72:12 Extent=[78:44 - 78:55]
// CHECK: 78:44: CallExpr=getLength:72:12 Extent=[78:44 - 78:55]
// CHECK: 78:44: MemberRefExpr=getLength:72:12 Extent=[78:44 - 78:53]
-// CHECK: 82:11: Namespace=llvm:82:11 (Definition) Extent=[82:11 - 96:2]
+// CHECK: 82:11: Namespace=llvm:82:11 (Definition) Extent=[82:1 - 96:2]
// CHECK: 83:47: ClassTemplate=StringSwitch:83:47 (Definition) Extent=[83:1 - 95:2]
-// CHECK: 83:21: TemplateTypeParameter=T:83:21 (Definition) Extent=[83:21 - 83:22]
-// CHECK: 83:33: TemplateTypeParameter=R:83:33 (Definition) Extent=[83:33 - 83:34]
-// CHECK: 84:13: FieldDecl=Str:84:13 (Definition) Extent=[84:13 - 84:16]
+// CHECK: 83:21: TemplateTypeParameter=T:83:21 (Definition) Extent=[83:12 - 83:22]
+// CHECK: 83:33: TemplateTypeParameter=R:83:33 (Definition) Extent=[83:24 - 83:38]
+// CHECK: 84:13: FieldDecl=Str:84:13 (Definition) Extent=[84:3 - 84:16]
// CHECK: 84:3: TypeRef=class llvm::StringRef:38:7 Extent=[84:3 - 84:12]
-// CHECK: 85:12: FieldDecl=Result:85:12 (Definition) Extent=[85:12 - 85:18]
+// CHECK: 85:12: FieldDecl=Result:85:12 (Definition) Extent=[85:3 - 85:18]
// CHECK: 86:1: UnexposedDecl=:86:1 (Definition) Extent=[86:1 - 86:8]
-// CHECK: 87:12: CXXConstructor=StringSwitch<T, R>:87:12 (Definition) Extent=[87:12 - 87:64]
+// CHECK: 87:12: CXXConstructor=StringSwitch<T, R>:87:12 (Definition) Extent=[87:3 - 87:64]
// CHECK: 87:35: ParmDecl=Str:87:35 (Definition) Extent=[87:25 - 87:38]
// CHECK: 87:25: TypeRef=class llvm::StringRef:38:7 Extent=[87:25 - 87:34]
// CHECK: 87:42: MemberRef=Str:84:13 Extent=[87:42 - 87:45]
@@ -1850,23 +1851,23 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 87:62: UnexposedStmt= Extent=[87:62 - 87:64]
// CHECK: 88:42: FunctionTemplate=Case:88:42 (Definition) Extent=[88:3 - 91:4]
// CHECK: 88:23: NonTypeTemplateParameter=N:88:23 (Definition) Extent=[88:14 - 88:24]
-// CHECK: 88:60: ParmDecl=S:88:60 (Definition) Extent=[88:53 - 88:61]
+// CHECK: 88:60: ParmDecl=S:88:60 (Definition) Extent=[88:47 - 88:65]
// CHECK: 88:63: DeclRefExpr=N:88:23 Extent=[88:63 - 88:64]
-// CHECK: 89:57: ParmDecl=Value:89:57 (Definition) Extent=[89:53 - 89:62]
+// CHECK: 89:57: ParmDecl=Value:89:57 (Definition) Extent=[89:47 - 89:62]
// CHECK: 89:64: UnexposedStmt= Extent=[89:64 - 91:4]
// CHECK: 90:5: UnexposedStmt= Extent=[90:5 - 90:17]
// CHECK: 90:12: UnexposedExpr= Extent=[90:12 - 90:17]
// CHECK: 90:13: UnexposedExpr= Extent=[90:13 - 90:17]
-// CHECK: 92:5: CXXMethod=Default:92:5 (Definition) Extent=[92:5 - 94:4]
-// CHECK: 92:23: ParmDecl=Value:92:23 (Definition) Extent=[92:19 - 92:28]
+// CHECK: 92:5: CXXMethod=Default:92:5 (Definition) Extent=[92:3 - 94:4]
+// CHECK: 92:23: ParmDecl=Value:92:23 (Definition) Extent=[92:13 - 92:28]
// CHECK: 92:36: UnexposedStmt= Extent=[92:36 - 94:4]
// CHECK: 93:5: UnexposedStmt= Extent=[93:5 - 93:17]
// CHECK: 93:12: DeclRefExpr=Value:92:23 Extent=[93:12 - 93:17]
// CHECK: 98:17: UsingDirective=:98:17 Extent=[98:1 - 98:22]
// CHECK: 98:17: NamespaceRef=clang:10:17 Extent=[98:17 - 98:22]
-// CHECK: 100:36: CXXMethod=getKind:100:36 (Definition) Extent=[100:36 - 186:2]
+// CHECK: 100:36: CXXMethod=getKind:100:36 (Definition) Extent=[100:1 - 186:2]
// CHECK: 100:21: TypeRef=class clang::AttributeList:12:9 Extent=[100:21 - 100:34]
-// CHECK: 100:67: ParmDecl=Name:100:67 (Definition) Extent=[100:50 - 100:71]
+// CHECK: 100:67: ParmDecl=Name:100:67 (Definition) Extent=[100:44 - 100:71]
// CHECK: 100:50: TypeRef=class clang::IdentifierInfo:66:7 Extent=[100:50 - 100:64]
// CHECK: 100:73: UnexposedStmt= Extent=[100:73 - 186:2]
// CHECK: 101:3: UnexposedStmt= Extent=[101:3 - 101:46]
@@ -1917,170 +1918,170 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 103:53: UnexposedExpr= Extent=[103:53 - 103:54]
// CHECK: 103:53: UnexposedExpr= Extent=[103:53 - 103:54]
// CHECK: 105:3: UnexposedStmt= Extent=[105:3 - 185:31]
-// CHECK: 105:16: CallExpr=Default:92:5 Extent=[105:16 - 185:31]
-// CHECK: 185:6: MemberRefExpr=Default:92:5 Extent=[105:16 - 185:13]
-// CHECK: 105:16: UnexposedExpr=Case:88:42 Extent=[105:16 - 184:33]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 184:33]
-// CHECK: 184:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 184:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 183:37]
-// CHECK: 183:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 183:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 182:37]
-// CHECK: 182:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 182:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 181:35]
-// CHECK: 181:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 181:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 180:31]
-// CHECK: 180:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 180:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 179:31]
-// CHECK: 179:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 179:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 178:35]
-// CHECK: 178:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 178:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 177:63]
-// CHECK: 177:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 177:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 176:45]
-// CHECK: 176:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 176:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 175:51]
-// CHECK: 175:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 175:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 174:49]
-// CHECK: 174:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 174:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 173:49]
-// CHECK: 173:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 173:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 172:53]
-// CHECK: 172:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 172:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 171:57]
-// CHECK: 171:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 171:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 170:65]
-// CHECK: 170:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 170:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 169:57]
-// CHECK: 169:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 169:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 168:65]
-// CHECK: 168:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 168:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 167:55]
-// CHECK: 167:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 167:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 166:55]
-// CHECK: 166:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 166:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 165:53]
-// CHECK: 165:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 165:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 164:53]
-// CHECK: 164:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 164:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 163:49]
-// CHECK: 163:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 163:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 162:47]
-// CHECK: 162:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 162:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 161:45]
-// CHECK: 161:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 161:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 160:45]
-// CHECK: 160:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 160:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 159:45]
-// CHECK: 159:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 159:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 158:45]
-// CHECK: 158:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 158:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 157:43]
-// CHECK: 157:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 157:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 156:41]
-// CHECK: 156:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 156:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 155:41]
-// CHECK: 155:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 155:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 154:41]
-// CHECK: 154:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 154:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 153:37]
-// CHECK: 153:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 153:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 152:41]
-// CHECK: 152:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 152:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 151:39]
-// CHECK: 151:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 151:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 150:39]
-// CHECK: 150:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 150:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 149:39]
-// CHECK: 149:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 149:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 148:39]
-// CHECK: 148:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 148:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 147:39]
-// CHECK: 147:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 147:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 146:39]
-// CHECK: 146:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 146:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 145:41]
-// CHECK: 145:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 145:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 144:37]
-// CHECK: 144:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 144:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 143:37]
-// CHECK: 143:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 143:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 142:35]
-// CHECK: 142:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 142:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 141:35]
-// CHECK: 141:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 141:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 140:35]
-// CHECK: 140:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 140:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 139:35]
-// CHECK: 139:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 139:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 138:35]
-// CHECK: 138:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 138:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 137:55]
-// CHECK: 137:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 137:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 136:35]
-// CHECK: 136:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 136:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 135:35]
-// CHECK: 135:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 135:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 134:35]
-// CHECK: 134:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 134:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 133:35]
-// CHECK: 133:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 133:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 132:33]
-// CHECK: 132:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 132:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 131:33]
-// CHECK: 131:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 131:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 130:33]
-// CHECK: 130:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 130:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 129:33]
-// CHECK: 129:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 129:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 128:33]
-// CHECK: 128:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 128:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 127:33]
-// CHECK: 127:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 127:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 126:33]
-// CHECK: 126:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 126:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 125:29]
-// CHECK: 125:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 125:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 124:33]
-// CHECK: 124:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 124:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 123:33]
-// CHECK: 123:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 123:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 122:31]
-// CHECK: 122:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 122:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 121:31]
-// CHECK: 121:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 121:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 120:31]
-// CHECK: 120:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 120:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 119:31]
-// CHECK: 119:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 119:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 118:31]
-// CHECK: 118:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 118:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 117:31]
-// CHECK: 117:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 117:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 116:31]
-// CHECK: 116:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 116:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 115:29]
-// CHECK: 115:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 115:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 114:29]
-// CHECK: 114:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 114:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 113:29]
-// CHECK: 113:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 113:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 112:31]
-// CHECK: 112:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 112:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 111:29]
-// CHECK: 111:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 111:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 110:27]
-// CHECK: 110:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 110:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 109:27]
-// CHECK: 109:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 109:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 108:27]
-// CHECK: 108:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 108:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 107:33]
-// CHECK: 107:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 107:10]
-// CHECK: 105:16: CallExpr=Case:88:42 Extent=[105:16 - 106:27]
-// CHECK: 106:6: MemberRefExpr=Case:88:42 Extent=[105:16 - 106:10]
-// CHECK: 105:16: UnexposedExpr=StringSwitch:87:12 Extent=[105:16 - 105:63]
+// CHECK: 105:10: CallExpr=Default:92:5 Extent=[105:10 - 185:31]
+// CHECK: 185:6: MemberRefExpr=Default:92:5 Extent=[105:10 - 185:13]
+// CHECK: 105:10: UnexposedExpr=Case:88:42 Extent=[105:10 - 184:33]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 184:33]
+// CHECK: 184:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 184:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 183:37]
+// CHECK: 183:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 183:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 182:37]
+// CHECK: 182:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 182:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 181:35]
+// CHECK: 181:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 181:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 180:31]
+// CHECK: 180:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 180:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 179:31]
+// CHECK: 179:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 179:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 178:35]
+// CHECK: 178:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 178:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 177:63]
+// CHECK: 177:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 177:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 176:45]
+// CHECK: 176:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 176:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 175:51]
+// CHECK: 175:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 175:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 174:49]
+// CHECK: 174:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 174:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 173:49]
+// CHECK: 173:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 173:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 172:53]
+// CHECK: 172:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 172:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 171:57]
+// CHECK: 171:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 171:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 170:65]
+// CHECK: 170:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 170:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 169:57]
+// CHECK: 169:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 169:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 168:65]
+// CHECK: 168:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 168:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 167:55]
+// CHECK: 167:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 167:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 166:55]
+// CHECK: 166:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 166:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 165:53]
+// CHECK: 165:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 165:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 164:53]
+// CHECK: 164:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 164:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 163:49]
+// CHECK: 163:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 163:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 162:47]
+// CHECK: 162:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 162:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 161:45]
+// CHECK: 161:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 161:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 160:45]
+// CHECK: 160:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 160:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 159:45]
+// CHECK: 159:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 159:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 158:45]
+// CHECK: 158:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 158:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 157:43]
+// CHECK: 157:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 157:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 156:41]
+// CHECK: 156:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 156:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 155:41]
+// CHECK: 155:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 155:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 154:41]
+// CHECK: 154:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 154:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 153:37]
+// CHECK: 153:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 153:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 152:41]
+// CHECK: 152:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 152:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 151:39]
+// CHECK: 151:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 151:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 150:39]
+// CHECK: 150:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 150:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 149:39]
+// CHECK: 149:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 149:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 148:39]
+// CHECK: 148:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 148:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 147:39]
+// CHECK: 147:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 147:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 146:39]
+// CHECK: 146:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 146:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 145:41]
+// CHECK: 145:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 145:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 144:37]
+// CHECK: 144:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 144:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 143:37]
+// CHECK: 143:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 143:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 142:35]
+// CHECK: 142:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 142:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 141:35]
+// CHECK: 141:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 141:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 140:35]
+// CHECK: 140:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 140:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 139:35]
+// CHECK: 139:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 139:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 138:35]
+// CHECK: 138:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 138:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 137:55]
+// CHECK: 137:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 137:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 136:35]
+// CHECK: 136:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 136:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 135:35]
+// CHECK: 135:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 135:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 134:35]
+// CHECK: 134:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 134:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 133:35]
+// CHECK: 133:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 133:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 132:33]
+// CHECK: 132:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 132:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 131:33]
+// CHECK: 131:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 131:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 130:33]
+// CHECK: 130:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 130:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 129:33]
+// CHECK: 129:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 129:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 128:33]
+// CHECK: 128:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 128:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 127:33]
+// CHECK: 127:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 127:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 126:33]
+// CHECK: 126:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 126:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 125:29]
+// CHECK: 125:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 125:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 124:33]
+// CHECK: 124:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 124:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 123:33]
+// CHECK: 123:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 123:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 122:31]
+// CHECK: 122:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 122:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 121:31]
+// CHECK: 121:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 121:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 120:31]
+// CHECK: 120:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 120:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 119:31]
+// CHECK: 119:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 119:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 118:31]
+// CHECK: 118:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 118:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 117:31]
+// CHECK: 117:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 117:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 116:31]
+// CHECK: 116:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 116:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 115:29]
+// CHECK: 115:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 115:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 114:29]
+// CHECK: 114:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 114:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 113:29]
+// CHECK: 113:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 113:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 112:31]
+// CHECK: 112:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 112:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 111:29]
+// CHECK: 111:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 111:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 110:27]
+// CHECK: 110:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 110:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 109:27]
+// CHECK: 109:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 109:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 108:27]
+// CHECK: 108:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 108:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 107:33]
+// CHECK: 107:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 107:10]
+// CHECK: 105:10: CallExpr=Case:88:42 Extent=[105:10 - 106:27]
+// CHECK: 106:6: MemberRefExpr=Case:88:42 Extent=[105:10 - 106:10]
+// CHECK: 105:10: UnexposedExpr=StringSwitch:87:12 Extent=[105:10 - 105:63]
// CHECK: 105:16: TemplateRef=StringSwitch:83:47 Extent=[105:16 - 105:28]
-// CHECK: 105:16: CallExpr=StringSwitch:87:12 Extent=[105:16 - 105:62]
+// CHECK: 105:10: CallExpr=StringSwitch:87:12 Extent=[105:10 - 105:62]
// CHECK: 105:54: CallExpr=StringRef:38:7 Extent=[105:54 - 105:62]
// CHECK: 105:54: UnexposedExpr=AttrName:101:19 Extent=[105:54 - 105:62]
// CHECK: 105:54: DeclRefExpr=AttrName:101:19 Extent=[105:54 - 105:62]
diff --git a/test/Index/recursive-member-access.c b/test/Index/recursive-member-access.c
index c76fa0e50401..87855ca36159 100644
--- a/test/Index/recursive-member-access.c
+++ b/test/Index/recursive-member-access.c
@@ -125,11 +125,11 @@ int test_rdar8650865(struct rdar8650865 *s) {
// RUN: c-index-test -test-load-source all %s | FileCheck %s
// CHECK: 1:8: StructDecl=rdar8650865:1:8 (Definition) Extent=[1:1 - 4:2]
-// CHECK: 2:23: FieldDecl=first:2:23 (Definition) Extent=[2:23 - 2:28]
+// CHECK: 2:23: FieldDecl=first:2:23 (Definition) Extent=[2:3 - 2:28]
// CHECK: 2:10: TypeRef=struct rdar8650865:1:8 Extent=[2:10 - 2:21]
-// CHECK: 3:7: FieldDecl=x:3:7 (Definition) Extent=[3:7 - 3:8]
-// CHECK: 6:5: FunctionDecl=test_rdar8650865:6:5 (Definition) Extent=[6:5 - 124:2]
-// CHECK: 6:42: ParmDecl=s:6:42 (Definition) Extent=[6:29 - 6:43]
+// CHECK: 3:7: FieldDecl=x:3:7 (Definition) Extent=[3:3 - 3:8]
+// CHECK: 6:5: FunctionDecl=test_rdar8650865:6:5 (Definition) Extent=[6:1 - 124:2]
+// CHECK: 6:42: ParmDecl=s:6:42 (Definition) Extent=[6:22 - 6:43]
// CHECK: 6:29: TypeRef=struct rdar8650865:1:8 Extent=[6:29 - 6:40]
// CHECK: 6:45: UnexposedStmt= Extent=[6:45 - 124:2]
// CHECK: 7:3: UnexposedStmt= Extent=[7:3 - 123:8]
@@ -257,7 +257,7 @@ int test_rdar8650865(struct rdar8650865 *s) {
// CHECK-tokens: Keyword: "struct" [1:1 - 1:7] StructDecl=rdar8650865:1:8 (Definition)
// CHECK-tokens: Identifier: "rdar8650865" [1:8 - 1:19] StructDecl=rdar8650865:1:8 (Definition)
// CHECK-tokens: Punctuation: "{" [1:20 - 1:21] StructDecl=rdar8650865:1:8 (Definition)
-// CHECK-tokens: Keyword: "struct" [2:3 - 2:9] StructDecl=rdar8650865:1:8 (Definition)
+// CHECK-tokens: Keyword: "struct" [2:3 - 2:9] FieldDecl=first:2:23 (Definition)
// CHECK-tokens: Identifier: "rdar8650865" [2:10 - 2:21] TypeRef=struct rdar8650865:1:8
// CHECK-tokens: Punctuation: "*" [2:22 - 2:23] FieldDecl=first:2:23 (Definition)
// CHECK-tokens: Identifier: "first" [2:23 - 2:28] FieldDecl=first:2:23 (Definition)
@@ -270,7 +270,7 @@ int test_rdar8650865(struct rdar8650865 *s) {
// CHECK-tokens: Keyword: "int" [6:1 - 6:4] FunctionDecl=test_rdar8650865:6:5 (Definition)
// CHECK-tokens: Identifier: "test_rdar8650865" [6:5 - 6:21] FunctionDecl=test_rdar8650865:6:5 (Definition)
// CHECK-tokens: Punctuation: "(" [6:21 - 6:22] FunctionDecl=test_rdar8650865:6:5 (Definition)
-// CHECK-tokens: Keyword: "struct" [6:22 - 6:28] FunctionDecl=test_rdar8650865:6:5 (Definition)
+// CHECK-tokens: Keyword: "struct" [6:22 - 6:28] ParmDecl=s:6:42 (Definition)
// CHECK-tokens: Identifier: "rdar8650865" [6:29 - 6:40] TypeRef=struct rdar8650865:1:8
// CHECK-tokens: Punctuation: "*" [6:41 - 6:42] ParmDecl=s:6:42 (Definition)
// CHECK-tokens: Identifier: "s" [6:42 - 6:43] ParmDecl=s:6:42 (Definition)
diff --git a/test/Index/remap-load.c b/test/Index/remap-load.c
index d54c3a107682..5a8f46b7f3d8 100644
--- a/test/Index/remap-load.c
+++ b/test/Index/remap-load.c
@@ -1,6 +1,6 @@
// RUN: c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s
-// CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) Extent=[1:5 - 3:2]
+// CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) Extent=[1:1 - 3:2]
// CHECK: remap-load.c:1:13: ParmDecl=parm1:1:13 (Definition) Extent=[1:9 - 1:18]
// CHECK: remap-load.c:1:26: ParmDecl=parm2:1:26 (Definition) Extent=[1:20 - 1:31]
// CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23]
diff --git a/test/Index/usrs-cxx0x.cpp b/test/Index/usrs-cxx0x.cpp
index a0ea6ba69cf0..50aee0968867 100644
--- a/test/Index/usrs-cxx0x.cpp
+++ b/test/Index/usrs-cxx0x.cpp
@@ -5,4 +5,4 @@ void f(tuple<int, float, double>);
// RUN: c-index-test -test-load-source-usrs all -std=c++0x %s | FileCheck %s
// CHECK: usrs-cxx0x.cpp c:@ST>1#pT@tuple Extent=[1:1 - 2:17]
-// CHECK: usrs-cxx0x.cpp c:@F@f#$@S@tuple>#p3Ifd# Extent=[4:6 - 4:34]
+// CHECK: usrs-cxx0x.cpp c:@F@f#$@S@tuple>#p3Ifd# Extent=[4:1 - 4:34]
diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp
index 698aded84381..a43b6893ebfb 100644
--- a/test/Index/usrs.cpp
+++ b/test/Index/usrs.cpp
@@ -66,55 +66,55 @@ using foo::ClsB;
namespace foo_alias3 = foo;
// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
-// CHECK: usrs.cpp c:@N@foo Extent=[1:11 - 4:2]
+// CHECK: usrs.cpp c:@N@foo Extent=[1:1 - 4:2]
// CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8]
-// CHECK: usrs.cpp c:@N@foo@F@bar#I# Extent=[3:8 - 3:18]
+// CHECK: usrs.cpp c:@N@foo@F@bar#I# Extent=[3:3 - 3:18]
// CHECK: usrs.cpp c:usrs.cpp@36@N@foo@F@bar#I#@z Extent=[3:12 - 3:17]
-// CHECK: usrs.cpp c:@N@bar Extent=[5:11 - 8:2]
-// CHECK: usrs.cpp c:usrs.cpp@76@N@bar@T@QType Extent=[6:15 - 6:20]
-// CHECK: usrs.cpp c:@N@bar@F@bar#I# Extent=[7:8 - 7:20]
+// CHECK: usrs.cpp c:@N@bar Extent=[5:1 - 8:2]
+// CHECK: usrs.cpp c:usrs.cpp@64@N@bar@T@QType Extent=[6:3 - 6:20]
+// CHECK: usrs.cpp c:@N@bar@F@bar#I# Extent=[7:3 - 7:20]
// CHECK: usrs.cpp c:usrs.cpp@94@N@bar@F@bar#I#@z Extent=[7:12 - 7:19]
// CHECK: usrs.cpp c:@C@ClsA Extent=[10:1 - 14:2]
// CHECK: usrs.cpp c: Extent=[11:1 - 11:8]
-// CHECK: usrs.cpp c:@C@ClsA@FI@a Extent=[12:7 - 12:8]
-// CHECK: usrs.cpp c:@C@ClsA@FI@b Extent=[12:10 - 12:11]
+// CHECK: usrs.cpp c:@C@ClsA@FI@a Extent=[12:3 - 12:8]
+// CHECK: usrs.cpp c:@C@ClsA@FI@b Extent=[12:3 - 12:11]
// CHECK: usrs.cpp c:@C@ClsA@F@ClsA#I#I# Extent=[13:3 - 13:37]
// CHECK: usrs.cpp c:usrs.cpp@147@C@ClsA@F@ClsA#I#I#@A Extent=[13:8 - 13:13]
// CHECK: usrs.cpp c:usrs.cpp@154@C@ClsA@F@ClsA#I#I#@B Extent=[13:15 - 13:20]
-// CHECK: usrs.cpp c:@N@foo Extent=[16:11 - 22:2]
+// CHECK: usrs.cpp c:@N@foo Extent=[16:1 - 22:2]
// CHECK: usrs.cpp c:@N@foo@C@ClsB Extent=[17:3 - 21:4]
// CHECK: usrs.cpp c: Extent=[18:3 - 18:10]
// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@ClsB# Extent=[19:5 - 19:27]
-// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[20:9 - 20:17]
-// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[24:16 - 26:2]
+// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[20:5 - 20:23]
+// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[24:1 - 26:2]
// CHECK: usrs.cpp c:@aN@C@ClsC Extent=[29:3 - 29:35]
// CHECK: usrs.cpp c:@aN@w Extent=[30:3 - 30:8]
// CHECK: usrs.cpp c:@z Extent=[33:1 - 33:6]
-// CHECK: usrs.cpp c:@N@foo Extent=[35:11 - 40:2]
-// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[35:27 - 39:2]
+// CHECK: usrs.cpp c:@N@foo Extent=[35:1 - 40:2]
+// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[35:17 - 39:2]
// CHECK: usrs.cpp c:@N@foo@N@taz@x Extent=[36:3 - 36:8]
-// CHECK: usrs.cpp c:usrs.cpp@475@N@foo@N@taz@F@add#I#I# Extent=[37:21 - 37:56]
+// CHECK: usrs.cpp c:usrs.cpp@457@N@foo@N@taz@F@add#I#I# Extent=[37:3 - 37:56]
// CHECK: usrs.cpp c:usrs.cpp@479@N@foo@N@taz@F@add#I#I#@a Extent=[37:25 - 37:30]
// CHECK: usrs.cpp c:usrs.cpp@486@N@foo@N@taz@F@add#I#I#@b Extent=[37:32 - 37:37]
-// CHECK: usrs.cpp c:@N@foo@N@taz@F@sub#I#I# Extent=[38:8 - 38:25]
+// CHECK: usrs.cpp c:@N@foo@N@taz@F@sub#I#I# Extent=[38:3 - 38:25]
// CHECK: usrs.cpp c:usrs.cpp@522@N@foo@N@taz@F@sub#I#I#@a Extent=[38:12 - 38:17]
// CHECK: usrs.cpp c:usrs.cpp@529@N@foo@N@taz@F@sub#I#I#@b Extent=[38:19 - 38:24]
-// CHECK: usrs.cpp c:@N@foo Extent=[42:11 - 52:3]
-// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[42:27 - 52:2]
+// CHECK: usrs.cpp c:@N@foo Extent=[42:1 - 52:3]
+// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[42:17 - 52:2]
// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD Extent=[43:3 - 51:4]
// CHECK: usrs.cpp c: Extent=[44:3 - 44:10]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#I# Extent=[45:11 - 45:52]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#I# Extent=[45:5 - 45:52]
// CHECK: usrs.cpp c:usrs.cpp@638@N@foo@N@taz@C@ClsD@F@operator=#I#@x Extent=[45:21 - 45:26]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#d# Extent=[46:11 - 46:61]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#d# Extent=[46:5 - 46:61]
// CHECK: usrs.cpp c:usrs.cpp@690@N@foo@N@taz@C@ClsD@F@operator=#d#@x Extent=[46:21 - 46:29]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD# Extent=[47:11 - 47:62]
-// CHECK: usrs.cpp c:usrs.cpp@757@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD#@x Extent=[47:27 - 47:34]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@qux#S Extent=[48:16 - 48:21]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@uz#I.#S Extent=[49:16 - 49:30]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD# Extent=[47:5 - 47:62]
+// CHECK: usrs.cpp c:usrs.cpp@751@N@foo@N@taz@C@ClsD@F@operator=#&1$@N@foo@N@taz@C@ClsD#@x Extent=[47:21 - 47:34]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@qux#S Extent=[48:5 - 48:21]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@uz#I.#S Extent=[49:5 - 49:30]
// CHECK: usrs.cpp c:usrs.cpp@833@N@foo@N@taz@C@ClsD@F@uz#I.#S@z Extent=[49:19 - 49:24]
-// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1 Extent=[50:10 - 50:62]
-// CHECK: usrs.cpp c:usrs.cpp@872@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1@x Extent=[50:27 - 50:34]
-// CHECK: usrs.cpp c:@F@rez Extent=[55:8 - 55:25]
+// CHECK: usrs.cpp c:@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1 Extent=[50:5 - 50:62]
+// CHECK: usrs.cpp c:usrs.cpp@866@N@foo@N@taz@C@ClsD@F@operator==#&1$@N@foo@N@taz@C@ClsD#1@x Extent=[50:21 - 50:34]
+// CHECK: usrs.cpp c:@F@rez Extent=[55:3 - 55:25]
// CHECK: usrs.cpp c:usrs.cpp@941@F@rez@a Extent=[55:12 - 55:17]
// CHECK: usrs.cpp c:usrs.cpp@948@F@rez@b Extent=[55:19 - 55:24]
// CHECK: usrs.cpp c:@NA@foo_alias
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index edfb81437d87..4b79fdcbba8d 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -80,7 +80,7 @@ int test_multi_declaration(void) {
- (void)method;
@end
-// CHECK: usrs.m c:usrs.m@85@F@my_helper Extent=[3:19 - 3:60]
+// CHECK: usrs.m c:usrs.m@67@F@my_helper Extent=[3:1 - 3:60]
// CHECK: usrs.m c:usrs.m@95@F@my_helper@x Extent=[3:29 - 3:34]
// CHECK: usrs.m c:usrs.m@102@F@my_helper@y Extent=[3:36 - 3:41]
// CHECK: usrs.m c:usrs.m@128@Ea Extent=[5:1 - 8:2]
@@ -90,15 +90,15 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:usrs.m@155@Ea@FOO Extent=[11:3 - 11:6]
// CHECK: usrs.m c:usrs.m@155@Ea@BAR Extent=[12:3 - 12:6]
// CHECK: usrs.m c:@SA@MyStruct Extent=[15:9 - 18:2]
-// CHECK: usrs.m c:@SA@MyStruct@FI@wa Extent=[16:7 - 16:9]
-// CHECK: usrs.m c:@SA@MyStruct@FI@moo Extent=[17:7 - 17:10]
-// CHECK: usrs.m c:usrs.m@219@T@MyStruct Extent=[18:3 - 18:11]
+// CHECK: usrs.m c:@SA@MyStruct@FI@wa Extent=[16:3 - 16:9]
+// CHECK: usrs.m c:@SA@MyStruct@FI@moo Extent=[17:3 - 17:10]
+// CHECK: usrs.m c:usrs.m@179@T@MyStruct Extent=[15:1 - 18:11]
// CHECK: usrs.m c:@E@Pizza Extent=[20:1 - 23:2]
// CHECK: usrs.m c:@E@Pizza@CHEESE Extent=[21:3 - 21:9]
// CHECK: usrs.m c:@E@Pizza@MUSHROOMS Extent=[22:3 - 22:12]
// CHECK: usrs.m c:objc(cs)Foo Extent=[25:1 - 32:5]
-// CHECK: usrs.m c:objc(cs)Foo@x Extent=[26:6 - 26:7]
-// CHECK: usrs.m c:objc(cs)Foo@y Extent=[27:6 - 27:7]
+// CHECK: usrs.m c:objc(cs)Foo@x Extent=[26:3 - 26:7]
+// CHECK: usrs.m c:objc(cs)Foo@y Extent=[27:3 - 27:7]
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[29:1 - 29:17]
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[30:1 - 30:17]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[31:1 - 31:17]
@@ -107,14 +107,14 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:usrs.m@352objc(cs)Foo(im)setD1:@d1 Extent=[31:15 - 31:17]
// CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2]
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2]
-// CHECK: usrs.m c:usrs.m@409objc(cs)Foo(im)godzilla@a Extent=[36:10 - 36:19]
-// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@z Extent=[37:10 - 37:15]
+// CHECK: usrs.m c:usrs.m@402objc(cs)Foo(im)godzilla@a Extent=[36:3 - 36:19]
+// CHECK: usrs.m c:objc(cs)Foo(im)godzilla@z Extent=[37:3 - 37:15]
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2]
// CHECK: usrs.m c:usrs.m@470objc(cs)Foo(cm)kingkong@local_var Extent=[41:3 - 41:16]
// CHECK: usrs.m c:objc(cs)Foo@d1 Extent=[44:13 - 44:15]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
// CHECK: usrs.m c:@z Extent=[47:1 - 47:6]
-// CHECK: usrs.m c:usrs.m@540@F@local_func Extent=[49:12 - 49:43]
+// CHECK: usrs.m c:usrs.m@529@F@local_func Extent=[49:1 - 49:43]
// CHECK: usrs.m c:usrs.m@551@F@local_func@x Extent=[49:23 - 49:28]
// CHECK: usrs.m c:objc(cs)CWithExt Extent=[51:1 - 53:5]
// CHECK: usrs.m c:objc(cs)CWithExt(im)meth1 Extent=[52:1 - 52:14]
@@ -130,8 +130,8 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:objc(cs)CWithExt(im)meth3 Extent=[66:1 - 66:27]
// CHECK: usrs.m c:objc(cy)CWithExt@Bar Extent=[68:1 - 70:2]
// CHECK: usrs.m c:objc(cs)CWithExt(im)meth4 Extent=[69:1 - 69:27]
-// CHECK: usrs.m c:@F@aux_1 Extent=[72:6 - 72:26]
-// CHECK: usrs.m c:@F@test_multi_declaration Extent=[73:5 - 77:2]
+// CHECK: usrs.m c:@F@aux_1 Extent=[72:1 - 72:26]
+// CHECK: usrs.m c:@F@test_multi_declaration Extent=[73:1 - 77:2]
// CHECK: usrs.m c:usrs.m@980@F@test_multi_declaration@foo Extent=[74:3 - 74:14]
// CHECK: usrs.m c:usrs.m@980@F@test_multi_declaration@bar Extent=[74:16 - 74:23]
// CHECK: usrs.m c:usrs.m@980@F@test_multi_declaration@baz Extent=[74:25 - 74:32]
@@ -139,7 +139,7 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:objc(pl)P1(im)method Extent=[80:1 - 80:16]
// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-source %s
-// CHECK-source: usrs.m:3:19: FunctionDecl=my_helper:3:19 (Definition) Extent=[3:19 - 3:60]
+// CHECK-source: usrs.m:3:19: FunctionDecl=my_helper:3:19 (Definition) Extent=[3:1 - 3:60]
// CHECK-source: usrs.m:3:33: ParmDecl=x:3:33 (Definition) Extent=[3:29 - 3:34]
// CHECK-source: usrs.m:3:40: ParmDecl=y:3:40 (Definition) Extent=[3:36 - 3:41]
// CHECK-source: usrs.m:3:43: UnexposedStmt= Extent=[3:43 - 3:60]
@@ -154,17 +154,17 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:11:3: EnumConstantDecl=FOO:11:3 (Definition) Extent=[11:3 - 11:6]
// CHECK-source: usrs.m:12:3: EnumConstantDecl=BAR:12:3 (Definition) Extent=[12:3 - 12:6]
// CHECK-source: usrs.m:15:9: StructDecl=:15:9 (Definition) Extent=[15:9 - 18:2]
-// CHECK-source: usrs.m:16:7: FieldDecl=wa:16:7 (Definition) Extent=[16:7 - 16:9]
-// CHECK-source: usrs.m:17:7: FieldDecl=moo:17:7 (Definition) Extent=[17:7 - 17:10]
-// CHECK-source: usrs.m:18:3: TypedefDecl=MyStruct:18:3 (Definition) Extent=[18:3 - 18:11]
+// CHECK-source: usrs.m:16:7: FieldDecl=wa:16:7 (Definition) Extent=[16:3 - 16:9]
+// CHECK-source: usrs.m:17:7: FieldDecl=moo:17:7 (Definition) Extent=[17:3 - 17:10]
+// CHECK-source: usrs.m:18:3: TypedefDecl=MyStruct:18:3 (Definition) Extent=[15:1 - 18:11]
// CHECK-source: usrs.m:15:9: TypeRef=MyStruct:15:9 Extent=[15:9 - 15:15]
// CHECK-source: usrs.m:20:6: EnumDecl=Pizza:20:6 (Definition) Extent=[20:1 - 23:2]
// CHECK-source: usrs.m:21:3: EnumConstantDecl=CHEESE:21:3 (Definition) Extent=[21:3 - 21:9]
// CHECK-source: usrs.m:22:3: EnumConstantDecl=MUSHROOMS:22:3 (Definition) Extent=[22:3 - 22:12]
// CHECK-source: usrs.m:25:12: ObjCInterfaceDecl=Foo:25:12 Extent=[25:1 - 32:5]
-// CHECK-source: usrs.m:26:6: ObjCIvarDecl=x:26:6 (Definition) Extent=[26:6 - 26:7]
+// CHECK-source: usrs.m:26:6: ObjCIvarDecl=x:26:6 (Definition) Extent=[26:3 - 26:7]
// CHECK-source: usrs.m:26:3: TypeRef=id:0:0 Extent=[26:3 - 26:5]
-// CHECK-source: usrs.m:27:6: ObjCIvarDecl=y:27:6 (Definition) Extent=[27:6 - 27:7]
+// CHECK-source: usrs.m:27:6: ObjCIvarDecl=y:27:6 (Definition) Extent=[27:3 - 27:7]
// CHECK-source: usrs.m:27:3: TypeRef=id:0:0 Extent=[27:3 - 27:5]
// CHECK-source: usrs.m:29:1: ObjCInstanceMethodDecl=godzilla:29:1 Extent=[29:1 - 29:17]
// CHECK-source: usrs.m:29:4: TypeRef=id:0:0 Extent=[29:4 - 29:6]
@@ -179,10 +179,10 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:35:4: TypeRef=id:0:0 Extent=[35:4 - 35:6]
// CHECK-source: usrs.m:35:17: UnexposedStmt= Extent=[35:17 - 39:2]
// CHECK-source: usrs.m:36:3: UnexposedStmt= Extent=[36:3 - 36:20]
-// CHECK-source: usrs.m:36:14: VarDecl=a:36:14 (Definition) Extent=[36:10 - 36:19]
+// CHECK-source: usrs.m:36:14: VarDecl=a:36:14 (Definition) Extent=[36:3 - 36:19]
// CHECK-source: usrs.m:36:18: UnexposedExpr= Extent=[36:18 - 36:19]
// CHECK-source: usrs.m:37:3: UnexposedStmt= Extent=[37:3 - 37:16]
-// CHECK-source: usrs.m:37:14: VarDecl=z:37:14 Extent=[37:10 - 37:15]
+// CHECK-source: usrs.m:37:14: VarDecl=z:37:14 Extent=[37:3 - 37:15]
// CHECK-source: usrs.m:38:3: UnexposedStmt= Extent=[38:3 - 38:11]
// CHECK-source: usrs.m:38:10: UnexposedExpr= Extent=[38:10 - 38:11]
// CHECK-source: usrs.m:38:10: UnexposedExpr= Extent=[38:10 - 38:11]
@@ -197,7 +197,7 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:44:13: ObjCIvarDecl=d1:44:13 (Definition) Extent=[44:13 - 44:15]
// CHECK-source: usrs.m:44:13: UnexposedDecl=d1:31:15 (Definition) Extent=[44:1 - 44:15]
// CHECK-source: usrs.m:47:5: VarDecl=z:47:5 Extent=[47:1 - 47:6]
-// CHECK-source: usrs.m:49:12: FunctionDecl=local_func:49:12 (Definition) Extent=[49:12 - 49:43]
+// CHECK-source: usrs.m:49:12: FunctionDecl=local_func:49:12 (Definition) Extent=[49:1 - 49:43]
// CHECK-source: usrs.m:49:27: ParmDecl=x:49:27 (Definition) Extent=[49:23 - 49:28]
// CHECK-source: usrs.m:49:30: UnexposedStmt= Extent=[49:30 - 49:43]
// CHECK-source: usrs.m:49:32: UnexposedStmt= Extent=[49:32 - 49:40]
@@ -244,11 +244,11 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:69:16: UnexposedStmt= Extent=[69:16 - 69:24]
// CHECK-source: usrs.m:69:23: UnexposedExpr= Extent=[69:23 - 69:24]
// CHECK-source: usrs.m:69:23: UnexposedExpr= Extent=[69:23 - 69:24]
-// CHECK-source: usrs.m:72:6: FunctionDecl=aux_1:72:6 Extent=[72:6 - 72:26]
+// CHECK-source: usrs.m:72:6: FunctionDecl=aux_1:72:6 Extent=[72:1 - 72:26]
// CHECK-source: usrs.m:72:15: ParmDecl=:72:15 (Definition) Extent=[72:12 - 72:16]
// CHECK-source: usrs.m:72:20: ParmDecl=:72:20 (Definition) Extent=[72:17 - 72:21]
// CHECK-source: usrs.m:72:25: ParmDecl=:72:25 (Definition) Extent=[72:22 - 72:26]
-// CHECK-source: usrs.m:73:5: FunctionDecl=test_multi_declaration:73:5 (Definition) Extent=[73:5 - 77:2]
+// CHECK-source: usrs.m:73:5: FunctionDecl=test_multi_declaration:73:5 (Definition) Extent=[73:1 - 77:2]
// CHECK-source: usrs.m:73:34: UnexposedStmt= Extent=[73:34 - 77:2]
// CHECK-source: usrs.m:74:3: UnexposedStmt= Extent=[74:3 - 74:33]
// CHECK-source: usrs.m:74:7: VarDecl=foo:74:7 (Definition) Extent=[74:3 - 74:14]
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index 07a3ebd38d3a..57949e301773 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -41,6 +41,16 @@ int no_auto_type();
// CHECK-NO-0X: no_auto_type
+#if __has_feature(cxx_trailing_return)
+int has_trailing_return();
+#else
+int no_trailing_return();
+#endif
+
+// CHECK-0X: has_trailing_return
+// CHECK-NO-0X: no_trailing_return
+
+
#if __has_feature(cxx_attributes)
int has_attributes();
#else
@@ -99,6 +109,17 @@ int no_inline_namespaces();
// CHECK-0X: has_inline_namespaces
// CHECK-NO-0X: no_inline_namespaces
+
+#if __has_feature(cxx_range_for)
+int has_range_for();
+#else
+int no_range_for();
+#endif
+
+// CHECK-0X: has_range_for
+// CHECK-NO-0X: no_range_for
+
+
#if __has_feature(cxx_reference_qualified_functions)
int has_reference_qualified_functions();
#else
@@ -117,3 +138,20 @@ int no_default_function_template_args();
// CHECK-0X: has_default_function_template_args
// CHECK-NO-0X: no_default_function_template_args
+#if __has_feature(cxx_noexcept)
+int has_noexcept();
+#else
+int no_noexcept();
+#endif
+
+// CHECK-0X: has_noexcept
+// CHECK-NO-0X: no_noexcept
+
+#if __has_feature(cxx_override_control)
+int has_override_control();
+#else
+int no_override_control();
+#endif
+
+// CHECK-0X: has_override_control
+// CHECK-NO-0X: no_override_control
diff --git a/test/Lexer/pragma-message.c b/test/Lexer/pragma-message.c
index 710568cc2de6..807edda66a0c 100644
--- a/test/Lexer/pragma-message.c
+++ b/test/Lexer/pragma-message.c
@@ -7,7 +7,7 @@
// OR
// #pragma message messagestring
//
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Werror %s
#define STRING2(x) #x
#define STRING(x) STRING2(x)
#pragma message(":O I'm a message! " STRING(__LINE__)) // expected-warning {{:O I'm a message! 13}}
diff --git a/test/Makefile b/test/Makefile
index b0c829c255e6..050c3a51ddec 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -38,30 +38,32 @@ FORCE:
lit.site.cfg: FORCE
@echo "Making Clang 'lit.site.cfg' file..."
- @sed -e "s#@LLVM_SOURCE_DIR@#$(LLVM_SRC_ROOT)#g" \
- -e "s#@LLVM_BINARY_DIR@#$(LLVM_OBJ_ROOT)#g" \
- -e "s#@LLVM_TOOLS_DIR@#$(ToolDir)#g" \
- -e "s#@LLVM_LIBS_DIR@#$(LibDir)#g" \
- -e "s#@CLANG_SOURCE_DIR@#$(PROJ_SRC_DIR)/..#g" \
- -e "s#@CLANG_BINARY_DIR@#$(PROJ_OBJ_DIR)/..#g" \
- -e "s#@TARGET_TRIPLE@#$(TARGET_TRIPLE)#g" \
- $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
+ @$(ECHOPATH) s=@LLVM_SOURCE_DIR@=$(LLVM_SRC_ROOT)=g > lit.tmp
+ @$(ECHOPATH) s=@LLVM_BINARY_DIR@=$(LLVM_OBJ_ROOT)=g >> lit.tmp
+ @$(ECHOPATH) s=@LLVM_TOOLS_DIR@=$(ToolDir)=g >> lit.tmp
+ @$(ECHOPATH) s=@LLVM_LIBS_DIR@=$(LibDir)=g >> lit.tmp
+ @$(ECHOPATH) s=@CLANG_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> lit.tmp
+ @$(ECHOPATH) s=@CLANG_BINARY_DIR@=$(PROJ_OBJ_DIR)/..=g >> lit.tmp
+ @$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> lit.tmp
+ @sed -f lit.tmp $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
+ @-rm -f lit.tmp
Unit/lit.site.cfg: FORCE
@echo "Making Clang 'Unit/lit.site.cfg' file..."
@$(MKDIR) $(dir $@)
- @sed -e "s#@LLVM_SOURCE_DIR@#$(LLVM_SRC_ROOT)#g" \
- -e "s#@LLVM_BINARY_DIR@#$(LLVM_OBJ_ROOT)#g" \
- -e "s#@LLVM_TOOLS_DIR@#$(ToolDir)#g" \
- -e "s#@LLVM_LIBS_DIR@#$(LibDir)#g" \
- -e "s#@CLANG_SOURCE_DIR@#$(PROJ_SRC_DIR)/..#g" \
- -e "s#@CLANG_BINARY_DIR@#$(PROJ_OBJ_DIR)/..#g" \
- -e "s#@TARGET_TRIPLE@#$(TARGET_TRIPLE)#g" \
- -e "s#@LLVM_BUILD_MODE@#$(BuildMode)#g" \
- -e "s#@ENABLE_SHARED@#$(ENABLE_SHARED)#g" \
- -e "s#@SHLIBDIR@#$(SharedLibDir)#g" \
- -e "s#@SHLIBPATH_VAR@#$(SHLIBPATH_VAR)#g" \
- $(PROJ_SRC_DIR)/Unit/lit.site.cfg.in > $@
+ @$(ECHOPATH) s=@LLVM_SOURCE_DIR@=$(LLVM_SRC_ROOT)=g > unit.tmp
+ @$(ECHOPATH) s=@LLVM_BINARY_DIR@=$(LLVM_OBJ_ROOT)=g >> unit.tmp
+ @$(ECHOPATH) s=@LLVM_TOOLS_DIR@=$(ToolDir)=g >> unit.tmp
+ @$(ECHOPATH) s=@LLVM_LIBS_DIR@=$(LibDir)=g >> unit.tmp
+ @$(ECHOPATH) s=@CLANG_SOURCE_DIR@=$(PROJ_SRC_DIR)/..=g >> unit.tmp
+ @$(ECHOPATH) s=@CLANG_BINARY_DIR@=$(PROJ_OBJ_DIR)/..=g >> unit.tmp
+ @$(ECHOPATH) s=@TARGET_TRIPLE@=$(TARGET_TRIPLE)=g >> unit.tmp
+ @$(ECHOPATH) s=@LLVM_BUILD_MODE@=$(BuildMode)=g >> unit.tmp
+ @$(ECHOPATH) s=@ENABLE_SHARED@=$(ENABLE_SHARED)=g >> unit.tmp
+ @$(ECHOPATH) s=@SHLIBDIR@=$(SharedLibDir)=g >> unit.tmp
+ @$(ECHOPATH) s=@SHLIBPATH_VAR@=$(SHLIBPATH_VAR)=g >> unit.tmp
+ @sed -f unit.tmp $(PROJ_SRC_DIR)/Unit/lit.site.cfg.in > $@
+ @-rm -f unit.tmp
clean::
@ find . -name Output | xargs rm -fr
diff --git a/test/Misc/Inputs/include.h b/test/Misc/Inputs/include.h
new file mode 100644
index 000000000000..d325775691de
--- /dev/null
+++ b/test/Misc/Inputs/include.h
@@ -0,0 +1 @@
+int foo(int x) { return x; }
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index e138f59d608c..e45ad2a60518 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -1,27 +1,24 @@
-// RUN: %clang_cc1 -fsyntax-only %s > %t 2>&1
+// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
#define M1(x) x
-
-// RUN: grep ":6:12: note: instantiated from:" %t
#define M2 1;
-
void foo() {
- // RUN: grep ":10:2: warning: expression result unused" %t
- M1(
- // RUN: grep ":12:5: note: instantiated from:" %t
- M2)
+ M1(
+ M2);
+ // CHECK: {{.*}}:6:{{[0-9]+}}: warning: expression result unused
+ // CHECK: {{.*}}:7:{{[0-9]+}}: note: instantiated from:
+ // CHECK: {{.*}}:4:{{[0-9]+}}: note: instantiated from:
}
-// RUN: grep ":16:11: note: instantiated from:" %t
#define A 1
-// RUN: grep ":18:11: note: instantiated from:" %t
#define B A
-// RUN: grep ":20:11: note: instantiated from:" %t
#define C B
-
void bar() {
- // RUN: grep ":24:3: warning: expression result unused" %t
C;
+ // CHECK: {{.*}}:17:{{[0-9]+}}: warning: expression result unused
+ // CHECK: {{.*}}:15:{{[0-9]+}}: note: instantiated from:
+ // CHECK: {{.*}}:14:{{[0-9]+}}: note: instantiated from:
+ // CHECK: {{.*}}:13:{{[0-9]+}}: note: instantiated from:
}
diff --git a/test/Misc/include-stack-for-note-flag.cpp b/test/Misc/include-stack-for-note-flag.cpp
new file mode 100644
index 000000000000..f8d0080f57ac
--- /dev/null
+++ b/test/Misc/include-stack-for-note-flag.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACK
+// RUN: %clang_cc1 -fsyntax-only -fno-diagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
+// RUN: %clang_cc1 -fsyntax-only -fno-diagnostics-show-note-include-stack -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACK
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack -fno-diagnostics-show-note-include-stack %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
+// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s -check-prefix=STACKLESS
+
+#include "Inputs/include.h"
+int test() {
+ return foo(1, 1);
+}
+
+// STACK: error: no matching function for call to 'foo'
+// STACK: In file included from
+// STACK: note: candidate function not viable
+
+// STACKLESS: error: no matching function for call to 'foo'
+// STACKLESS-NOT: In file included from
+// STACKLESS: note: candidate function not viable
diff --git a/test/Misc/warn-in-system-header.c b/test/Misc/warn-in-system-header.c
new file mode 100644
index 000000000000..7e4615e65efa
--- /dev/null
+++ b/test/Misc/warn-in-system-header.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -isystem %S %s -fsyntax-only -verify
+
+#include <warn-in-system-header.h>
+// expected-warning {{#warning}}
diff --git a/test/Misc/warn-in-system-header.h b/test/Misc/warn-in-system-header.h
new file mode 100644
index 000000000000..5e127b9d3fc8
--- /dev/null
+++ b/test/Misc/warn-in-system-header.h
@@ -0,0 +1,4 @@
+
+
+
+#warning the cake is a lie
diff --git a/test/PCH/Inputs/working-directory-1.h b/test/PCH/Inputs/working-directory-1.h
new file mode 100644
index 000000000000..e42eda45c87f
--- /dev/null
+++ b/test/PCH/Inputs/working-directory-1.h
@@ -0,0 +1,5 @@
+template<typename T> struct A {
+ A() {
+ int a;
+ }
+};
diff --git a/test/PCH/chain-cxx.cpp b/test/PCH/chain-cxx.cpp
index d269de529fba..af0a23afea9f 100644
--- a/test/PCH/chain-cxx.cpp
+++ b/test/PCH/chain-cxx.cpp
@@ -4,9 +4,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify -include %s -include %s %s
// With PCH
-// RUN: %clang_cc1 -x c++-header -emit-pch -o %t1 %s
-// RUN: %clang_cc1 -x c++-header -emit-pch -o %t2 %s -include-pch %t1 -chained-pch
-// RUN: %clang_cc1 -fsyntax-only -verify -include-pch %t2 %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s
#ifndef HEADER1
#define HEADER1
@@ -34,9 +32,26 @@ struct S<T *> { typedef int H; };
template <typename T> struct TS2;
typedef TS2<int> TS2int;
+template <typename T> struct TestBaseSpecifiers { };
+template<typename T> struct TestBaseSpecifiers2 : TestBaseSpecifiers<T> { };
+
+template <typename T>
+struct TS3 {
+ static const int value = 0;
+};
+template <typename T>
+const int TS3<T>::value;
+// Instantiate struct, but not value.
+struct instantiate : TS3<int> {};
+
+
//===----------------------------------------------------------------------===//
#elif not defined(HEADER2)
#define HEADER2
+#if !defined(HEADER1)
+#error Header inclusion order messed up
+#endif
+
//===----------------------------------------------------------------------===//
// Dependent header for C++ chained PCH test
@@ -73,6 +88,15 @@ struct S<int &> { typedef int L; };
template <typename T> struct TS2 { };
+struct TestBaseSpecifiers3 { };
+struct TestBaseSpecifiers4 : TestBaseSpecifiers3 { };
+
+struct A { };
+struct B : A { };
+
+// Instantiate TS3's member.
+static const int ts3m1 = TS3<int>::value;
+
//===----------------------------------------------------------------------===//
#else
//===----------------------------------------------------------------------===//
@@ -96,7 +120,12 @@ void test() {
typedef S<int &>::L T6;
TS2int ts2;
+
+ B b;
}
+// Should have remembered that there is a definition.
+static const int ts3m2 = TS3<int>::value;
+
//===----------------------------------------------------------------------===//
#endif
diff --git a/test/PCH/chain-empty-initial-namespace.cpp b/test/PCH/chain-empty-initial-namespace.cpp
new file mode 100644
index 000000000000..bf15caa72cda
--- /dev/null
+++ b/test/PCH/chain-empty-initial-namespace.cpp
@@ -0,0 +1,24 @@
+// no PCH
+// RUN: %clang_cc1 -include %s -include %s -fsyntax-only %s
+// full PCH
+// RUN: %clang_cc1 -chain-include %s -chain-include %s -fsyntax-only %s
+#if !defined(PASS1)
+#define PASS1
+
+namespace foo {} // no external storage
+
+#elif !defined(PASS2)
+#define PASS2
+
+namespace foo {
+ void bar();
+}
+
+#else
+// PASS3
+
+void test() {
+ foo::bar(); // no-error
+}
+
+#endif
diff --git a/test/PCH/chain-implicit-definition.cpp b/test/PCH/chain-implicit-definition.cpp
new file mode 100644
index 000000000000..245e8f9e10f8
--- /dev/null
+++ b/test/PCH/chain-implicit-definition.cpp
@@ -0,0 +1,39 @@
+// no PCH
+// RUN: %clang_cc1 -emit-llvm-only -include %s -include %s %s
+// with PCH
+// RUN: %clang_cc1 -emit-llvm-only -chain-include %s -chain-include %s %s
+#if !defined(PASS1)
+#define PASS1
+
+// A base with a virtual dtor.
+struct A {
+ virtual ~A();
+};
+
+// A derived class with an implicit virtual dtor.
+struct B : A {
+ // Key function to suppress vtable definition.
+ virtual void virt();
+};
+
+#elif !defined(PASS2)
+#define PASS2
+
+// Further derived class that requires ~B().
+// Causes definition of ~B(), but it was lost when saving PCH.
+struct C : B {
+ C();
+ ~C() {}
+};
+
+#else
+
+void foo() {
+ // Variable that requires ~C().
+ C c;
+}
+
+// VTable placement would again cause definition of ~B(), hiding the bug,
+// if not for B::virt(), which suppresses the placement.
+
+#endif
diff --git a/test/PCH/chain-late-anonymous-namespace.cpp b/test/PCH/chain-late-anonymous-namespace.cpp
new file mode 100644
index 000000000000..87205c631b3a
--- /dev/null
+++ b/test/PCH/chain-late-anonymous-namespace.cpp
@@ -0,0 +1,61 @@
+// no PCH
+// RUN: %clang_cc1 -include %s -include %s -fsyntax-only %s
+// with PCH
+// RUN: %clang_cc1 -chain-include %s -chain-include %s -fsyntax-only %s
+#if !defined(PASS1)
+#define PASS1
+
+namespace ns {}
+namespace os {}
+
+#elif !defined(PASS2)
+#define PASS2
+
+namespace ns {
+ namespace {
+ extern int x;
+ }
+}
+
+namespace {
+ extern int y;
+}
+namespace {
+}
+
+namespace os {
+ extern "C" {
+ namespace {
+ extern int z;
+ }
+ }
+}
+
+#else
+
+namespace ns {
+ namespace {
+ int x;
+ }
+ void test() {
+ (void)x;
+ }
+}
+
+namespace {
+ int y;
+}
+void test() {
+ (void)y;
+}
+
+namespace os {
+ namespace {
+ int z;
+ }
+ void test() {
+ (void)z;
+ }
+}
+
+#endif
diff --git a/test/PCH/chain-pending-instantiations.cpp b/test/PCH/chain-pending-instantiations.cpp
new file mode 100644
index 000000000000..e49abcda4484
--- /dev/null
+++ b/test/PCH/chain-pending-instantiations.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -chain-include %s -chain-include %s | FileCheck %s
+// CHECK: define linkonce_odr %{{[^ ]+}} @_ZN1AI1BE3getEv
+#if !defined(PASS1)
+#define PASS1
+
+template <typename Derived>
+struct A {
+ Derived* get() { return 0; }
+};
+
+struct B : A<B> {
+};
+
+#elif !defined(PASS2)
+#define PASS2
+
+struct C : B {
+};
+
+struct D : C {
+ void run() {
+ (void)get();
+ }
+};
+
+#else
+
+int main() {
+ D d;
+ d.run();
+}
+
+#endif
diff --git a/test/PCH/cxx-chain-function-template.cpp b/test/PCH/cxx-chain-function-template.cpp
new file mode 100644
index 000000000000..494e190f776b
--- /dev/null
+++ b/test/PCH/cxx-chain-function-template.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -chain-include %s -chain-include %s -fsyntax-only %s
+// Just don't crash.
+#if !defined(RUN1)
+#define RUN1
+
+struct CXXRecordDecl { CXXRecordDecl(int); };
+
+template <typename T, typename U>
+T cast(U u) {
+ return reinterpret_cast<T&>(u);
+}
+
+void test1() {
+ cast<float>(1);
+}
+
+#elif !defined(RUN2)
+#define RUN2
+
+template <typename T>
+void test2(T) {
+ cast<CXXRecordDecl>(1.0f);
+}
+
+#else
+
+void test3() {
+ cast<CXXRecordDecl>(1.0f);
+ test2(1);
+}
+
+#endif
diff --git a/test/PCH/cxx-for-range.cpp b/test/PCH/cxx-for-range.cpp
new file mode 100644
index 000000000000..5854917da5c7
--- /dev/null
+++ b/test/PCH/cxx-for-range.cpp
@@ -0,0 +1,19 @@
+// Test this without pch.
+// RUN: %clang_cc1 -std=c++0x -include %S/cxx-for-range.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %S/cxx-for-range.h
+// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+void h() {
+ f();
+
+ g<int>();
+
+ char a[3] = { 0, 1, 2 };
+ for (auto w : a)
+ for (auto x : S())
+ for (auto y : T())
+ for (auto z : U())
+ ;
+}
diff --git a/test/PCH/cxx-for-range.h b/test/PCH/cxx-for-range.h
new file mode 100644
index 000000000000..f15c7e73df39
--- /dev/null
+++ b/test/PCH/cxx-for-range.h
@@ -0,0 +1,35 @@
+// Header for PCH test cxx-for-range.cpp
+
+struct S {
+ int *begin();
+ int *end();
+};
+
+struct T { };
+char *begin(T);
+char *end(T);
+
+struct U { };
+namespace std {
+ char *begin(U);
+ char *end(U);
+}
+
+void f() {
+ char a[3] = { 0, 1, 2 };
+ for (auto w : a)
+ for (auto x : S())
+ for (auto y : T())
+ for (auto z : U())
+ ;
+}
+
+template<typename A>
+void g() {
+ A a[3] = { 0, 1, 2 };
+ for (auto &v : a)
+ for (auto x : S())
+ for (auto y : T())
+ for (auto z : U())
+ ;
+}
diff --git a/test/PCH/cxx-reference.cpp b/test/PCH/cxx-reference.cpp
new file mode 100644
index 000000000000..90d00d777c44
--- /dev/null
+++ b/test/PCH/cxx-reference.cpp
@@ -0,0 +1,6 @@
+// Test this without pch.
+// RUN: %clang_cc1 -std=c++0x -include %S/cxx-reference.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %S/cxx-reference.h
+// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
diff --git a/test/PCH/cxx-reference.h b/test/PCH/cxx-reference.h
new file mode 100644
index 000000000000..b46a3671a325
--- /dev/null
+++ b/test/PCH/cxx-reference.h
@@ -0,0 +1,13 @@
+// Header for PCH test cxx-reference.cpp
+
+typedef char (&LR);
+typedef char (&&RR);
+
+char c;
+
+char &lr = c;
+char &&rr = 'c';
+LR &lrlr = c;
+LR &&rrlr = c;
+RR &lrrr = c;
+RR &&rrrr = 'c';
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index 05dd6ed0d2be..982fc67e4e8a 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -1,11 +1,11 @@
// Test this without pch.
-// RUN: %clang_cc1 -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s
// Test with pch.
-// RUN: %clang_cc1 -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -fexceptions -include-pch %t -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -fexceptions -include-pch %t %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o -
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - | FileCheck %s
// CHECK: define weak_odr void @_ZN2S4IiE1mEv
// CHECK: define linkonce_odr void @_ZN2S3IiE1mEv
@@ -43,3 +43,22 @@ S7<int[5]> s7_5;
namespace ZeroLengthExplicitTemplateArgs {
template void f<X>(X*);
}
+
+// This used to overwrite memory and crash.
+namespace Test1 {
+ struct StringHasher {
+ template<typename T, char Converter(T)> static inline unsigned createHash(const T*, unsigned) {
+ return 0;
+ }
+ };
+
+ struct CaseFoldingHash {
+ static inline char foldCase(char) {
+ return 0;
+ }
+
+ static unsigned hash(const char* data, unsigned length) {
+ return StringHasher::createHash<char, foldCase>(data, length);
+ }
+ };
+}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index d2c820f877c6..c45e02dcb23c 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -193,3 +193,15 @@ namespace ZeroLengthExplicitTemplateArgs {
template<typename T> void g2(T);
};
}
+
+namespace NonTypeTemplateParmContext {
+ template<typename T, int inlineCapacity = 0> class Vector { };
+
+ struct String {
+ template<int inlineCapacity>
+ static String adopt(Vector<char, inlineCapacity>&);
+ };
+
+ template<int inlineCapacity>
+ inline bool equalIgnoringNullity(const Vector<char, inlineCapacity>& a, const String& b) { return false; }
+}
diff --git a/test/PCH/cxx_exprs.cpp b/test/PCH/cxx_exprs.cpp
index cf7ae338eba1..49df80db4fed 100644
--- a/test/PCH/cxx_exprs.cpp
+++ b/test/PCH/cxx_exprs.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -fexceptions -include %S/cxx_exprs.h -std=c++0x -fsyntax-only -verify %s -ast-dump
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx_exprs.h -std=c++0x -fsyntax-only -verify %s -ast-dump
// Test with pch. Use '-ast-dump' to force deserialization of function bodies.
-// RUN: %clang_cc1 -fexceptions -x c++-header -std=c++0x -emit-pch -o %t %S/cxx_exprs.h
-// RUN: %clang_cc1 -fexceptions -std=c++0x -include-pch %t -fsyntax-only -verify %s -ast-dump
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -x c++-header -std=c++0x -emit-pch -o %t %S/cxx_exprs.h
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++0x -include-pch %t -fsyntax-only -verify %s -ast-dump
int integer;
double floating;
diff --git a/test/PCH/exprs.c b/test/PCH/exprs.c
index d855defe7eed..5928abda58f3 100644
--- a/test/PCH/exprs.c
+++ b/test/PCH/exprs.c
@@ -39,7 +39,7 @@ negate_enum *int_ptr4 = &integer;
// OffsetOfExpr
offsetof_type *offsetof_ptr = &size_type_value;
-// SizeOfAlignOfExpr
+// UnaryExprOrTypeTraitExpr
typeof(sizeof(float)) size_t_value;
typeof_sizeof *size_t_ptr = &size_t_value;
typeof_sizeof2 *size_t_ptr2 = &size_t_value;
@@ -93,3 +93,6 @@ choose_expr *int_ptr8 = &integer;
// ShuffleVectorExpr
shuffle_expr *vec_ptr = &vec2;
+
+// GenericSelectionExpr
+generic_selection_expr *double_ptr6 = &floating;
diff --git a/test/PCH/exprs.h b/test/PCH/exprs.h
index 80768f8df24e..3495b8b4bbde 100644
--- a/test/PCH/exprs.h
+++ b/test/PCH/exprs.h
@@ -38,7 +38,7 @@ struct Z {
typedef typeof(__builtin_offsetof(struct Z, y.array[1 + 2].member))
offsetof_type;
-// SizeOfAlignOfExpr
+// UnaryExprOrTypeTraitExpr
typedef typeof(sizeof(int)) typeof_sizeof;
typedef typeof(sizeof(Enumerator)) typeof_sizeof2;
@@ -99,3 +99,7 @@ typedef typeof(__builtin_choose_expr(17 > 19, d0, 1)) choose_expr;
// ShuffleVectorExpr
typedef typeof(__builtin_shufflevector(vec2, vec2b, 2, 1)) shuffle_expr;
+
+// GenericSelectionExpr
+typedef typeof(_Generic(i, char*: 0, int: 0., default: hello))
+ generic_selection_expr;
diff --git a/test/PCH/headersearch.cpp b/test/PCH/headersearch.cpp
index 151756c7071e..8ca0c361c4dc 100644
--- a/test/PCH/headersearch.cpp
+++ b/test/PCH/headersearch.cpp
@@ -1,8 +1,9 @@
// Test reading of PCH with changed location of original input files,
// i.e. invoking header search.
-// XFAIL: win32
+// REQUIRES: shell
// Generate the original files:
+// RUN: rm -rf %t_orig %t_moved
// RUN: mkdir -p %t_orig/sub %t_orig/sub2
// RUN: echo 'struct orig_sub{char c; int i; };' > %t_orig/sub/orig_sub.h
// RUN: echo 'void orig_sub2_1();' > %t_orig/sub2/orig_sub2_1.h
@@ -16,8 +17,7 @@
// Generate the PCH:
// RUN: cd %t_orig && %clang_cc1 -x c++ -emit-pch -o all.h.pch -Isub2 all.h
-// RUN: rm -rf %t_moved
-// RUN: mv %t_orig %t_moved
+// RUN: cp -pR %t_orig %t_moved
// Check diagnostic with location in original source:
// RUN: %clang_cc1 -include-pch all.h.pch -I%t_moved -I%t_moved/sub2 -Wpadded -emit-obj -o %t.o %s 2> %t.stderr
diff --git a/test/PCH/modified-header-crash.c b/test/PCH/modified-header-crash.c
new file mode 100644
index 000000000000..c74ce2239c22
--- /dev/null
+++ b/test/PCH/modified-header-crash.c
@@ -0,0 +1,10 @@
+// Don't crash.
+
+// RUN: cp %S/modified-header-crash.h %t.h
+// RUN: %clang_cc1 -DCAKE -x c-header %t.h -emit-pch -o %t
+// RUN: echo >> %t.h
+// RUN: not %clang_cc1 %s -include-pch %t -fsyntax-only
+
+void f(void) {
+ foo = 3;
+}
diff --git a/test/PCH/modified-header-crash.h b/test/PCH/modified-header-crash.h
new file mode 100644
index 000000000000..971746e3bd4c
--- /dev/null
+++ b/test/PCH/modified-header-crash.h
@@ -0,0 +1 @@
+int foo;
diff --git a/test/PCH/objcxx-ivar-class.h b/test/PCH/objcxx-ivar-class.h
index 50ebda709db0..5e5565864d87 100644
--- a/test/PCH/objcxx-ivar-class.h
+++ b/test/PCH/objcxx-ivar-class.h
@@ -1,6 +1,7 @@
struct S {
S();
S(const S&);
+ ~S();
S& operator= (const S&);
};
diff --git a/test/PCH/pragma-diag-section.cpp b/test/PCH/pragma-diag-section.cpp
index 312f720ebd98..5b996bb2f0d1 100644
--- a/test/PCH/pragma-diag-section.cpp
+++ b/test/PCH/pragma-diag-section.cpp
@@ -12,7 +12,10 @@
#pragma clang diagnostic ignored "-Wtautological-compare"
template <typename T>
struct TS {
- void m() { T b = b==b; }
+ void m() {
+ T a = 0;
+ T b = a==a;
+ }
};
#pragma clang diagnostic pop
diff --git a/test/PCH/pragma-diag.c b/test/PCH/pragma-diag.c
index c5171036400f..b304c4bf8c35 100644
--- a/test/PCH/pragma-diag.c
+++ b/test/PCH/pragma-diag.c
@@ -13,7 +13,8 @@
#else
void f() {
- int b = b==b;
+ int a = 0;
+ int b = a==a;
}
#endif
diff --git a/test/PCH/rdar8852495.c b/test/PCH/rdar8852495.c
index 2d49e001b051..fb465a37ce38 100644
--- a/test/PCH/rdar8852495.c
+++ b/test/PCH/rdar8852495.c
@@ -16,7 +16,8 @@
#else
int f() {
- int b = b==b;
+ int a;
+ int b = a==a;
unsigned x;
signed y;
return x == y;
diff --git a/test/PCH/reloc.c b/test/PCH/reloc.c
index 51a7c4c87946..fd78feba6047 100644
--- a/test/PCH/reloc.c
+++ b/test/PCH/reloc.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-pch -o %t -relocatable-pch -isysroot %S/libroot %S/libroot/usr/include/reloc.h
// RUN: %clang_cc1 -include-pch %t -isysroot %S/libroot %s -verify
// RUN: not %clang_cc1 -include-pch %t %s
-// XFAIL: win32
+
#include <reloc.h>
int x = 2; // expected-error{{redefinition}}
diff --git a/test/PCH/source-manager-stack.c b/test/PCH/source-manager-stack.c
index cc8555661a4d..8f5da2f0e371 100644
--- a/test/PCH/source-manager-stack.c
+++ b/test/PCH/source-manager-stack.c
@@ -2,9 +2,9 @@
// when using PCH.
// RUN: echo 'int x;' > %t.prefix.h
-// RUN: not %clang_cc1 -fsyntax-only -include %t.prefix.h %s 2> %t.diags.no_pch.txt
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack -include %t.prefix.h %s 2> %t.diags.no_pch.txt
// RUN: %clang_cc1 -emit-pch -o %t.prefix.pch %t.prefix.h
-// RUN: not %clang_cc1 -fsyntax-only -include-pch %t.prefix.pch %s 2> %t.diags.pch.txt
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-show-note-include-stack -include-pch %t.prefix.pch %s 2> %t.diags.pch.txt
// RUN: diff %t.diags.no_pch.txt %t.diags.pch.txt
// XFAIL: *
// PR5662
diff --git a/test/PCH/working-directory.cpp b/test/PCH/working-directory.cpp
new file mode 100644
index 000000000000..e77d31b4be61
--- /dev/null
+++ b/test/PCH/working-directory.cpp
@@ -0,0 +1,12 @@
+// Test this without pch.
+// RUN: %clang_cc1 -working-directory %S -I. -include working-directory.h %s -Wunused
+
+// Test with pch.
+// RUN: %clang_cc1 -working-directory %S -x c++-header -emit-pch -o %t.pch -I. working-directory.h
+// RUN: %clang_cc1 -include-pch %t.pch -fsyntax-only %s -Wunused
+
+void f() {
+ // Instantiating A<char> will trigger a warning, which will end up trying to get the path to
+ // the header that contains A.
+ A<char> b;
+}
diff --git a/test/PCH/working-directory.h b/test/PCH/working-directory.h
new file mode 100644
index 000000000000..02a60e3e763e
--- /dev/null
+++ b/test/PCH/working-directory.h
@@ -0,0 +1 @@
+#include <Inputs/working-directory-1.h>
diff --git a/test/Parser/DelayedTemplateParsing.cpp b/test/Parser/DelayedTemplateParsing.cpp
new file mode 100644
index 000000000000..b447fff2f1c0
--- /dev/null
+++ b/test/Parser/DelayedTemplateParsing.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fdelayed-template-parsing -fsyntax-only -verify %s
+
+template <class T>
+class A {
+ void foo() {
+ undeclared();
+ }
+ void foo2();
+};
+
+template <class T>
+class B {
+ void foo4() { } // expected-note {{previous definition is here}} expected-note {{previous definition is here}}
+ void foo4() { } // expected-error {{class member cannot be redeclared}} expected-error {{redefinition of 'foo4'}} expected-note {{previous definition is here}}
+};
+
+
+template <class T>
+void B<T>::foo4() {// expected-error {{redefinition of 'foo4'}}
+}
+
+template <class T>
+void A<T>::foo2() {
+ undeclared();
+}
+
+
+template <class T>
+void foo3() {
+ undeclared();
+}
+
+template void A<int>::foo2();
+
+
+void undeclared()
+{
+
+}
+
+template <class T> void foo5() {} //expected-note {{previous definition is here}}
+template <class T> void foo5() {} // expected-error {{redefinition of 'foo5'}}
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index 9df8fa3a4e91..2f5da5255b37 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -43,7 +43,7 @@ char x = FOO(a);
typedef enum E { e1 };
-
+
diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp
index fd0d7d50d0eb..32ed375889a6 100644
--- a/test/Parser/MicrosoftExtensions.cpp
+++ b/test/Parser/MicrosoftExtensions.cpp
@@ -95,6 +95,16 @@ void template_uuid()
}
+template <class T, const GUID* g = &__uuidof(T)>
+class COM_CLASS_TEMPLATE { };
+
+typedef COM_CLASS_TEMPLATE<struct_with_uuid, &__uuidof(struct_with_uuid)> COM_TYPE_1;
+typedef COM_CLASS_TEMPLATE<struct_with_uuid> COM_TYPE_2;
+
+template <class T, const GUID& g>
+class COM_CLASS_TEMPLATE_REF { };
+typedef COM_CLASS_TEMPLATE<struct_with_uuid, __uuidof(struct_with_uuid)> COM_TYPE_REF;
+
class CtorCall {
public:
@@ -111,3 +121,46 @@ CtorCall& CtorCall::operator=(const CtorCall& that)
}
return *this;
}
+
+template <class A>
+class C1 {
+public:
+ template <int B>
+ class Iterator {
+ };
+};
+
+template<class T>
+class C2 {
+ typename C1<T>:: /*template*/ Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+};
+
+template <class T>
+void f(){
+ typename C1<T>:: /*template*/ Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+}
+
+
+
+class AAAA { };
+
+template <class T>
+void redundant_typename() {
+ typename T t;// expected-warning {{expected a qualified name after 'typename'}}
+ typename AAAA a;// expected-warning {{expected a qualified name after 'typename'}}
+ t = 3;
+}
+
+int main() {
+ redundant_typename<int>();
+ f<int>();
+}
+
+
+__interface MicrosoftInterface;
+__interface MicrosoftInterface {
+ virtual void foo1() = 0;
+ virtual void foo2() = 0;
+};
+
+__int64 x7 = __int64(0);
diff --git a/test/Parser/altivec.c b/test/Parser/altivec.c
index 64f82f7a563c..d1e655213761 100644
--- a/test/Parser/altivec.c
+++ b/test/Parser/altivec.c
@@ -113,9 +113,9 @@ void f() {
}
// bug 6895 - Vectorl literal casting confusion.
-vector char v1 = (vector char)((vector int)(1, 2, 3, 4));
-vector char v2 = (vector char)((vector float)(1.0f, 2.0f, 3.0f, 4.0f));
-vector char v3 = (vector char)((vector int)('a', 'b', 'c', 'd'));
-vector int v4 = (vector int)(1, 2, 3, 4);
+vector char v1 = (vector char)((vector int)(1, 2, 3, 4));
+vector char v2 = (vector char)((vector float)(1.0f, 2.0f, 3.0f, 4.0f));
+vector char v3 = (vector char)((vector int)('a', 'b', 'c', 'd'));
+vector int v4 = (vector int)(1, 2, 3, 4);
vector float v5 = (vector float)(1.0f, 2.0f, 3.0f, 4.0f);
vector char v6 = (vector char)((vector int)(1+2, -2, (int)(2.0 * 3), -(5-3)));
diff --git a/test/Parser/attr-availability.c b/test/Parser/attr-availability.c
new file mode 100644
index 000000000000..269f90847d66
--- /dev/null
+++ b/test/Parser/attr-availability.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if !__has_feature(attribute_availability)
+# error 'availability' attribute is not available
+#endif
+
+void f0() __attribute__((availability(macosx,introduced=10.2,deprecated=10.4,obsoleted=10.6)));
+
+void f1() __attribute__((availability(macosx,deprecated=10.4,introduced=10.2,obsoleted=10.6)));
+
+void f2() __attribute__((availability(ios,deprecated=10.4.7,introduced=10,obsoleted=10.6)));
+
+void f3() __attribute__((availability(ios,deprecated=10.4.7,introduced=10,obsoleted=10.6,introduced=10.2))); // expected-error{{redundant 'introduced' availability change; only the last specified change will be used}}
+
+void f4() __attribute__((availability(macosx,introduced=10.5), availability(ios,unavailable)));
+
+void f5() __attribute__((availability(macosx,introduced=10.5), availability(ios,unavailable, unavailable))); // expected-error{{redundant 'unavailable' availability change; only the last specified change will be used}}
+
+void f6() __attribute__((availability(macosx,unavailable,introduced=10.5))); // expected-warning{{warning: 'unavailable' availability overrides all other availability information}}
+
diff --git a/test/Parser/c1x-generic-selection.c b/test/Parser/c1x-generic-selection.c
new file mode 100644
index 000000000000..ee23059cc4de
--- /dev/null
+++ b/test/Parser/c1x-generic-selection.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s
+
+void foo(void) {
+ _Generic; // expected-error {{expected '('}}
+ (void) _Generic(0); // expected-error {{expected ','}}
+ (void) _Generic(0, void); // expected-error {{expected ':'}}
+ (void) _Generic(0,
+ default: 0, // expected-note {{previous default generic association is here}}
+ default: 0); // expected-error {{duplicate default generic association}}
+}
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
index 98d962ad0998..4a0bb4d1e4e5 100644
--- a/test/Parser/cxx-casting.cpp
+++ b/test/Parser/cxx-casting.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
char *const_cast_test(const char *var)
{
@@ -34,6 +34,36 @@ char postfix_expr_test()
// This was being incorrectly tentatively parsed.
namespace test1 {
- template <class T> class A {};
+ template <class T> class A {}; // expected-note 2{{here}}
void foo() { A<int>(*(A<int>*)0); }
}
+
+typedef char* c;
+typedef A* a;
+void test2(char x, struct B * b) {
+ (void)const_cast<::c>(&x); // expected-error{{found '<::' after a const_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ (void)dynamic_cast<::a>(b); // expected-error{{found '<::' after a dynamic_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ (void)reinterpret_cast<::c>(x); // expected-error{{found '<::' after a reinterpret_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ (void)static_cast<::c>(&x); // expected-error{{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+
+ // Do not do digraph correction.
+ (void)static_cast<: :c>(&x); //\
+ expected-error {{expected '<' after 'static_cast'}} \
+ expected-error {{expected expression}}\
+ expected-error {{expected ']'}}\
+ expected-note {{to match this '['}}
+ (void)static_cast<: // expected-error {{expected '<' after 'static_cast'}} \
+ expected-note {{to match this '['}}
+ :c>(&x); // expected-error {{expected expression}} \
+ expected-error {{expected ']'}}
+#define LC <:
+#define C :
+ test1::A LC:B> c; // expected-error {{cannot refer to class template 'A' without a template argument list}} expected-error 2{{}} expected-note{{}}
+ (void)static_cast LC:c>(&x); // expected-error {{expected '<' after 'static_cast'}} expected-error 2{{}} expected-note{{}}
+ test1::A<:C B> d; // expected-error {{cannot refer to class template 'A' without a template argument list}} expected-error 2{{}} expected-note{{}}
+ (void)static_cast<:C c>(&x); // expected-error {{expected '<' after 'static_cast'}} expected-error 2{{}} expected-note{{}}
+
+#define LCC <::
+ test1::A LCC B> e; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+ (void)static_cast LCC c>(&x); // expected-error{{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+}
diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp
index 6d720d36a259..70eff973e0e1 100644
--- a/test/Parser/cxx-decl.cpp
+++ b/test/Parser/cxx-decl.cpp
@@ -7,8 +7,8 @@ struct Type {
};
// rdar://8365458
-typedef char bool; // expected-error {{redeclaration of C++ built-in type 'bool'}} \
- // expected-warning {{declaration does not declare anything}}
+// rdar://9132143
+typedef char bool; // expected-error {{redeclaration of C++ built-in type 'bool'}}
// PR4451 - We should recover well from the typo of '::' as ':' in a2.
namespace y {
diff --git a/test/Parser/cxx-exception-spec.cpp b/test/Parser/cxx-exception-spec.cpp
deleted file mode 100644
index e6c3c757f012..000000000000
--- a/test/Parser/cxx-exception-spec.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only %s
-
-struct X { };
-
-struct Y { };
-
-void f() throw() { }
-
-void g(int) throw(X) { }
-
-void h() throw(X, Y) { }
-
-class Class {
- void foo() throw (X, Y) { }
-};
-
-void (*fptr)() throw();
diff --git a/test/Parser/cxx-member-crash.cpp b/test/Parser/cxx-member-crash.cpp
new file mode 100644
index 000000000000..2b31a608a583
--- /dev/null
+++ b/test/Parser/cxx-member-crash.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only %s 2>&1|FileCheck %s
+
+// <rdar://problem/9221993>
+
+// We only care to chek whether the compiler crashes; the actual
+// diagnostics are uninteresting.
+// CHECK: 8 errors generated.
+template<class _CharT> struct char_traits;
+template<typename _CharT, typename _Traits = char_traits<_CharT> > class basic_ios;
+template<typename _CharT, typename _Traits = char_traits<_CharT> > class ostreambuf_iterator;
+template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> > class num_get;
+template<typename _CharT, typename _Traits> class basic_ostream : virtual public basic_ios<_CharT, _Traits> {
+ template<typename _CharT, typename _InIter> _InIter num_get<_CharT, _InIter>:: _M_extract_float(_InIter __beg, _InIter __end, ios_base& __io, ios_base::iostate& __err, string& __xtrc) const {
+ const bool __plus = __c == __lit[__num_base::_S_iplus];
+ if ((__plus || __c == __lit[__num_base::_S_iminus]) && !(__lc->_M_use_grouping && __c == __lc->_M_thousands_sep) && !(__c == __lc->_M_decimal_point)) {
diff --git a/test/Parser/cxx-stmt.cpp b/test/Parser/cxx-stmt.cpp
index 795aca6e93c0..7677ca880128 100644
--- a/test/Parser/cxx-stmt.cpp
+++ b/test/Parser/cxx-stmt.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
void f1()
{
diff --git a/test/Parser/cxx-throw.cpp b/test/Parser/cxx-throw.cpp
index 20b8f4b754ab..d63b6d4cae6c 100644
--- a/test/Parser/cxx-throw.cpp
+++ b/test/Parser/cxx-throw.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
int i;
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 3147de940418..f65e29070957 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x %s
// Declaration syntax checks
[[]] int before_attr;
diff --git a/test/Parser/cxx0x-override-control-keywords.cpp b/test/Parser/cxx0x-override-control-keywords.cpp
index f959f7a9952c..91d5132febe8 100644
--- a/test/Parser/cxx0x-override-control-keywords.cpp
+++ b/test/Parser/cxx0x-override-control-keywords.cpp
@@ -7,9 +7,6 @@ struct Base {
struct S : Base {
virtual void final() final;
virtual void override() override;
- virtual void n() new;
- int i : 3 new;
- int j new;
};
struct T {
diff --git a/test/Parser/expressions.c b/test/Parser/expressions.c
index 6015e918a340..0d1b6c945c5c 100644
--- a/test/Parser/expressions.c
+++ b/test/Parser/expressions.c
@@ -51,3 +51,9 @@ int test6(void) {
test5(1)
; // expected-error {{expected ')'}}
}
+
+// PR8394
+void test7() {
+ ({} // expected-note {{to match}}
+ ; // expected-error {{expected ')'}}
+}
diff --git a/test/Parser/objc-missing-impl.m b/test/Parser/objc-missing-impl.m
index 05d9d6c0b232..e9c37ab1b158 100644
--- a/test/Parser/objc-missing-impl.m
+++ b/test/Parser/objc-missing-impl.m
@@ -1,2 +1,2 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@end // expected-warning {{@end must appear in an @implementation context}}
+@end // expected-error {{@end must appear in an @implementation context}}
diff --git a/test/Parser/objcxx-at.mm b/test/Parser/objcxx-at.mm
new file mode 100644
index 000000000000..37aee4dd6aa9
--- /dev/null
+++ b/test/Parser/objcxx-at.mm
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface B {
+ int i;
+}
+@end
+
+struct Z {
+ @defs(B); // expected-error{{@defs is not supported in Objective-C++}}
+};
+
+struct Y { // expected-note{{to match this '{'}}
+ struct X { } // expected-error{{expected ';' after struct}}
+ @interface A // expected-error{{unexpected '@' in member specification}}
+} // expected-error{{expected '}'}} expected-error{{expected ';' after struct}}
diff --git a/test/Parser/opencl-image-access.cl b/test/Parser/opencl-image-access.cl
new file mode 100644
index 000000000000..313587c1d225
--- /dev/null
+++ b/test/Parser/opencl-image-access.cl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -fsyntax-only
+
+typedef void* image2d_t;
+
+__kernel void f__ro(__read_only image2d_t a) { }
+
+__kernel void f__wo(__write_only image2d_t a) { }
+
+__kernel void f__rw(__read_write image2d_t a) { }
+
+
+__kernel void fro(read_only image2d_t a) { }
+
+__kernel void fwo(write_only image2d_t a) { }
+
+__kernel void frw(read_write image2d_t a) { }
diff --git a/test/Parser/recovery.m b/test/Parser/recovery.m
new file mode 100644
index 000000000000..e1265262b1b2
--- /dev/null
+++ b/test/Parser/recovery.m
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -fblocks %s
+
+@interface Test0
+@property (assign) id x // expected-error {{expected ';' at end of declaration list}}
+@end
diff --git a/test/Parser/selector-1.m b/test/Parser/selector-1.m
index 0f35ce79b20f..5ba2da9931cf 100644
--- a/test/Parser/selector-1.m
+++ b/test/Parser/selector-1.m
@@ -1,14 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// rdar://8366474
int main() {
- SEL s = @selector(retain);
- SEL s1 = @selector(meth1:);
- SEL s2 = @selector(retainArgument::);
- SEL s3 = @selector(retainArgument:::::);
- SEL s4 = @selector(retainArgument:with:);
- SEL s5 = @selector(meth1:with:with:);
- SEL s6 = @selector(getEnum:enum:bool:);
- SEL s7 = @selector(char:float:double:unsigned:short:long:);
-
- SEL s9 = @selector(:enum:bool:);
+ SEL s = @selector(retain);
+ SEL s1 = @selector(meth1:);
+ SEL s2 = @selector(retainArgument::);
+ SEL s3 = @selector(retainArgument:::::);
+ SEL s4 = @selector(retainArgument:with:);
+ SEL s5 = @selector(meth1:with:with:);
+ SEL s6 = @selector(getEnum:enum:bool:);
+ SEL s7 = @selector(char:float:double:unsigned:short:long:);
+ SEL s9 = @selector(:enum:bool:);
+
+ (void) @selector(foo:);
+ (void) @selector(foo::);
+ (void) @selector(foo:::);
+ (void) @selector(foo::::);
}
diff --git a/test/Parser/switch-recovery.cpp b/test/Parser/switch-recovery.cpp
index f11babc5b600..0e4dcfa3c637 100644
--- a/test/Parser/switch-recovery.cpp
+++ b/test/Parser/switch-recovery.cpp
@@ -31,4 +31,128 @@ struct B {
break;
}
}
+
+ int test3(int i) {
+ switch (i) {
+ case 1: return 0;
+ 2: return 1; // expected-error {{expected 'case' keyword before expression}}
+ default: return 5;
+ }
+ }
};
+
+int test4(int i) {
+ switch (i)
+ 1: return -1; // expected-error {{expected 'case' keyword before expression}}
+ return 0;
+}
+
+int test5(int i) {
+ switch (i) {
+ case 1: case 2: case 3: return 1;
+ {
+ 4:5:6:7: return 2; // expected-error 4{{expected 'case' keyword before expression}}
+ }
+ default: return -1;
+ }
+}
+
+int test6(int i) {
+ switch (i) {
+ case 1:
+ case 4:
+ // This class provides extra single colon tokens. Make sure no
+ // errors are seen here.
+ class foo{
+ public:
+ protected:
+ private:
+ };
+ case 2:
+ 5: // expected-error {{expected 'case' keyword before expression}}
+ default: return 1;
+ }
+}
+
+int test7(int i) {
+ switch (i) {
+ case false ? 1 : 2:
+ true ? 1 : 2: // expected-error {{expected 'case' keyword before expression}}
+ case 10:
+ 14 ? 3 : 4;
+ default:
+ return 1;
+ }
+}
+
+enum foo { A, B, C};
+int test8( foo x ) {
+ switch (x) {
+ A: return 0; // FIXME: give a warning for unused labels that could also be
+ // a case expression.
+ default: return 1;
+ }
+}
+
+// Stress test to make sure Clang doesn't crash.
+void test9(int x) {
+ switch(x) {
+ case 1: return;
+ 2: case; // expected-error {{expected 'case' keyword before expression}} \
+ expected-error {{expected expression}}
+ 4:5:6: return; // expected-error 3{{expected 'case' keyword before expression}}
+ 7: :x; // expected-error {{expected 'case' keyword before expression}} \
+ expected-error {{expected expression}}
+ 8:: x; // expected-error {{expected ';' after expression}} \
+ expected-error {{no member named 'x' in the global namespace}} \
+ expected-warning {{expression result unused}}
+ 9:: :y; // expected-error {{expected ';' after expression}} \
+ expected-error {{expected unqualified-id}} \
+ expected-warning {{expression result unused}}
+ :; // expected-error {{expected expression}}
+ ::; // expected-error {{expected unqualified-id}}
+ }
+}
+
+void test10(int x) {
+ switch (x) {
+ case 1: {
+ struct Inner {
+ void g(int y) {
+ 2: y++; // expected-error {{expected ';' after expression}} \
+ // expected-warning {{expression result unused}}
+ }
+ };
+ break;
+ }
+ }
+}
+
+template<typename T>
+struct test11 {
+ enum { E };
+
+ void f(int x) {
+ switch (x) {
+ E: break; // FIXME: give a 'case' fix-it for unused labels that
+ // could also be an expression an a case label.
+ E+1: break; // expected-error {{expected 'case' keyword before expression}}
+ }
+ }
+};
+
+void test12(int x) {
+ switch (x) {
+ 0: // expected-error {{expected 'case' keyword before expression}}
+ while (x) {
+ 1: // expected-error {{expected 'case' keyword before expression}}
+ for (;x;) {
+ 2: // expected-error {{expected 'case' keyword before expression}}
+ if (x > 0) {
+ 3: // expected-error {{expected 'case' keyword before expression}}
+ --x;
+ }
+ }
+ }
+ }
+}
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 98b053552eb1..b0515b3bba3c 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -11,7 +11,6 @@
//
// RUN: %clang_cc1 -x c++ -std=c++0x -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s
//
-// CXX0X:#define __DEPRECATED 1
// CXX0X:#define __GNUG__
// CXX0X:#define __GXX_EXPERIMENTAL_CXX0X__ 1
// CXX0X:#define __GXX_RTTI 1
@@ -22,7 +21,6 @@
//
// RUN: %clang_cc1 -x c++ -std=c++98 -E -dM < /dev/null | FileCheck -check-prefix CXX98 %s
//
-// CXX98:#define __DEPRECATED 1
// CXX98:#define __GNUG__
// CXX98:#define __GXX_RTTI 1
// CXX98:#define __GXX_WEAK__ 1
@@ -30,6 +28,11 @@
// CXX98:#define __private_extern__ extern
//
//
+// RUN: %clang_cc1 -fdeprecated-macro -E -dM < /dev/null | FileCheck -check-prefix DEPRECATED %s
+//
+// DEPRECATED:#define __DEPRECATED 1
+//
+//
// RUN: %clang_cc1 -std=c99 -E -dM < /dev/null | FileCheck -check-prefix C99 %s
//
// C99:#define __STDC_VERSION__ 199901L
@@ -62,7 +65,6 @@
//
// RUN: %clang_cc1 -x c++ -std=gnu++98 -E -dM < /dev/null | FileCheck -check-prefix GXX98 %s
//
-// GXX98:#define __DEPRECATED 1
// GXX98:#define __GNUG__
// GXX98:#define __GXX_WEAK__ 1
// GXX98:#define __cplusplus 1
@@ -78,10 +80,6 @@
//
// MSEXT-NOT:#define __STDC__
// MSEXT:#define _INTEGRAL_MAX_BITS 64
-// MSEXT:#define __int16 __INT16_TYPE__
-// MSEXT:#define __int32 __INT32_TYPE__
-// MSEXT:#define __int64 __INT64_TYPE__
-// MSEXT:#define __int8 __INT8_TYPE__
//
//
// RUN: %clang_cc1 -x objective-c -E -dM < /dev/null | FileCheck -check-prefix OBJC %s
@@ -982,7 +980,7 @@
// SPARC:#define __SIZE_WIDTH__ 32
// SPARC:#define __UINTMAX_TYPE__ long long unsigned int
// SPARC:#define __USER_LABEL_PREFIX__ _
-// SPARC:#define __VERSION__ "4.2.1 Compatible Clang Compiler"
+// SPARC:#define __VERSION__ "4.2.1 Compatible
// SPARC:#define __WCHAR_MAX__ 2147483647
// SPARC:#define __WCHAR_TYPE__ int
// SPARC:#define __WCHAR_WIDTH__ 32
diff --git a/test/Preprocessor/pragma-pushpop-macro.c b/test/Preprocessor/pragma-pushpop-macro.c
index 71b0e0e2600b..08a65704e4cb 100644
--- a/test/Preprocessor/pragma-pushpop-macro.c
+++ b/test/Preprocessor/pragma-pushpop-macro.c
@@ -25,7 +25,7 @@ int pmx3 = X;
#pragma pop_macro("Y")
int pmy1 = Y;
-// Have a stray 'push' to show we don't crash when having inbalanced
+// Have a stray 'push' to show we don't crash when having imbalanced
// push/pop
#pragma push_macro("Y")
#define Y 4
diff --git a/test/Preprocessor/pragma_diagnostic_sections.cpp b/test/Preprocessor/pragma_diagnostic_sections.cpp
index 69436b0bd84e..b680fae5b993 100644
--- a/test/Preprocessor/pragma_diagnostic_sections.cpp
+++ b/test/Preprocessor/pragma_diagnostic_sections.cpp
@@ -2,14 +2,14 @@
// rdar://8365684
struct S {
- void m1() { int b = b==b; } // expected-warning {{always evaluates to true}}
+ void m1() { int b; while (b==b); } // expected-warning {{always evaluates to true}}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-compare"
- void m2() { int b = b==b; }
+ void m2() { int b; while (b==b); }
#pragma clang diagnostic pop
- void m3() { int b = b==b; } // expected-warning {{always evaluates to true}}
+ void m3() { int b; while (b==b); } // expected-warning {{always evaluates to true}}
};
//------------------------------------------------------------------------------
@@ -18,7 +18,7 @@ struct S {
#pragma clang diagnostic ignored "-Wtautological-compare"
template <typename T>
struct TS {
- void m() { T b = b==b; }
+ void m() { T b; while (b==b); }
};
#pragma clang diagnostic pop
diff --git a/test/Preprocessor/pragma_unknown.c b/test/Preprocessor/pragma_unknown.c
index 0672ade66059..2586754a180a 100644
--- a/test/Preprocessor/pragma_unknown.c
+++ b/test/Preprocessor/pragma_unknown.c
@@ -21,7 +21,7 @@
#pragma STDC CX_LIMITED_RANGE IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
#pragma STDC CX_LIMITED_RANGE // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
-#pragma STDC CX_LIMITED_RANGE ON FULL POWER // expected-warning {{expected end of macro in pragma}}
+#pragma STDC CX_LIMITED_RANGE ON FULL POWER // expected-warning {{expected end of directive in pragma}}
#pragma STDC SO_GREAT // expected-warning {{unknown pragma in STDC namespace}}
#pragma STDC // expected-warning {{unknown pragma in STDC namespace}}
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index b3ae8438033c..ee8e3c28c37f 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -1059,6 +1059,18 @@
// X86_64:UINTMAX_C_(0) 0UL
//
//
+// RUN: %clang_cc1 -E -ffreestanding -triple=x86_64-pc-linux-gnu %s | FileCheck -check-prefix X86_64_LINUX %s
+//
+// X86_64_LINUX:WINT_MIN_ 0U
+// X86_64_LINUX:WINT_MAX_ 4294967295U
+//
+//
+// RUN: %clang_cc1 -E -ffreestanding -triple=i386-mingw32 %s | FileCheck -check-prefix I386_MINGW32 %s
+//
+// I386_MINGW32:WCHAR_MAX_ 65535U
+// I386_MINGW32:WCHAR_MIN_ 0U
+//
+//
// stdint.h forms several macro definitions by pasting together identifiers
// to form names (eg. int32_t is formed from int ## 32 ## _t). The following
// case tests that these joining operations are performed correctly even if
diff --git a/test/Preprocessor/traditional-cpp.c b/test/Preprocessor/traditional-cpp.c
new file mode 100644
index 000000000000..5fc9ee398ecf
--- /dev/null
+++ b/test/Preprocessor/traditional-cpp.c
@@ -0,0 +1,12 @@
+/* Clang supports a very limited subset of -traditional-cpp, basically we only
+ * intend to add support for things that people actually rely on when doing
+ * things like using /usr/bin/cpp to preprocess non-source files. */
+
+/*
+ RUN: %clang_cc1 -traditional-cpp %s -E -o %t
+ RUN: FileCheck < %t %s
+*/
+
+/* CHECK: foo // bar
+ */
+foo // bar
diff --git a/test/Rewriter/rewrite-block-literal-1.mm b/test/Rewriter/rewrite-block-literal-1.mm
new file mode 100644
index 000000000000..04302d17f10f
--- /dev/null
+++ b/test/Rewriter/rewrite-block-literal-1.mm
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// radar 9254348
+
+void *sel_registerName(const char *);
+typedef void (^BLOCK_TYPE)(void);
+
+@interface CoreDAVTaskGroup
+{
+ int IVAR;
+}
+@property int IVAR;
+- (void) setCompletionBlock : (BLOCK_TYPE) arg;
+@end
+
+@implementation CoreDAVTaskGroup
+- (void)_finishInitialSync {
+ CoreDAVTaskGroup *folderPost;
+ folderPost.completionBlock = ^{
+ self.IVAR = 0;
+ [self _finishInitialSync];
+ };
+
+ [folderPost setCompletionBlock : (^{
+ self.IVAR = 0;
+ })];
+}
+@dynamic IVAR;
+- (void) setCompletionBlock : (BLOCK_TYPE) arg {}
+@end
+
+
diff --git a/test/Rewriter/rewrite-block-pointer.mm b/test/Rewriter/rewrite-block-pointer.mm
index abb2f136183c..d010a22484af 100644
--- a/test/Rewriter/rewrite-block-pointer.mm
+++ b/test/Rewriter/rewrite-block-pointer.mm
@@ -88,3 +88,20 @@ void test8608902() {
ppp(1, 0);
}
+void test9204669() {
+ __attribute__((__blocks__(byref))) char (^addChangeToData)();
+
+ addChangeToData = ^() {
+ return 'b';
+ };
+ addChangeToData();
+}
+
+void test9204669_1() {
+ __attribute__((__blocks__(byref))) void (^addChangeToData)();
+
+ addChangeToData = ^() {
+ addChangeToData();
+ };
+}
+
diff --git a/test/Sema/__try.c b/test/Sema/__try.c
new file mode 100644
index 000000000000..5490aea539ed
--- /dev/null
+++ b/test/Sema/__try.c
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -fborland-extensions -fsyntax-only -verify %s
+
+#define JOIN2(x,y) x ## y
+#define JOIN(x,y) JOIN2(x,y)
+#define TEST2(name) JOIN(name,__LINE__)
+#define TEST TEST2(test)
+typedef int DWORD;
+
+#pragma sysheader begin
+
+struct EXCEPTION_INFO{};
+
+int __exception_code();
+struct EXCEPTION_INFO* __exception_info();
+void __abnormal_termination();
+
+#define GetExceptionCode __exception_code
+#define GetExceptionInformation __exception_info
+#define AbnormalTermination __abnormal_termination
+
+#pragma sysheader end
+
+DWORD FilterExpression(int);
+DWORD FilterExceptionInformation(struct EXCEPTION_INFO*);
+
+const char * NotFilterExpression();
+
+void TEST() {
+ __try {
+ __try {
+ __try {
+ }
+ __finally{
+ }
+ }
+ __finally{
+ }
+ }
+ __finally{
+ }
+}
+
+void TEST() {
+ __try {
+
+ }
+} // expected-error{{expected '__except' or '__finally' block}}
+
+void TEST() {
+ __except ( FilterExpression() ) { // expected-error{{}}
+
+ }
+}
+
+void TEST() {
+ __finally { } // expected-error{{}}
+}
+
+void TEST() {
+ __try{
+ int try_scope = 0;
+ } // TODO: expected expression is an extra error
+ __except( try_scope ? 1 : -1 ) // expected-error{{undeclared identifier 'try_scope'}} expected-error{{expected expression}}
+ {}
+}
+
+void TEST() {
+ __try {
+
+ }
+ // TODO: Why are there two errors?
+ __except( ) { // expected-error{{expected expression}} expected-error{{expected expression}}
+ }
+}
+
+void TEST() {
+ __try {
+
+ }
+ __except ( FilterExpression(GetExceptionCode()) ) {
+
+ }
+
+ __try {
+
+ }
+ __except( FilterExpression(__exception_code()) ) {
+
+ }
+
+ __try {
+
+ }
+ __except( FilterExceptionInformation(__exception_info()) ) {
+
+ }
+
+ __try {
+
+ }
+ __except(FilterExceptionInformation( GetExceptionInformation() ) ) {
+
+ }
+}
+
+void TEST() {
+ __try {
+
+ }
+ __except ( NotFilterExpression() ) { // expected-error{{filter expression type should be an integral value not 'const char *'}}
+
+ }
+}
+
+void TEST() {
+ int function_scope = 0;
+ __try {
+ int try_scope = 0;
+ }
+ __except ( FilterExpression(GetExceptionCode()) ) {
+ (void)function_scope;
+ (void)try_scope; // expected-error{{undeclared identifier}}
+ }
+}
+
+void TEST() {
+ int function_scope = 0;
+ __try {
+ int try_scope = 0;
+ }
+ __finally {
+ (void)function_scope;
+ (void)try_scope; // expected-error{{undeclared identifier}}
+ }
+}
+
+void TEST() {
+ int function_scope = 0;
+ __try {
+
+ }
+ __except( function_scope ? 1 : -1 ) {}
+}
+
+void TEST() {
+ __try {
+ (void)AbnormalTermination; // expected-error{{only allowed in __finally block}}
+ (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
+ }
+ __except( 1 ) {
+ (void)AbnormalTermination; // expected-error{{only allowed in __finally block}}
+ (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
+ }
+
+ __try {
+ }
+ __finally {
+ AbnormalTermination();
+ __abnormal_termination();
+ }
+}
+
+void TEST() {
+ (void)__exception_code; // expected-error{{only allowed in __except block}}
+ (void)__exception_info; // expected-error{{only allowed in __except filter expression}}
+ (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
+
+ (void)GetExceptionCode(); // expected-error{{only allowed in __except block}}
+ (void)GetExceptionInformation(); // expected-error{{only allowed in __except filter expression}}
+ (void)AbnormalTermination(); // expected-error{{only allowed in __finally block}}
+}
diff --git a/test/Sema/align-x86-64.c b/test/Sema/align-x86-64.c
index 6dcf5714b005..edea5d8b7422 100644
--- a/test/Sema/align-x86-64.c
+++ b/test/Sema/align-x86-64.c
@@ -9,3 +9,17 @@ void foo(void) {
char y[__alignof__(x) == 16 ? 1 : -1];
frob(y);
}
+
+// PR5637
+
+typedef __attribute__((aligned(16))) struct {
+ unsigned long long w[3];
+} UINT192;
+
+UINT192 ten2mk192M[] = {
+ {{0xcddd6e04c0592104ULL, 0x0fcf80dc33721d53ULL, 0xa7c5ac471b478423ULL}},
+ {{0xcddd6e04c0592104ULL, 0x0fcf80dc33721d53ULL, 0xa7c5ac471b478423ULL}},
+ {{0xcddd6e04c0592104ULL, 0x0fcf80dc33721d53ULL, 0xa7c5ac471b478423ULL}}
+};
+
+short chk1[sizeof(ten2mk192M) == 80 ? 1 : -1];
diff --git a/test/Sema/align-x86.c b/test/Sema/align-x86.c
index c9a63989ecbc..61bd1d33c9d6 100644
--- a/test/Sema/align-x86.c
+++ b/test/Sema/align-x86.c
@@ -14,7 +14,31 @@ short chk1[__alignof__(g3) == 8 ? 1 : -1];
short chk2[__alignof__(_Complex double) == 8 ? 1 : -1];
// PR6362
-struct __attribute__((packed)) {unsigned int a} g4;
+struct __attribute__((packed)) {unsigned int a;} g4;
short chk1[__alignof__(g4) == 1 ? 1 : -1];
short chk2[__alignof__(g4.a) == 1 ? 1 : -1];
+
+// PR5637
+
+#define ALIGNED(x) __attribute__((aligned(x)))
+
+typedef ALIGNED(2) struct {
+ char a[3];
+} T;
+
+short chk1[sizeof(T) == 3 ? 1 : -1];
+short chk2[sizeof(T[1]) == 4 ? 1 : -1];
+short chk3[sizeof(T[2]) == 6 ? 1 : -1];
+short chk4[sizeof(T[2][1]) == 8 ? 1 : -1];
+short chk5[sizeof(T[1][2]) == 6 ? 1 : -1];
+
+typedef struct ALIGNED(2) {
+ char a[3];
+} T2;
+
+short chk1[sizeof(T2) == 4 ? 1 : -1];
+short chk2[sizeof(T2[1]) == 4 ? 1 : -1];
+short chk3[sizeof(T2[2]) == 8 ? 1 : -1];
+short chk4[sizeof(T2[2][1]) == 8 ? 1 : -1];
+short chk5[sizeof(T2[1][2]) == 8 ? 1 : -1];
diff --git a/test/Sema/altivec-init.c b/test/Sema/altivec-init.c
index ef6fe4bd9d2f..973aab15d466 100644
--- a/test/Sema/altivec-init.c
+++ b/test/Sema/altivec-init.c
@@ -9,6 +9,18 @@ v8 foo(void) {
a = (v8){4, 2};
b = (v4)(5, 6, 7, 8, 9); // expected-warning {{excess elements in vector initializer}}
b = (v4)(5, 6, 8, 8.0f);
+
+ vector int vi;
+ vi = (vector int)(1);
+ vi = (vector int)(1, 2); // expected-error {{number of elements must be either one or match the size of the vector}}
+ vi = (vector int)(1, 2, 3, 4);
+ vi = (vector int)(1, 2, 3, 4, 5); // expected-warning {{excess elements in vector initializer}}
+ vi = (vector int){1};
+ vi = (vector int){1, 2};
+ vi = (vector int){1, 2, 3, 4, 5}; // expected-warning {{excess elements in vector initializer}}
+ vector float vf;
+ vf = (vector float)(1.0);
+
return (v8){0, 1, 2, 3, 1, 2, 3, 4};
// FIXME: test that (type)(fn)(args) still works with -faltivec
diff --git a/test/Sema/annotate.c b/test/Sema/annotate.c
index 4d550759a25f..6f81491f1ffa 100644
--- a/test/Sema/annotate.c
+++ b/test/Sema/annotate.c
@@ -3,5 +3,5 @@
void __attribute__((annotate("foo"))) foo(float *a) {
__attribute__((annotate("bar"))) int x;
__attribute__((annotate(1))) int y; // expected-error {{argument to annotate attribute was not a string literal}}
- __attribute__((annotate("bar", 1))) int z; // expected-error {{attribute requires 1 argument(s)}}
+ __attribute__((annotate("bar", 1))) int z; // expected-error {{attribute takes one argument}}
}
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index d9e08397f2d3..d88abc3c3b9e 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -94,7 +94,7 @@ struct {}; // expected-warning{{declaration does not declare anything}}
struct s2 {
union {
int a;
- }
+ } // expected-warning{{expected ';' at end of declaration list}}
}; // expected-error{{expected member name or ';' after declaration specifiers}}
// Make sure we don't a.k.a. anonymous structs.
diff --git a/test/Sema/arm-layout.c b/test/Sema/arm-layout.c
index 424868510428..d017fdb8aa07 100644
--- a/test/Sema/arm-layout.c
+++ b/test/Sema/arm-layout.c
@@ -42,7 +42,7 @@ check(s3_offset_0, __builtin_offsetof(struct s3, field0) == 0);
check(s3_offset_1, __builtin_offsetof(struct s3, field2) == 7);
struct s4 {
- int field0 : 4
+ int field0 : 4;
};
#ifdef __ARM_EABI__
check(s4_size, sizeof(struct s4) == 4);
diff --git a/test/Sema/attr-args.c b/test/Sema/attr-args.c
new file mode 100644
index 000000000000..61358016fbe1
--- /dev/null
+++ b/test/Sema/attr-args.c
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -DATTR=noreturn -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=always_inline -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=cdecl -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=const -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=fastcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=malloc -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=nothrow -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=stdcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=used -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=unused -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=weak -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+
+#define ATTR_DECL(a) __attribute__((ATTR(a)))
+
+int a;
+
+inline ATTR_DECL(a) void* foo(); // expected-error{{attribute takes no arguments}}
+
+
+
+// RUN: %clang_cc1 -DATTR=noreturn -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=always_inline -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=cdecl -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=const -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=fastcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=malloc -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=nothrow -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=stdcall -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=used -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=unused -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+// RUN: %clang_cc1 -DATTR=weak -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -Wunused -fsyntax-only %s
+
+#define ATTR_DECL(a) __attribute__((ATTR(a)))
+
+int a;
+
+inline ATTR_DECL(a) void* foo(); // expected-error{{attribute takes no arguments}}
+
+
+
diff --git a/test/Sema/attr-availability-ios.c b/test/Sema/attr-availability-ios.c
new file mode 100644
index 000000000000..435e312481d6
--- /dev/null
+++ b/test/Sema/attr-availability-ios.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 "-triple" "x86_64-apple-darwin3.0.0-iphoneos" -fsyntax-only -verify %s
+
+void f0(int) __attribute__((availability(ios,introduced=2.0,deprecated=2.1)));
+void f1(int) __attribute__((availability(ios,introduced=2.1)));
+void f2(int) __attribute__((availability(ios,introduced=2.0,deprecated=3.0)));
+void f3(int) __attribute__((availability(ios,introduced=3.0)));
+void f4(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(ios,introduced=2.0,deprecated=2.1,obsoleted=3.0))); // expected-note{{explicitly marked unavailable}}
+
+void f5(int) __attribute__((availability(ios,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0)));
+void f6(int) __attribute__((availability(ios,deprecated=3.0)));
+void f6(int) __attribute__((availability(ios,introduced=2.0)));
+
+void test() {
+ f0(0); // expected-warning{{'f0' is deprecated: first deprecated in iOS 2.1}}
+ f1(0);
+ f2(0); // expected-warning{{'f2' is deprecated: first deprecated in iOS 3.0}}
+ f3(0);
+ f4(0); // expected-error{{f4' is unavailable: obsoleted in iOS 3.0}}
+ f5(0); // expected-warning{{'f5' is deprecated: first deprecated in iOS 3.0}}
+ f6(0); // expected-warning{{'f6' is deprecated: first deprecated in iOS 3.0}}
+}
diff --git a/test/Sema/attr-availability-macosx.c b/test/Sema/attr-availability-macosx.c
new file mode 100644
index 000000000000..2b7c1e06ace7
--- /dev/null
+++ b/test/Sema/attr-availability-macosx.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 "-triple" "x86_64-apple-darwin9.0.0" -fsyntax-only -verify %s
+
+void f0(int) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6)));
+void f1(int) __attribute__((availability(macosx,introduced=10.5)));
+void f2(int) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5)));
+void f3(int) __attribute__((availability(macosx,introduced=10.6)));
+void f4(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(ios,introduced=2.0,deprecated=3.0))); // expected-note{{explicitly marked unavailable}}
+void f5(int) __attribute__((availability(ios,introduced=3.2), availability(macosx,unavailable))); // expected-note{{function has been explicitly marked unavailable here}}
+
+void test() {
+ f0(0);
+ f1(0);
+ f2(0); // expected-warning{{'f2' is deprecated: first deprecated in Mac OS X 10.5}}
+ f3(0);
+ f4(0); // expected-error{{f4' is unavailable: obsoleted in Mac OS X 10.5}}
+ f5(0); // expected-error{{'f5' is unavailable: not available on Mac OS X}}
+}
diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c
new file mode 100644
index 000000000000..1314cf5a5b03
--- /dev/null
+++ b/test/Sema/attr-availability.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f0() __attribute__((availability(macosx,introduced=10.4,deprecated=10.2))); // expected-warning{{feature cannot be deprecated in Mac OS X version 10.2 before it was introduced in version 10.4; attribute ignored}}
+void f1() __attribute__((availability(ios,obsoleted=2.1,deprecated=3.0))); // expected-warning{{feature cannot be obsoleted in iOS version 2.1 before it was deprecated in version 3.0; attribute ignored}}
+
+void f2() __attribute__((availability(otheros,introduced=2.2))); // expected-warning{{unknown platform 'otheros' in availability macro}}
diff --git a/test/Sema/attr-cleanup.c b/test/Sema/attr-cleanup.c
index 9057c27a56fe..59ebbfc4599f 100644
--- a/test/Sema/attr-cleanup.c
+++ b/test/Sema/attr-cleanup.c
@@ -8,8 +8,8 @@ static int g3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribut
void t1()
{
- int v1 __attribute((cleanup)); // expected-error {{attribute requires 1 argument(s)}}
- int v2 __attribute((cleanup(1, 2))); // expected-error {{attribute requires 1 argument(s)}}
+ int v1 __attribute((cleanup)); // expected-error {{attribute takes one argument}}
+ int v2 __attribute((cleanup(1, 2))); // expected-error {{attribute takes one argument}}
static int v3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}}
diff --git a/test/Sema/attr-naked.c b/test/Sema/attr-naked.c
index 65d1726da133..1ebd78438e2f 100644
--- a/test/Sema/attr-naked.c
+++ b/test/Sema/attr-naked.c
@@ -4,5 +4,5 @@ int a __attribute__((naked)); // expected-warning {{'naked' attribute only appli
void t1() __attribute__((naked));
-void t2() __attribute__((naked(2))); // expected-error {{attribute requires 0 argument(s)}}
+void t2() __attribute__((naked(2))); // expected-error {{attribute takes no arguments}}
diff --git a/test/Sema/attr-nodebug.c b/test/Sema/attr-nodebug.c
index 6865de060266..a66e96168dd6 100644
--- a/test/Sema/attr-nodebug.c
+++ b/test/Sema/attr-nodebug.c
@@ -4,5 +4,5 @@ int a __attribute__((nodebug)); // expected-warning {{'nodebug' attribute only a
void t1() __attribute__((nodebug));
-void t2() __attribute__((nodebug(2))); // expected-error {{attribute requires 0 argument(s)}}
+void t2() __attribute__((nodebug(2))); // expected-error {{attribute takes no arguments}}
diff --git a/test/Sema/attr-noinline.c b/test/Sema/attr-noinline.c
index 8c91b65b4f48..dfc88a8d8fcb 100644
--- a/test/Sema/attr-noinline.c
+++ b/test/Sema/attr-noinline.c
@@ -4,5 +4,5 @@ int a __attribute__((noinline)); // expected-warning {{'noinline' attribute only
void t1() __attribute__((noinline));
-void t2() __attribute__((noinline(2))); // expected-error {{attribute requires 0 argument(s)}}
+void t2() __attribute__((noinline(2))); // expected-error {{attribute takes no arguments}}
diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c
index 5333a2c13fc2..5c643fff718d 100644
--- a/test/Sema/attr-noreturn.c
+++ b/test/Sema/attr-noreturn.c
@@ -13,7 +13,7 @@ int f1() __attribute__((noreturn));
int g0 __attribute__((noreturn)); // expected-warning {{'noreturn' only applies to function types; type here is 'int'}}
-int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute requires 0 argument(s)}}
+int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute takes no arguments}}
void f3() __attribute__((noreturn));
void f3() {
@@ -41,4 +41,4 @@ __attribute__((noreturn)) void f(__attribute__((noreturn)) void (*x)(void)) {
x();
}
-typedef void (*Fun)(void) __attribute__ ((noreturn(2))); // expected-error {{attribute requires 0 argument(s)}}
+typedef void (*Fun)(void) __attribute__ ((noreturn(2))); // expected-error {{attribute takes no arguments}}
diff --git a/test/Sema/attr-regparm.c b/test/Sema/attr-regparm.c
index 4049e0e8a13f..642c07e7bc11 100644
--- a/test/Sema/attr-regparm.c
+++ b/test/Sema/attr-regparm.c
@@ -4,7 +4,7 @@ __attribute((regparm(2))) int x0(void);
__attribute((regparm(1.0))) int x1(void); // expected-error{{'regparm' attribute requires integer constant}}
__attribute((regparm(-1))) int x2(void); // expected-error{{'regparm' parameter must be between 0 and 3 inclusive}}
__attribute((regparm(5))) int x3(void); // expected-error{{'regparm' parameter must be between 0 and 3 inclusive}}
-__attribute((regparm(5,3))) int x4(void); // expected-error{{attribute requires 1 argument(s)}}
+__attribute((regparm(5,3))) int x4(void); // expected-error{{attribute takes one argument}}
void __attribute__((regparm(3))) x5(int);
void x5(int); // expected-note{{previous declaration is here}}
diff --git a/test/Sema/attr-unused.c b/test/Sema/attr-unused.c
index 6a7ea951a360..07c65cbd9aed 100644
--- a/test/Sema/attr-unused.c
+++ b/test/Sema/attr-unused.c
@@ -9,7 +9,7 @@ int f1() __attribute__((unused));
int g0 __attribute__((unused));
-int f2() __attribute__((unused(1, 2))); // expected-error {{attribute requires 0 argument(s)}}
+int f2() __attribute__((unused(1, 2))); // expected-error {{attribute takes no arguments}}
struct Test0_unused {} __attribute__((unused));
struct Test0_not_unused {};
diff --git a/test/Sema/block-args.c b/test/Sema/block-args.c
index e2e2d8e44622..5ee383eebb02 100644
--- a/test/Sema/block-args.c
+++ b/test/Sema/block-args.c
@@ -40,3 +40,8 @@ void test4() {
int (^f)() = ^((x)) { }; // expected-error {{expected ')'}} expected-warning {{type specifier missing}} expected-note {{to match this}}
}
+// rdar://problem/9170609
+void test5_helper(void (^)(int, int[*]));
+void test5(void) {
+ test5_helper(^(int n, int array[n]) {});
+}
diff --git a/test/Sema/builtins-decl.c b/test/Sema/builtins-decl.c
new file mode 100644
index 000000000000..19bdb840ccfb
--- /dev/null
+++ b/test/Sema/builtins-decl.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=i686-mingw32
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=x86_64-mingw32
+
+// mingw-w64's intrin.h has decls below.
+// we should accept them.
+extern unsigned int __builtin_ia32_crc32qi (unsigned int, unsigned char);
+extern unsigned int __builtin_ia32_crc32hi (unsigned int, unsigned short);
+extern unsigned int __builtin_ia32_crc32si (unsigned int, unsigned int);
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index 4072faa94b9f..64efefc7fdad 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -27,7 +27,7 @@ int test6(float a, long double b) {
void test7() {
const void *X;
X = CFSTR("\242"); // expected-warning {{input conversion stopped}}
- X = CFSTR("\0"); // expected-warning {{ CFString literal contains NUL character }}
+ X = CFSTR("\0"); // no-warning
X = CFSTR(242); // expected-error {{ CFString literal is not a string constant }} expected-warning {{incompatible integer to pointer conversion}}
X = CFSTR("foo", "bar"); // expected-error {{too many arguments to function call}}
}
diff --git a/test/Sema/c89.c b/test/Sema/c89.c
index 038f7e537d76..670dd15539f0 100644
--- a/test/Sema/c89.c
+++ b/test/Sema/c89.c
@@ -80,3 +80,5 @@ void test13b() {
/* Make sure we allow *test14 as a "function designator" */
int test14() { return (&*test14)(); }
+
+int test15[5] = { [2] = 1 }; /* expected-warning {{designated initializers are a C99 feature}} */
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
index 92a20572a2c1..25669f08ae29 100644
--- a/test/Sema/callingconv.c
+++ b/test/Sema/callingconv.c
@@ -6,7 +6,7 @@ void __attribute__((fastcall)) foo(float *a) {
void __attribute__((stdcall)) bar(float *a) {
}
-void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{attribute requires 0 argument(s)}}
+void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{attribute takes no arguments}}
}
void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use fastcall calling convention}}
@@ -20,7 +20,7 @@ void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic
void __attribute__((cdecl)) ctest0() {}
-void __attribute__((cdecl(1))) ctest1(float x) {} // expected-error {{attribute requires 0 argument(s)}}
+void __attribute__((cdecl(1))) ctest1(float x) {} // expected-error {{attribute takes no arguments}}
void (__attribute__((fastcall)) *pfoo)(float*) = foo;
diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c
index aa0cee5da5b3..56c429c58c2a 100644
--- a/test/Sema/const-eval.c
+++ b/test/Sema/const-eval.c
@@ -58,7 +58,7 @@ EVAL_EXPR(29, (_Complex int)1 ? 1 : -1)
// PR4027 + rdar://6808859
-struct a { int x, y };
+struct a { int x, y; };
static struct a V2 = (struct a)(struct a){ 1, 2};
static const struct a V1 = (struct a){ 1, 2};
diff --git a/test/Sema/constructor-attribute.c b/test/Sema/constructor-attribute.c
index 2decebbd284a..382591654d91 100644
--- a/test/Sema/constructor-attribute.c
+++ b/test/Sema/constructor-attribute.c
@@ -3,13 +3,13 @@
int x __attribute__((constructor)); // expected-warning {{'constructor' attribute only applies to functions}}
int f() __attribute__((constructor));
int f() __attribute__((constructor(1)));
-int f() __attribute__((constructor(1,2))); // expected-error {{attribute requires 0 or 1 argument(s)}}
+int f() __attribute__((constructor(1,2))); // expected-error {{attribute takes no more than 1 argument}}
int f() __attribute__((constructor(1.0))); // expected-error {{'constructor' attribute requires parameter 1 to be an integer constant}}
int x __attribute__((destructor)); // expected-warning {{'destructor' attribute only applies to functions}}
int f() __attribute__((destructor));
int f() __attribute__((destructor(1)));
-int f() __attribute__((destructor(1,2))); // expected-error {{attribute requires 0 or 1 argument(s)}}
+int f() __attribute__((destructor(1,2))); // expected-error {{attribute takes no more than 1 argument}}
int f() __attribute__((destructor(1.0))); // expected-error {{'destructor' attribute requires parameter 1 to be an integer constant}}
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index 619d6993251f..1eaf7082d67e 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -323,6 +323,10 @@ void test_8559831(enum E8559831b value_a, E8559831c value_c) {
enum E8559831a a1 = value_a; // expected-warning{{implicit conversion from enumeration type 'enum E8559831b' to different enumeration type 'enum E8559831a'}}
a1 = value_a; // expected-warning{{implicit conversion from enumeration type 'enum E8559831b' to different enumeration type 'enum E8559831a'}}
+ test_8559831_a(E8559831b_val); // expected-warning{{implicit conversion from enumeration type 'enum E8559831b' to different enumeration type 'enum E8559831a'}}
+ enum E8559831a a1a = E8559831b_val; // expected-warning{{implicit conversion from enumeration type 'enum E8559831b' to different enumeration type 'enum E8559831a'}}
+ a1 = E8559831b_val; // expected-warning{{implicit conversion from enumeration type 'enum E8559831b' to different enumeration type 'enum E8559831a'}}
+
test_8559831_a(value_c); // expected-warning{{implicit conversion from enumeration type 'E8559831c' to different enumeration type 'enum E8559831a'}}
enum E8559831a a2 = value_c; // expected-warning{{implicit conversion from enumeration type 'E8559831c' to different enumeration type 'enum E8559831a'}}
a2 = value_c; // expected-warning{{implicit conversion from enumeration type 'E8559831c' to different enumeration type 'enum E8559831a'}}
diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c
index 8f9f795d00dd..2b8cfbfa68f5 100644
--- a/test/Sema/expr-address-of.c
+++ b/test/Sema/expr-address-of.c
@@ -107,3 +107,14 @@ char* f7() {
void* t3 = &(*(void*)0);
}
+
+void f8() {
+ void *dummy0 = &f8(); // expected-error {{address expression must be an lvalue or a function designator}}
+
+ extern void v;
+ void *dummy1 = &(1 ? v : f8()); // expected-error {{address expression must be an lvalue or a function designator}}
+
+ void *dummy2 = &(f8(), v); // expected-error {{address expression must be an lvalue or a function designator}}
+
+ void *dummy3 = &({ ; }); // expected-error {{address expression must be an lvalue or a function designator}}
+}
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 0d6c5488de5f..e4eeaec05d97 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -12,6 +12,14 @@
} while (0)
+// Test that we don't report divide-by-zero errors in unreachable code.
+// This test should be left as is, as it also tests CFG functionality.
+void radar9171946() {
+ if (0) {
+ 0 / (0 ? 1 : 0); // expected-warning {{expression result unused}}
+ }
+}
+
int test_pr8876() {
PR8876(0); // no-warning
PR8876_pos(0); // expected-warning{{indirection of non-volatile null pointer will be deleted, not trap}} expected-note{{consider using __builtin_trap() or qualifying pointer with 'volatile'}}
@@ -155,7 +163,7 @@ void test17(int x) {
}
// PR6501
-void test18_a(int a);
+void test18_a(int a); // expected-note {{'test18_a' declared here}}
void test18(int b) {
test18_a(b, b); // expected-error {{too many arguments to function call, expected 1, have 2}}
test18_a(); // expected-error {{too few arguments to function call, expected 1, have 0}}
@@ -166,6 +174,12 @@ void test19() {
*(int*)0 = 0; // expected-warning {{indirection of non-volatile null pointer}} \
// expected-note {{consider using __builtin_trap}}
*(volatile int*)0 = 0; // Ok.
+
+ // rdar://9269271
+ int x = *(int*)0; // expected-warning {{indirection of non-volatile null pointer}} \
+ // expected-note {{consider using __builtin_trap}}
+ int x2 = *(volatile int*)0; // Ok.
+ int *p = &(*(int*)0); // Ok;
}
int test20(int x) {
diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c
index 7cd76c7c37e7..c2fa2f770745 100644
--- a/test/Sema/format-strings-fixit.c
+++ b/test/Sema/format-strings-fixit.c
@@ -1,6 +1,7 @@
// RUN: cp %s %t
// RUN: %clang_cc1 -pedantic -Wall -fixit %t || true
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror %t
+// RUN: %clang_cc1 -E -o - %t | FileCheck %s
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -41,4 +42,29 @@ void test() {
// Bad length modifiers
printf("%hhs", "foo");
printf("%1$zp", (void *)0);
+
+ // Perserve the original formatting for unsigned integers.
+ unsigned long val = 42;
+ printf("%X", val);
}
+
+// Validate the fixes...
+// CHECK: printf("%d", (int) 123);
+// CHECK: printf("abc%s", "testing testing 123");
+// CHECK: printf("%ld", (long) -12);
+// CHECK: printf("%d", 123);
+// CHECK: printf("%s\n", "x");
+// CHECK: printf("%f\n", 1.23);
+// CHECK: printf("%.2llu", (unsigned long long) 123456);
+// CHECK: printf("%1Lf", (long double) 1.23);
+// CHECK: printf("%0u", (unsigned) 31337);
+// CHECK: printf("%p", (void *) 0);
+// CHECK: printf("%+f", 1.23);
+// CHECK: printf("%-f", 1.23);
+// CHECK: printf("%1$d:%2$.*3$d:%4$.*3$d\n", 1, 2, 3, 4);
+// CHECK: printf("%10.5ld", 1l);
+// CHECK: printf("%c", 'a');
+// CHECK: printf("%-f", 1.23);
+// CHECK: printf("%s", "foo");
+// CHECK: printf("%1$p", (void *)0);
+// CHECK: printf("%lX", val);
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
index 27ec163ea9cb..7076bdf3bd1f 100644
--- a/test/Sema/function-redecl.c
+++ b/test/Sema/function-redecl.c
@@ -2,7 +2,7 @@
// PR3588
void g0(int, int);
-void g0(); // expected-note{{previous declaration is here}}
+void g0(); // expected-note{{previous declaration is here}} expected-note{{'g0' declared here}}
void f0() {
g0(1, 2, 3); // expected-error{{too many arguments to function call}}
diff --git a/test/Sema/generic-selection.c b/test/Sema/generic-selection.c
new file mode 100644
index 000000000000..8cef975c709c
--- /dev/null
+++ b/test/Sema/generic-selection.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s
+
+void foo(int n) {
+ (void) _Generic(0,
+ struct A: 0, // expected-error {{type 'struct A' in generic association incomplete}}
+ void(): 0, // expected-error {{type 'void ()' in generic association not an object type}}
+ int[n]: 0); // expected-error {{type 'int [n]' in generic association is a variably modified type}}
+
+ (void) _Generic(0,
+ void (*)(): 0, // expected-note {{compatible type 'void (*)()' specified here}}
+ void (*)(void): 0); // expected-error {{type 'void (*)(void)' in generic association compatible with previously specified type 'void (*)()'}}
+
+ (void) _Generic((void (*)()) 0, // expected-error {{controlling expression type 'void (*)()' compatible with 2 generic association types}}
+ void (*)(int): 0, // expected-note {{compatible type 'void (*)(int)' specified here}}
+ void (*)(void): 0); // expected-note {{compatible type 'void (*)(void)' specified here}}
+
+ (void) _Generic(0, // expected-error {{controlling expression type 'int' not compatible with any generic association type}}
+ char: 0, short: 0, long: 0);
+
+ int a1[_Generic(0, int: 1, short: 2, float: 3, default: 4) == 1 ? 1 : -1];
+ int a2[_Generic(0, default: 1, short: 2, float: 3, int: 4) == 4 ? 1 : -1];
+ int a3[_Generic(0L, int: 1, short: 2, float: 3, default: 4) == 4 ? 1 : -1];
+ int a4[_Generic(0L, default: 1, short: 2, float: 3, int: 4) == 1 ? 1 : -1];
+ int a5[_Generic(0, int: 1, short: 2, float: 3) == 1 ? 1 : -1];
+ int a6[_Generic(0, short: 1, float: 2, int: 3) == 3 ? 1 : -1];
+}
diff --git a/test/Sema/incomplete-call.c b/test/Sema/incomplete-call.c
index 3ef578d59f6f..d34bda54986c 100644
--- a/test/Sema/incomplete-call.c
+++ b/test/Sema/incomplete-call.c
@@ -6,8 +6,8 @@ struct foo a(); // expected-note {{'a' declared here}}
void b(struct foo);
void c();
-void func() {
+void func(void *p) {
a(); // expected-error{{calling 'a' with incomplete return type 'struct foo'}}
- b(*(struct foo*)0); // expected-error{{argument type 'struct foo' is incomplete}}
- c(*(struct foo*)0); // expected-error{{argument type 'struct foo' is incomplete}}
+ b(*(struct foo*)p); // expected-error{{argument type 'struct foo' is incomplete}}
+ c(*(struct foo*)p); // expected-error{{argument type 'struct foo' is incomplete}}
}
diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c
index d054a0476505..6243af619398 100644
--- a/test/Sema/knr-def-call.c
+++ b/test/Sema/knr-def-call.c
@@ -36,6 +36,8 @@ void proto(x)
}
void use_proto() {
- proto(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}}
- (&proto)(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}}
+ proto(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ (&proto)(42.0); // expected-warning{{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
}
diff --git a/test/Sema/memset-invalid.c b/test/Sema/memset-invalid.c
new file mode 100644
index 000000000000..c763858e26ec
--- /dev/null
+++ b/test/Sema/memset-invalid.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+
+char memset(); // expected-warning {{incompatible redeclaration of library function 'memset'}} expected-note{{'memset' is a builtin with type}}
+char test() {
+ return memset();
+}
diff --git a/test/Sema/missing-field-initializers.c b/test/Sema/missing-field-initializers.c
index 6aa48ba9e419..90e0e2a345b0 100644
--- a/test/Sema/missing-field-initializers.c
+++ b/test/Sema/missing-field-initializers.c
@@ -46,7 +46,7 @@ struct Three data[] = {
{ { .two = { 1.0f, 2.0f } } } // expected-warning {{missing field 'e' initializer}}
};
-struct { int:5; int a; int:5; int b; int:5 } noNamedImplicit[] = {
+struct { int:5; int a; int:5; int b; int:5; } noNamedImplicit[] = {
{ 1, 2 },
{ 1 } // expected-warning {{missing field 'b' initializer}}
};
diff --git a/test/Sema/neon-vector-types.c b/test/Sema/neon-vector-types.c
index 1f501776cc8e..cbf013398a26 100644
--- a/test/Sema/neon-vector-types.c
+++ b/test/Sema/neon-vector-types.c
@@ -16,7 +16,7 @@ typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t;
// The attributes must have a single argument.
-typedef __attribute__((neon_vector_type(2, 4))) int only_one_arg; // expected-error{{attribute requires 1 argument(s)}}
+typedef __attribute__((neon_vector_type(2, 4))) int only_one_arg; // expected-error{{attribute takes one argument}}
// The number of elements must be an ICE.
typedef __attribute__((neon_vector_type(2.0))) int non_int_width; // expected-error{{attribute requires integer constant}}
diff --git a/test/Sema/overloaded-func-transparent-union.c b/test/Sema/overloaded-func-transparent-union.c
new file mode 100644
index 000000000000..fa0314e946f2
--- /dev/null
+++ b/test/Sema/overloaded-func-transparent-union.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+// rdar:// 9129552
+// PR9406
+
+typedef struct {
+ char *str;
+ char *str2;
+} Class;
+
+typedef union {
+ Class *object;
+} Instance __attribute__((transparent_union));
+
+__attribute__((overloadable)) void Class_Init(Instance this, char *str, void *str2) {
+ this.object->str = str;
+ this.object->str2 = str2;
+}
+
+__attribute__((overloadable)) void Class_Init(Instance this, char *str) {
+ this.object->str = str;
+ this.object->str2 = str;
+}
+
+int main(void) {
+ Class obj;
+ Class_Init(&obj, "Hello ", " World");
+}
+
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index b45d8512f6bf..a25ded66a665 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -26,7 +26,8 @@ void bitwise_rel(unsigned i) {
(void)(i == 1 | i == 2 | i == 3);
(void)(i != 1 & i != 2 & i != 3);
- (void)(i || i && i); // expected-warning {{'&&' within '||'}} \
+ (void)(i ||
+ i && i); // expected-warning {{'&&' within '||'}} \
// expected-note {{place parentheses around the '&&' expression to silence this warning}}
(void)(i || i && "w00t"); // no warning.
(void)("w00t" && i || i); // no warning.
diff --git a/test/Sema/pragma-ms_struct.c b/test/Sema/pragma-ms_struct.c
new file mode 100644
index 000000000000..b2c2684c6194
--- /dev/null
+++ b/test/Sema/pragma-ms_struct.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin9 %s
+
+#pragma ms_struct on
+
+#pragma ms_struct off
+
+#pragma ms_struct reset
+
+#pragma ms_struct // expected-warning {{incorrect use of '#pragma ms_struct on|off' - ignored}}
+
+#pragma ms_struct on top of spaghetti // expected-warning {{extra tokens at end of '#pragma ms_struct' - ignored}}
+
+struct foo
+{
+ int a;
+ int b;
+ char c;
+};
+
+
+struct {
+ unsigned long bf_1 : 12;
+ unsigned long : 0;
+ unsigned long bf_2 : 12;
+} __attribute__((__ms_struct__)) t1;
+
+struct S {
+ double __attribute__((ms_struct)) d; // expected-warning {{'ms_struct' attribute ignored}}
+ unsigned long bf_1 : 12;
+ unsigned long : 0;
+ unsigned long bf_2 : 12;
+} __attribute__((ms_struct)) t2;
+
+
diff --git a/test/Sema/sentinel-attribute.c b/test/Sema/sentinel-attribute.c
index ed0ef89db70b..e5cbf6ee04af 100644
--- a/test/Sema/sentinel-attribute.c
+++ b/test/Sema/sentinel-attribute.c
@@ -5,7 +5,7 @@ void f1(int a, ...) __attribute__ ((sentinel));
void f2(int a, ...) __attribute__ ((sentinel(1)));
void f3(int a, ...) __attribute__ ((sentinel("hello"))); //expected-error{{'sentinel' attribute requires parameter 1 to be an integer constant}}
-void f4(int a, ...) __attribute__ ((sentinel(1, 2, 3))); //expected-error{{attribute requires 0, 1 or 2 argument(s)}}
+void f4(int a, ...) __attribute__ ((sentinel(1, 2, 3))); //expected-error{{attribute takes no more than 2 arguments}}
void f4(int a, ...) __attribute__ ((sentinel(-1))); //expected-error{{parameter 1 less than zero}}
void f4(int a, ...) __attribute__ ((sentinel(0, 2))); // expected-error{{parameter 2 not 0 or 1}}
diff --git a/test/Sema/shift.c b/test/Sema/shift.c
index df6b1141bdfc..28407be079f4 100644
--- a/test/Sema/shift.c
+++ b/test/Sema/shift.c
@@ -56,3 +56,13 @@ void test() {
#define ashift 8
enum { b = (a << ashift) };
+// Don't warn for negative shifts in code that is unreachable.
+void test_pr5544() {
+ (void) (((1) > 63 && (1) < 128 ? (((unsigned long long) 1)<<((1)-64)) : (unsigned long long) 0)); // no-warning
+}
+
+void test_shift_too_much(char x) {
+ if (0)
+ (void) (x >> 80); // no-warning
+ (void) (x >> 80); // expected-warning {{shift count >= width of type}}
+}
diff --git a/test/Sema/static-assert.c b/test/Sema/static-assert.c
new file mode 100644
index 000000000000..13d70708582b
--- /dev/null
+++ b/test/Sema/static-assert.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s
+
+_Static_assert("foo", "string is nonzero"); // expected-error {{static_assert expression is not an integral constant expression}}
+
+_Static_assert(1, "1 is nonzero");
+_Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}}
+
+void foo(void) {
+ _Static_assert(1, "1 is nonzero");
+ _Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}}
+}
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
index 3639d2479b97..e1c7073e01b2 100644
--- a/test/Sema/struct-decl.c
+++ b/test/Sema/struct-decl.c
@@ -46,3 +46,14 @@ struct s0 f0(void) {}
struct x0 {
unsigned int x1;
};
+
+// rdar://problem/9150338
+static struct test1 { // expected-warning {{'static' ignored on this declaration}}
+ int x;
+};
+const struct test2 { // expected-warning {{'const' ignored on this declaration}}
+ int x;
+};
+inline struct test3 { // expected-warning {{'inline' ignored on this declaration}}
+ int x;
+};
diff --git a/test/Sema/uninit-variables-vectors.c b/test/Sema/uninit-variables-vectors.c
new file mode 100644
index 000000000000..10a8ecc378f0
--- /dev/null
+++ b/test/Sema/uninit-variables-vectors.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fsyntax-only -Wuninitialized -fsyntax-only %s -verify
+
+typedef int __v4si __attribute__((__vector_size__(16)));
+typedef float __m128 __attribute__((__vector_size__(16)));
+__m128 _mm_xor_ps(__m128 a, __m128 b);
+__m128 _mm_loadu_ps(const float *p);
+
+void test1(float *input) {
+ __m128 x, y, z, w, X; // expected-note {{variable 'x' is declared here}} expected-note {{variable 'y' is declared here}} expected-note {{variable 'w' is declared here}} expected-note {{variable 'z' is declared here}}
+ x = _mm_xor_ps(x,x); // expected-warning {{variable 'x' is uninitialized when used here}}
+ y = _mm_xor_ps(y,y); // expected-warning {{variable 'y' is uninitialized when used here}}
+ z = _mm_xor_ps(z,z); // expected-warning {{variable 'z' is uninitialized when used here}}
+ w = _mm_xor_ps(w,w); // expected-warning {{variable 'w' is uninitialized when used here}}
+ X = _mm_loadu_ps(&input[0]);
+ X = _mm_xor_ps(X,X); // no-warning
+}
+
diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c
index 973e504f634d..60cae802ae73 100644
--- a/test/Sema/uninit-variables.c
+++ b/test/Sema/uninit-variables.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only -fblocks %s -verify
+// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -Wconditional-uninitialized -fsyntax-only -fblocks %s -verify
int test1() {
int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
int test2() {
@@ -18,19 +18,19 @@ int test3() {
int test4() {
int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
- ++x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ ++x; // expected-warning{{variable 'x' is uninitialized when used here}}
return x;
}
int test5() {
int x, y; // expected-note{{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
- x = y; // expected-warning{{variable 'y' is possibly uninitialized when used here}}
+ x = y; // expected-warning{{variable 'y' is uninitialized when used here}}
return x;
}
int test6() {
int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
- x += 2; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ x += 2; // expected-warning{{variable 'x' is uninitialized when used here}}
return x;
}
@@ -38,7 +38,7 @@ int test7(int y) {
int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
if (y)
x = 1;
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' may be uninitialized when used here}}
}
int test8(int y) {
@@ -57,7 +57,7 @@ int test9(int n) {
break;
x = 1;
}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' may be uninitialized when used here}}
}
int test10(unsigned n) {
@@ -65,7 +65,7 @@ int test10(unsigned n) {
for (unsigned i = 0 ; i < n; ++i) {
x = 1;
}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' may be uninitialized when used here}}
}
int test11(unsigned n) {
@@ -73,11 +73,11 @@ int test11(unsigned n) {
for (unsigned i = 0 ; i <= n; ++i) {
x = 1;
}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' may be uninitialized when used here}}
}
void test12(unsigned n) {
- for (unsigned i ; n ; ++i) ; // expected-warning{{variable 'i' is possibly uninitialized when used here}} expected-note{{variable 'i' is declared here}} expected-note{{add initialization to silence this warning}}
+ for (unsigned i ; n ; ++i) ; // expected-warning{{variable 'i' may be uninitialized when used here}} expected-note{{variable 'i' is declared here}} expected-note{{add initialization to silence this warning}}
}
int test13() {
@@ -91,8 +91,10 @@ void test14() {
for (;;) {}
}
-void test15() {
- int x = x; // expected-warning{{variable 'x' is possibly uninitialized when used here}} expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+int test15() {
+ int x = x; // no-warning: signals intended lack of initialization. \
+ // expected-note{{variable 'x' is declared here}}
+ return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
// Don't warn in the following example; shows dataflow confluence.
@@ -107,7 +109,7 @@ void test17() {
// Don't warn multiple times about the same uninitialized variable
// along the same path.
int *x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
- *x = 1; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ *x = 1; // expected-warning{{variable 'x' is uninitialized when used here}}
*x = 1; // no-warning
}
@@ -132,14 +134,14 @@ int test19() {
int test20() {
int z; // expected-note{{variable 'z' is declared here}} expected-note{{add initialization to silence this warning}}
if ((test19_aux1() + test19_aux2() && test19_aux1()) || test19_aux3(&z))
- return z; // expected-warning{{variable 'z' is possibly uninitialized when used here}}
+ return z; // expected-warning{{variable 'z' may be uninitialized when used here}}
return 0;
}
int test21(int x, int y) {
int z; // expected-note{{variable 'z' is declared here}} expected-note{{add initialization to silence this warning}}
if ((x && y) || test19_aux3(&z) || test19_aux2())
- return z; // expected-warning{{variable 'z' is possibly uninitialized when used here}}
+ return z; // expected-warning{{variable 'z' may be uninitialized when used here}}
return 0;
}
@@ -167,18 +169,18 @@ int test24(int flag) {
val = 1;
if (!flag)
val = 1;
- return val; // expected-warning{{variable 'val' is possibly uninitialized when used here}}
+ return val; // expected-warning{{variable 'val' may be uninitialized when used here}}
}
float test25() {
float x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
typedef int MyInt;
MyInt test26() {
MyInt x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
// Test handling of sizeof().
@@ -189,12 +191,12 @@ int test27() {
int test28() {
int len; // expected-note{{variable 'len' is declared here}} expected-note{{add initialization to silence this warning}}
- return sizeof(int[len]); // expected-warning{{variable 'len' is possibly uninitialized when used here}}
+ return sizeof(int[len]); // expected-warning{{variable 'len' is uninitialized when used here}}
}
void test29() {
int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
- (void) ^{ (void) x; }; // expected-warning{{variable 'x' is possibly uninitialized when captured by block}}
+ (void) ^{ (void) x; }; // expected-warning{{variable 'x' is uninitialized when captured by block}}
}
void test30() {
@@ -220,7 +222,7 @@ void test_33() {
int test_34() {
int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
(void) x;
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
// Test that this case doesn't crash.
@@ -235,7 +237,7 @@ void test36()
void **pc; // expected-note{{variable 'pc' is declared here}} expected-note{{add initialization to silence this warning}}
void *dummy[] = { &&L1, &&L2 };
L1:
- goto *pc; // expected-warning{{variable 'pc' is possibly uninitialized when used here}}
+ goto *pc; // expected-warning{{variable 'pc' may be uninitialized when used here}}
L2:
goto *pc;
}
@@ -260,3 +262,80 @@ int test38(int r, int x, int y)
return ((r < 0) || ((r == 0) && (x < y)));
}
+int test39(int x) {
+ int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ int z = x + y; // expected-warning {{variable 'y' is uninitialized when used here}}
+ return z;
+}
+
+
+int test40(int x) {
+ int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ return x ? 1 : y; // expected-warning {{variable 'y' is uninitialized when used here}}
+}
+
+int test41(int x) {
+ int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ if (x) y = 1; // no-warning
+ return y; // expected-warning {{variable 'y' may be uninitialized when used here}}
+}
+
+void test42() {
+ int a;
+ a = 30; // no-warning
+}
+
+void test43_aux(int x);
+void test43(int i) {
+ int x; // expected-note {{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ for (i = 0 ; i < 10; i++)
+ test43_aux(x++); // expected-warning {{variable 'x' may be uninitialized when used here}}
+}
+
+void test44(int i) {
+ int x = i;
+ int y; // expected-note {{variable 'y' is declared here}} expected-note{{add initialization to silence this warning}}
+ for (i = 0; i < 10; i++ ) {
+ test43_aux(x++); // no-warning
+ x += y; // expected-warning {{variable 'y' may be uninitialized when used here}}
+ }
+}
+
+int test45(int j) {
+ int x = 1, y = x + 1;
+ if (y) // no-warning
+ return x;
+ return y;
+}
+
+void test46()
+{
+ int i; // expected-note {{variable 'i' is declared here}} expected-note{{add initialization to silence this warning}}
+ int j = i ? : 1; // expected-warning {{variable 'i' is uninitialized when used here}}
+}
+
+void *test47(int *i)
+{
+ return i ? : 0; // no-warning
+}
+
+void *test49(int *i)
+{
+ int a;
+ return &a ? : i; // no-warning
+}
+
+void test50()
+{
+ char c[1 ? : 2]; // no-warning
+}
+
+int test51(void)
+{
+ __block int a;
+ ^(void) {
+ a = 42;
+ }();
+ return a; // no-warning
+}
+
diff --git a/test/Sema/vector-ops.c b/test/Sema/vector-ops.c
index 20575ec510c3..ca397375d739 100644
--- a/test/Sema/vector-ops.c
+++ b/test/Sema/vector-ops.c
@@ -12,6 +12,9 @@ void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
(void)(~v2ua);
(void)(~v2fa); // expected-error{{invalid argument type 'v2f' to unary}}
+ // Comparison operators
+ v2ua = (v2ua==v2sa);
+
// Arrays
int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u'}}
int array2[17];
diff --git a/test/Sema/warn-gnu-designators.c b/test/Sema/warn-gnu-designators.c
index d5ac8cfe5539..bdb3374288df 100644
--- a/test/Sema/warn-gnu-designators.c
+++ b/test/Sema/warn-gnu-designators.c
@@ -1,2 +1,2 @@
// RUN: %clang_cc1 -Wno-gnu-designator -verify %s
-struct { int x, y, z[12] } value = { x:17, .z [3 ... 5] = 7 };
+struct { int x, y, z[12]; } value = { x:17, .z [3 ... 5] = 7 };
diff --git a/test/Sema/warn-unused-function.c b/test/Sema/warn-unused-function.c
index 5bbcf18a623d..8f4cdcba881e 100644
--- a/test/Sema/warn-unused-function.c
+++ b/test/Sema/warn-unused-function.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-function -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-function -Wunneeded-internal-declaration -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
@@ -6,7 +6,7 @@ void foo() {}
static void f2() {}
static void f1() {f2();} // expected-warning{{unused}}
-static int f0() { return 17; } // expected-warning{{unused}}
+static int f0() { return 17; } // expected-warning{{not needed and will not be emitted}}
int x = sizeof(f0());
static void f3();
@@ -46,7 +46,7 @@ static void f12(void) { } // expected-warning{{unused}}
static void f12(void);
// PR7923
-static void unused(void) { unused(); } // expected-warning{{unused}}
+static void unused(void) { unused(); } // expected-warning{{not needed and will not be emitted}}
// rdar://8728293
static void cleanupMalloc(char * const * const allocation) { }
diff --git a/test/Sema/warn-unused-value.c b/test/Sema/warn-unused-value.c
index 876eb9e4823e..95cd8fb70400 100644
--- a/test/Sema/warn-unused-value.c
+++ b/test/Sema/warn-unused-value.c
@@ -72,6 +72,15 @@ int test_logical_bar() {
return x;
}
+// PR8282
+void conditional_for_control_flow(int cond, int x, int y)
+{
+ cond? y++ : x; // no-warning
+ cond? y : ++x; // no-warning
+ cond? (x |= y) : ++x; // no-warning
+ cond? y : x; // expected-warning {{expression result unused}}
+}
+
struct s0 { int f0; };
void f0(int a);
diff --git a/test/Sema/warn-write-strings.c b/test/Sema/warn-write-strings.c
index dd0bb8a6d83a..dee554cf6b57 100644
--- a/test/Sema/warn-write-strings.c
+++ b/test/Sema/warn-write-strings.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
+// RUN: %clang_cc1 -verify -fsyntax-only -fconst-strings %s
// PR4804
char* x = "foo"; // expected-warning {{initializing 'char *' with an expression of type 'const char [4]' discards qualifiers}}
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 30ad4d0482f6..2d620b6da620 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -1,24 +1,16 @@
-// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions -fexceptions
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -verify -fms-extensions -fexceptions -fcxx-exceptions
// ::type_info is predeclared with forward class declartion
void f(const type_info &a);
-// The following three are all equivalent when ms-extensions are on
-void foo() throw(int);
-void foo() throw(int, long);
-void foo() throw(...);
-void foo(); // expected-note {{previous declaration}}
-
-// Only nothrow specification is treated specially.
-void foo() throw(); // expected-error {{exception specification in declaration does not match previous declaration}}
-// throw(...)
-void r3();
-void r3() throw(...);
+// Microsoft doesn't validate exception specification.
+void foo(); // expected-note {{previous declaration}}
+void foo() throw(); // expected-warning {{exception specification in declaration does not match previous declaration}}
-void r6() throw(...);
-void r6() throw(int); // okay
+void r6() throw(...); // expected-note {{previous declaration}}
+void r6() throw(int); // expected-warning {{exception specification in declaration does not match previous declaration}}
struct Base {
virtual void f2();
@@ -122,3 +114,69 @@ struct X0 {
enum : long long { // expected-warning{{enumeration types with a fixed underlying type are a Microsoft extension}}
SomeValue = 0x100000000
};
+
+
+class AAA {
+__declspec(dllimport) void f(void) { }
+void f2(void);
+};
+
+__declspec(dllimport) void AAA::f2(void) { // expected-error {{dllimport attribute can be applied only to symbol}}
+
+}
+
+
+
+template <class T>
+class BB {
+public:
+ void f(int g = 10 ); // expected-note {{previous definition is here}}
+};
+
+template <class T>
+void BB<T>::f(int g = 0) { } // expected-warning {{redefinition of default argument}}
+
+
+namespace MissingTypename {
+
+template<class T> class A {
+public:
+ typedef int TYPE;
+};
+
+template<class T> class B {
+public:
+ typedef int TYPE;
+};
+
+
+template<class T, class U>
+class C : private A<T>, public B<U> {
+public:
+ typedef A<T> Base1;
+ typedef B<U> Base2;
+ typedef A<U> Base3;
+
+ A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
+ Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
+
+ B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}}
+ Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}}
+
+ A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}}
+ Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}}
+ };
+
+}
+
+
+
+
+extern void static_func();
+void static_func(); // expected-note {{previous declaration is here}}
+
+
+static void static_func() // expected-warning {{static declaration of 'static_func' follows non-static declaration}}
+{
+
+} \ No newline at end of file
diff --git a/test/SemaCXX/PR9459.cpp b/test/SemaCXX/PR9459.cpp
new file mode 100644
index 000000000000..dfb242dc5952
--- /dev/null
+++ b/test/SemaCXX/PR9459.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Don't crash.
+
+template<typename>struct ae_same;
+template<typename>struct ts{}ap()
+{ts<a>::ap<ae_same<int>::&ae_same<>>::p(a); }; // expected-error {{use of undeclared identifier 'a'}}
diff --git a/test/SemaCXX/PR9460.cpp b/test/SemaCXX/PR9460.cpp
new file mode 100644
index 000000000000..2cc435e495d2
--- /dev/null
+++ b/test/SemaCXX/PR9460.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Don't crash.
+
+template<typename aT>
+struct basic_string{
+ a; // expected-error {{requires a type specifier}}
+ basic_string(aT*);
+};
+
+struct runtime_error{ // expected-note {{candidate constructor}}
+ runtime_error( // expected-note {{candidate constructor}}
+basic_string<char> struct{ // expected-error {{cannot combine with previous 'type-name' declaration specifier}}
+a(){ // expected-error {{requires a type specifier}}
+ runtime_error(0); // expected-error {{no matching conversion}}
+}
+}
+);
+};
diff --git a/test/SemaCXX/PR9461.cpp b/test/SemaCXX/PR9461.cpp
new file mode 100644
index 000000000000..ce17931324e0
--- /dev/null
+++ b/test/SemaCXX/PR9461.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Don't crash.
+
+template<typename,typename=int,typename=int>struct basic_string;
+
+typedef basic_string<char> string;
+
+
+
+template<typename aT,typename,typename oc>
+struct basic_string
+{
+int us;
+basic_string(const aT*,const oc&a=int());
+
+int _S_construct();
+
+int _S_construct(int);
+
+_S_construct(); // expected-error {{requires}}
+};
+
+template<typename _CharT,typename _Traits,typename _Alloc>
+basic_string<_CharT,_Traits,_Alloc>::basic_string(const _CharT*,const _Alloc&)
+:us(_S_construct)
+{string a;}
+
+struct runtime_error{runtime_error(string);}; // expected-note 2 {{candidate constructor}}
+
+struct system_error:runtime_error{ // expected-note {{to match}} expected-note {{specified here}}
+system_error():time_error("" // expected-error 4 {{expected}} expected-error {{initializer}} expected-note {{to match}} expected-error {{no matching constructor}}
diff --git a/test/SemaCXX/PR9572.cpp b/test/SemaCXX/PR9572.cpp
new file mode 100644
index 000000000000..d1b70778d062
--- /dev/null
+++ b/test/SemaCXX/PR9572.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+class Base {
+ virtual ~Base();
+};
+struct Foo : public Base {
+ const int kBlah = 3; // expected-error{{fields can only be initialized in constructors}}
+ Foo();
+};
+struct Bar : public Foo {
+ Bar() { }
+};
+struct Baz {
+ Foo f;
+ Baz() { }
+};
diff --git a/test/SemaCXX/__try.cpp b/test/SemaCXX/__try.cpp
new file mode 100644
index 000000000000..cb5d38a097ef
--- /dev/null
+++ b/test/SemaCXX/__try.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fborland-extensions -fcxx-exceptions %s
+
+// This test is from http://docwiki.embarcadero.com/RADStudio/en/Try
+
+int puts(const char *);
+
+template<typename T>
+int printf(const char *, T);
+
+const char * strdup(const char *);
+
+void free(const void *);
+
+#define EXCEPTION_EXECUTE_HANDLER 1
+
+class Exception
+{
+public:
+ Exception(const char* s = "Unknown"){what = strdup(s); }
+ Exception(const Exception& e ){what = strdup(e.what); }
+ ~Exception() {free(what); }
+ const char* msg() const {return what; }
+private:
+ const char* what;
+};
+
+int main()
+{
+ float e, f, g;
+ try
+ {
+ try
+ {
+ f = 1.0;
+ g = 0.0;
+ try
+ {
+ puts("Another exception:");
+
+ e = f / g;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ puts("Caught a C-based exception.");
+ throw(Exception("Hardware error: Divide by 0"));
+ }
+ }
+ catch(const Exception& e)
+ {
+ printf("Caught C++ Exception: %s :\n", e.msg());
+ }
+ }
+ __finally
+ {
+ puts("C++ allows __finally too!");
+ }
+ return e;
+}
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index a1079ff5bac6..a36fd582db2e 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -57,11 +57,12 @@ struct B
struct C {
C &getC() {
- return makeAC; // expected-error{{address of overloaded function 'makeAC'}}
+ // FIXME: this error message is terrible
+ return makeAC; // expected-error{{cannot bind to a value of unrelated type}}
}
- C &makeAC(); //expected-note{{candidate function}}
- const C &makeAC() const; //expected-note{{candidate function}}
+ C &makeAC();
+ const C &makeAC() const;
static void f(); // expected-note{{candidate function}}
static void f(int); // expected-note{{candidate function}}
diff --git a/test/SemaCXX/address-space-conversion.cpp b/test/SemaCXX/address-space-conversion.cpp
new file mode 100644
index 000000000000..d21d4194235b
--- /dev/null
+++ b/test/SemaCXX/address-space-conversion.cpp
@@ -0,0 +1,197 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This test checks for the various conversions and casting operations
+// with address-space-qualified pointers.
+
+struct A { virtual ~A() {} };
+struct B : A { };
+
+typedef void *void_ptr;
+typedef void __attribute__((address_space(1))) *void_ptr_1;
+typedef void __attribute__((address_space(2))) *void_ptr_2;
+
+typedef int *int_ptr;
+typedef int __attribute__((address_space(1))) *int_ptr_1;
+typedef int __attribute__((address_space(2))) *int_ptr_2;
+
+typedef A *A_ptr;
+typedef A __attribute__((address_space(1))) *A_ptr_1;
+typedef A __attribute__((address_space(2))) *A_ptr_2;
+
+typedef B *B_ptr;
+typedef B __attribute__((address_space(1))) *B_ptr_1;
+typedef B __attribute__((address_space(2))) *B_ptr_2;
+
+void test_const_cast(int_ptr ip, int_ptr_1 ip1, int_ptr_2 ip2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ const int *cip,
+ const int __attribute__((address_space(1))) *cip1) {
+ // Cannot use const_cast to cast between address spaces, add an
+ // address space, or remove an address space.
+ (void)const_cast<int_ptr>(ip1); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr>(ip2); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_1>(ip); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_1>(ip2); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_2>(ip); // expected-error{{is not allowed}}
+ (void)const_cast<int_ptr_2>(ip1); // expected-error{{is not allowed}}
+
+ (void)const_cast<A_ptr>(ap1); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr>(ap2); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_1>(ap); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_1>(ap2); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_2>(ap); // expected-error{{is not allowed}}
+ (void)const_cast<A_ptr_2>(ap1); // expected-error{{is not allowed}}
+
+ // It's acceptable to cast away constness.
+ (void)const_cast<int_ptr>(cip);
+ (void)const_cast<int_ptr_1>(cip1);
+}
+
+void test_static_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2) {
+ // Well-formed upcast
+ (void)static_cast<A_ptr>(bp);
+ (void)static_cast<A_ptr_1>(bp1);
+ (void)static_cast<A_ptr_2>(bp2);
+
+ // Well-formed downcast
+ (void)static_cast<B_ptr>(ap);
+ (void)static_cast<B_ptr_1>(ap1);
+ (void)static_cast<B_ptr_2>(ap2);
+
+ // Well-formed cast to/from void
+ (void)static_cast<void_ptr>(ap);
+ (void)static_cast<void_ptr_1>(ap1);
+ (void)static_cast<void_ptr_2>(ap2);
+ (void)static_cast<A_ptr>(vp);
+ (void)static_cast<A_ptr_1>(vp1);
+ (void)static_cast<A_ptr_2>(vp2);
+
+ // Ill-formed upcasts
+ (void)static_cast<A_ptr>(bp1); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr>(bp2); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_1>(bp); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_1>(bp2); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_2>(bp); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr_2>(bp1); // expected-error{{is not allowed}}
+
+ // Ill-formed downcasts
+ (void)static_cast<B_ptr>(ap1); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr>(ap2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_1>(ap); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_1>(ap2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_2>(ap); // expected-error{{casts away qualifiers}}
+ (void)static_cast<B_ptr_2>(ap1); // expected-error{{casts away qualifiers}}
+
+ // Ill-formed cast to/from void
+ (void)static_cast<void_ptr>(ap1); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr>(ap2); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_1>(ap); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_1>(ap2); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_2>(ap); // expected-error{{is not allowed}}
+ (void)static_cast<void_ptr_2>(ap1); // expected-error{{is not allowed}}
+ (void)static_cast<A_ptr>(vp1); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr>(vp2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_1>(vp); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_1>(vp2); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_2>(vp); // expected-error{{casts away qualifiers}}
+ (void)static_cast<A_ptr_2>(vp1); // expected-error{{casts away qualifiers}}
+}
+
+void test_dynamic_cast(A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2) {
+ // Well-formed upcast
+ (void)dynamic_cast<A_ptr>(bp);
+ (void)dynamic_cast<A_ptr_1>(bp1);
+ (void)dynamic_cast<A_ptr_2>(bp2);
+
+ // Well-formed downcast
+ (void)dynamic_cast<B_ptr>(ap);
+ (void)dynamic_cast<B_ptr_1>(ap1);
+ (void)dynamic_cast<B_ptr_2>(ap2);
+
+ // Ill-formed upcasts
+ (void)dynamic_cast<A_ptr>(bp1); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr>(bp2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_1>(bp); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_1>(bp2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_2>(bp); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<A_ptr_2>(bp1); // expected-error{{casts away qualifiers}}
+
+ // Ill-formed downcasts
+ (void)dynamic_cast<B_ptr>(ap1); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr>(ap2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_1>(ap); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_1>(ap2); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_2>(ap); // expected-error{{casts away qualifiers}}
+ (void)dynamic_cast<B_ptr_2>(ap1); // expected-error{{casts away qualifiers}}
+}
+
+void test_reinterpret_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2,
+ const void __attribute__((address_space(1))) *cvp1) {
+ // reinterpret_cast can be used to cast to a different address space.
+ (void)reinterpret_cast<A_ptr>(ap1);
+ (void)reinterpret_cast<A_ptr>(ap2);
+ (void)reinterpret_cast<A_ptr>(bp);
+ (void)reinterpret_cast<A_ptr>(bp1);
+ (void)reinterpret_cast<A_ptr>(bp2);
+ (void)reinterpret_cast<A_ptr>(vp);
+ (void)reinterpret_cast<A_ptr>(vp1);
+ (void)reinterpret_cast<A_ptr>(vp2);
+ (void)reinterpret_cast<A_ptr_1>(ap);
+ (void)reinterpret_cast<A_ptr_1>(ap2);
+ (void)reinterpret_cast<A_ptr_1>(bp);
+ (void)reinterpret_cast<A_ptr_1>(bp1);
+ (void)reinterpret_cast<A_ptr_1>(bp2);
+ (void)reinterpret_cast<A_ptr_1>(vp);
+ (void)reinterpret_cast<A_ptr_1>(vp1);
+ (void)reinterpret_cast<A_ptr_1>(vp2);
+
+ // ... but don't try to cast away constness!
+ (void)reinterpret_cast<A_ptr_2>(cvp1); // expected-error{{casts away qualifiers}}
+}
+
+void test_cstyle_cast(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2,
+ const void __attribute__((address_space(1))) *cvp1) {
+ // C-style casts are the wild west of casts.
+ (void)(A_ptr)(ap1);
+ (void)(A_ptr)(ap2);
+ (void)(A_ptr)(bp);
+ (void)(A_ptr)(bp1);
+ (void)(A_ptr)(bp2);
+ (void)(A_ptr)(vp);
+ (void)(A_ptr)(vp1);
+ (void)(A_ptr)(vp2);
+ (void)(A_ptr_1)(ap);
+ (void)(A_ptr_1)(ap2);
+ (void)(A_ptr_1)(bp);
+ (void)(A_ptr_1)(bp1);
+ (void)(A_ptr_1)(bp2);
+ (void)(A_ptr_1)(vp);
+ (void)(A_ptr_1)(vp1);
+ (void)(A_ptr_1)(vp2);
+ (void)(A_ptr_2)(cvp1);
+}
+
+void test_implicit_conversion(void_ptr vp, void_ptr_1 vp1, void_ptr_2 vp2,
+ A_ptr ap, A_ptr_1 ap1, A_ptr_2 ap2,
+ B_ptr bp, B_ptr_1 bp1, B_ptr_2 bp2) {
+ // Well-formed conversions
+ void_ptr vpA = ap;
+ void_ptr_1 vp_1A = ap1;
+ void_ptr_2 vp_2A = ap2;
+ A_ptr ap_A = bp;
+ A_ptr_1 ap_A1 = bp1;
+ A_ptr_2 ap_A2 = bp2;
+
+ // Ill-formed conversions
+ void_ptr vpB = ap1; // expected-error{{cannot initialize a variable of type}}
+ void_ptr_1 vp_1B = ap2; // expected-error{{cannot initialize a variable of type}}
+ A_ptr ap_B = bp1; // expected-error{{cannot initialize a variable of type}}
+ A_ptr_1 ap_B1 = bp2; // expected-error{{cannot initialize a variable of type}}
+}
diff --git a/test/SemaCXX/address-space-newdelete.cpp b/test/SemaCXX/address-space-newdelete.cpp
new file mode 100644
index 000000000000..b809cd3fadcc
--- /dev/null
+++ b/test/SemaCXX/address-space-newdelete.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void* operator new (__SIZE_TYPE__ size, void* ptr);
+void* operator new[](__SIZE_TYPE__ size, void* ptr);
+
+typedef int __attribute__((address_space(1))) int_1;
+
+void test_new(void *p) {
+ (void)new int_1; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+ (void)new __attribute__((address_space(1))) int; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+ (void)new int_1 [5]; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+ (void)new __attribute__((address_space(1))) int [5]; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+
+ // Placement new
+ (void)new (p) int_1; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+ (void)new (p) __attribute__((address_space(1))) int; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+ (void)new (p) int_1 [5]; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+ (void)new (p) __attribute__((address_space(1))) int [5]; // expected-error{{'new' cannot allocate objects of type 'int' in address space '1'}}
+}
+
+void test_delete(int_1 *ip1) {
+ delete ip1; // expected-error{{'delete' cannot delete objects of type 'int' in address space '1'}}
+ delete [] ip1; // expected-error{{'delete' cannot delete objects of type 'int' in address space '1'}}
+}
diff --git a/test/SemaCXX/address-space-references.cpp b/test/SemaCXX/address-space-references.cpp
new file mode 100644
index 000000000000..f5a63d24a968
--- /dev/null
+++ b/test/SemaCXX/address-space-references.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef int __attribute__((address_space(1))) int_1;
+typedef int __attribute__((address_space(2))) int_2;
+
+void f0(int_1 &); // expected-note{{candidate function not viable: 1st argument ('int') is in address space 0, but parameter must be in address space 1}} \
+// expected-note{{candidate function not viable: 1st argument ('int_2' (aka '__attribute__((address_space(2))) int')) is in address space 2, but parameter must be in address space 1}}
+void f0(const int_1 &); // expected-note{{candidate function not viable: 1st argument ('int') is in address space 0, but parameter must be in address space 1}} \
+// expected-note{{candidate function not viable: 1st argument ('int_2' (aka '__attribute__((address_space(2))) int')) is in address space 2, but parameter must be in address space 1}}
+
+void test_f0() {
+ int i;
+ static int_1 i1;
+ static int_2 i2;
+
+ f0(i); // expected-error{{no matching function for call to 'f0'}}
+ f0(i1);
+ f0(i2); // expected-error{{no matching function for call to 'f0'}}
+}
diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp
index 761edfc6393a..b517e43cf1ff 100644
--- a/test/SemaCXX/alignof-sizeof-reference.cpp
+++ b/test/SemaCXX/alignof-sizeof-reference.cpp
@@ -8,8 +8,8 @@ void test() {
static_assert(sizeof(r) == 1, "bad size");
}
-void f();
-void f(int);
+void f(); // expected-note{{candidate function}}
+void f(int); // expected-note{{candidate function}}
void g() {
- sizeof(&f); // expected-error{{cannot resolve overloaded function from context}}
+ sizeof(&f); // expected-error{{cannot resolve overloaded function 'f' from context}}
}
diff --git a/test/SemaCXX/altivec.cpp b/test/SemaCXX/altivec.cpp
index 921bb73f9ead..504eb1b33660 100644
--- a/test/SemaCXX/altivec.cpp
+++ b/test/SemaCXX/altivec.cpp
@@ -2,6 +2,36 @@
typedef int V4i __attribute__((vector_size(16)));
+void test_vec_step(vector short arg1) {
+ vector bool char vbc;
+ vector signed char vsc;
+ vector unsigned char vuc;
+ vector bool short vbs;
+ vector short vs;
+ vector unsigned short vus;
+ vector pixel vp;
+ vector bool int vbi;
+ vector int vi;
+ vector unsigned int vui;
+ vector float vf;
+
+ vector int *pvi;
+
+ int res1[vec_step(arg1) == 8 ? 1 : -1];
+ int res2[vec_step(vbc) == 16 ? 1 : -1];
+ int res3[vec_step(vsc) == 16 ? 1 : -1];
+ int res4[vec_step(vuc) == 16 ? 1 : -1];
+ int res5[vec_step(vbs) == 8 ? 1 : -1];
+ int res6[vec_step(vs) == 8 ? 1 : -1];
+ int res7[vec_step(vus) == 8 ? 1 : -1];
+ int res8[vec_step(vp) == 8 ? 1 : -1];
+ int res9[vec_step(vbi) == 4 ? 1 : -1];
+ int res10[vec_step(vi) == 4 ? 1 : -1];
+ int res11[vec_step(vui) == 4 ? 1 : -1];
+ int res12[vec_step(vf) == 4 ? 1 : -1];
+ int res13[vec_step(*pvi) == 4 ? 1 : -1];
+}
+
void f(V4i a)
{
}
diff --git a/test/SemaCXX/array-bounds.cpp b/test/SemaCXX/array-bounds.cpp
index 80646c719078..3bd6c35420d7 100644
--- a/test/SemaCXX/array-bounds.cpp
+++ b/test/SemaCXX/array-bounds.cpp
@@ -120,3 +120,56 @@ int test_pr9296() {
return array[true]; // no-warning
}
+int test_sizeof_as_condition(int flag) {
+ int arr[2] = { 0, 0 }; // expected-note {{array 'arr' declared here}}
+ if (flag)
+ return sizeof(char) != sizeof(char) ? arr[2] : arr[1];
+ return sizeof(char) == sizeof(char) ? arr[2] : arr[1]; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+}
+
+void test_switch() {
+ switch (4) {
+ case 1: {
+ int arr[2];
+ arr[2] = 1; // no-warning
+ break;
+ }
+ case 4: {
+ int arr[2]; // expected-note {{array 'arr' declared here}}
+ arr[2] = 1; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+ break;
+ }
+ default: {
+ int arr[2];
+ arr[2] = 1; // no-warning
+ break;
+ }
+ }
+}
+
+// Test nested switch statements.
+enum enumA { enumA_A, enumA_B, enumA_C, enumA_D, enumA_E };
+enum enumB { enumB_X, enumB_Y, enumB_Z };
+static enum enumB myVal = enumB_X;
+void test_nested_switch()
+{
+ switch (enumA_E) { // expected-warning {{no case matching constant}}
+ switch (myVal) { // expected-warning {{enumeration values 'enumB_X' and 'enumB_Z' not handled in switch}}
+ case enumB_Y: ;
+ }
+ }
+}
+
+// Test that if all the values of an enum covered, that the 'default' branch
+// is unreachable.
+enum Values { A, B, C, D };
+void test_all_enums_covered(enum Values v) {
+ int x[2];
+ switch (v) {
+ case A: return;
+ case B: return;
+ case C: return;
+ case D: return;
+ }
+ x[2] = 0; // no-warning
+}
diff --git a/test/SemaCXX/attr-nonnull.cpp b/test/SemaCXX/attr-nonnull.cpp
index 19d6642eb553..09c054c19770 100644
--- a/test/SemaCXX/attr-nonnull.cpp
+++ b/test/SemaCXX/attr-nonnull.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct S {
+ S(const char *) __attribute__((nonnull(2)));
+
static void f(const char*, const char*) __attribute__((nonnull(1)));
// GCC has a hidden 'this' argument in member functions, so the middle
@@ -10,7 +12,9 @@ struct S {
expected-error{{invalid for the implicit this argument}}
};
-void test(S s) {
+void test() {
+ S s(0); // expected-warning{{null passed}}
+
s.f(0, ""); // expected-warning{{null passed}}
s.f("", 0);
s.g("", 0, ""); // expected-warning{{null passed}}
diff --git a/test/SemaCXX/attr-unavailable.cpp b/test/SemaCXX/attr-unavailable.cpp
index fe3e8b14706f..5f34ed990413 100644
--- a/test/SemaCXX/attr-unavailable.cpp
+++ b/test/SemaCXX/attr-unavailable.cpp
@@ -25,6 +25,6 @@ namespace radar9046492 {
void foo() FOO; // expected-note {{candidate function has been explicitly made unavailable}}
void bar() {
- foo(); // expected-error {{call to unavailable function 'foo' not available - replaced}}
+ foo(); // expected-error {{call to unavailable function 'foo': not available - replaced}}
}
}
diff --git a/test/SemaCXX/auto-subst-failure.cpp b/test/SemaCXX/auto-subst-failure.cpp
new file mode 100644
index 000000000000..442c7e82ccdb
--- /dev/null
+++ b/test/SemaCXX/auto-subst-failure.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+void f() {
+ auto a = f(); // expected-error {{variable has incomplete type 'void'}}
+ auto &b = f(); // expected-error {{cannot form a reference to 'void'}}
+ auto *c = f(); // expected-error {{incompatible initializer of type 'void'}}
+
+ auto d(f()); // expected-error {{variable has incomplete type 'void'}}
+ auto &&e(f()); // expected-error {{cannot form a reference to 'void'}}
+ auto *g(f()); // expected-error {{incompatible initializer of type 'void'}}
+
+ (void)new auto(f()); // expected-error {{allocation of incomplete type 'void'}}
+ (void)new auto&(f()); // expected-error {{cannot form a reference to 'void'}}
+ (void)new auto*(f()); // expected-error {{incompatible constructor argument of type 'void'}}
+}
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 1da9a1724d31..b95700e9ba18 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify -std=c++0x -Wsign-compare %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x -Wsign-compare %s
// C++ rules for ?: are a lot stricter than C rules, and have to take into
// account more conversion options.
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index 61c8ada62fb3..aa47ae0f4825 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -353,3 +353,28 @@ namespace PR8034 {
};
int x = C().operator int();
}
+
+namespace PR9336 {
+ template<class T>
+ struct generic_list
+ {
+ template<class Container>
+ operator Container()
+ {
+ Container ar;
+ T* i;
+ ar[0]=*i;
+ return ar;
+ }
+ };
+
+ template<class T>
+ struct array
+ {
+ T& operator[](int);
+ const T& operator[](int)const;
+ };
+
+ generic_list<generic_list<int> > l;
+ array<array<int> > a = l;
+}
diff --git a/test/SemaCXX/cxx0x-constexpr-const.cpp b/test/SemaCXX/cxx0x-constexpr-const.cpp
new file mode 100644
index 000000000000..79e6dda3e11c
--- /dev/null
+++ b/test/SemaCXX/cxx0x-constexpr-const.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+constexpr int x = 1;
+constexpr int id(int x) { return x; }
+
+void foo(void) {
+ x = 2; // expected-error {{read-only variable is not assignable}}
+ int (*idp)(int) = id;
+}
+
diff --git a/test/SemaCXX/cxx0x-delegating-ctors.cpp b/test/SemaCXX/cxx0x-delegating-ctors.cpp
new file mode 100644
index 000000000000..b211cb1fe004
--- /dev/null
+++ b/test/SemaCXX/cxx0x-delegating-ctors.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+
+struct foo {
+ int i;
+ foo();
+ foo(int);
+ foo(int, int);
+ foo(bool);
+ foo(char);
+ foo(float*);
+ foo(float&);
+};
+
+// Good
+foo::foo (int i) : i(i) {
+}
+// Good
+foo::foo () : foo(-1) {
+}
+// Good
+foo::foo (int, int) : foo() {
+}
+
+foo::foo (bool) : foo(true) { // expected-error{{delegates to itself}}
+}
+
+// Good
+foo::foo (float* f) : foo(*f) {
+}
+
+// FIXME: This should error
+foo::foo (float &f) : foo(&f) {
+}
+
+foo::foo (char) : i(3), foo(3) { // expected-error{{must appear alone}}
+}
diff --git a/test/SemaCXX/cxx0x-return-init-list.cpp b/test/SemaCXX/cxx0x-return-init-list.cpp
new file mode 100644
index 000000000000..2005a7f9f676
--- /dev/null
+++ b/test/SemaCXX/cxx0x-return-init-list.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This test checks for a teeny tiny subset of the functionality in
+// the C++0x generalized initializer lists feature, which happens to
+// be used in libstdc++ 4.5. We accept only this syntax so that Clang
+// can handle the libstdc++ 4.5 headers.
+
+int test0(int i) {
+ return { i }; // expected-warning{{generalized initializer lists are a C++0x extension unsupported in Clang}}
+}
+
+template<typename T, typename U>
+T test1(U u) {
+ return { u }; // expected-warning{{generalized initializer lists are a C++0x extension unsupported in Clang}}
+}
+
+template int test1(char);
+template long test1(int);
diff --git a/test/SemaCXX/decltype-98.cpp b/test/SemaCXX/decltype-98.cpp
new file mode 100644
index 000000000000..db52565e6c74
--- /dev/null
+++ b/test/SemaCXX/decltype-98.cpp
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s
+extern int x;
+__decltype(1) x = 3;
diff --git a/test/SemaCXX/decltype-overloaded-functions.cpp b/test/SemaCXX/decltype-overloaded-functions.cpp
index c11a47ecdf04..f4aacd64ddbc 100644
--- a/test/SemaCXX/decltype-overloaded-functions.cpp
+++ b/test/SemaCXX/decltype-overloaded-functions.cpp
@@ -1,12 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
-void f();
-void f(int);
-decltype(f) a; // expected-error{{cannot resolve overloaded function from context}}
+void f(); // expected-note{{candidate function}}
+void f(int); // expected-note{{candidate function}}
+decltype(f) a; // expected-error{{cannot resolve overloaded function 'f' from context}}
template<typename T> struct S {
- decltype(T::f) * f; // expected-error{{cannot resolve overloaded function from context}}
+ decltype(T::f) * f; // expected-error{{cannot resolve overloaded function 'f' from context}}
};
-struct K { void f(); void f(int); };
+struct K {
+ void f(); // expected-note{{candidate function}}
+ void f(int); // expected-note{{candidate function}}
+};
S<K> b; // expected-note{{in instantiation of template class 'S<K>' requested here}}
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index 14a4fb891cd3..01f21de6de17 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -177,3 +177,16 @@ namespace PR9238 {
class B { public: ~B(); };
class C : virtual B { public: ~C() { } };
}
+
+namespace PR7900 {
+ struct A { // expected-note 2{{type 'PR7900::A' is declared here}}
+ };
+ struct B : public A {
+ };
+ void foo() {
+ B b;
+ b.~B();
+ b.~A(); // expected-error{{destructor type 'PR7900::A' in object destruction expression does not match the type 'PR7900::B' of the object being destroyed}}
+ (&b)->~A(); // expected-error{{destructor type 'PR7900::A' in object destruction expression does not match the type 'PR7900::B' of the object being destroyed}}
+ }
+}
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index cf579e180f69..8c4bfe72d3e2 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -103,3 +103,9 @@ enum : long {
enum : long x; // expected-error{{unnamed enumeration must be a definition}} \
// expected-warning{{declaration does not declare anything}}
+
+void PR9333() {
+ enum class scoped_enum { yes, no, maybe };
+ scoped_enum e = scoped_enum::yes;
+ if (e == scoped_enum::no) { }
+}
diff --git a/test/SemaCXX/exception-spec-no-exceptions.cpp b/test/SemaCXX/exception-spec-no-exceptions.cpp
index 1fe45b0cffcb..2e180706d3b9 100644
--- a/test/SemaCXX/exception-spec-no-exceptions.cpp
+++ b/test/SemaCXX/exception-spec-no-exceptions.cpp
@@ -1,7 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fobjc-exceptions %s
-// Note: this is intentionally -fno-exceptions, not just accidentally
-// so because that's the current -cc1 default.
+// Note that we're specifically excluding -fcxx-exceptions in the command line above.
+
+// That this should work even with -fobjc-exceptions is PR9358
// PR7243: redeclarations
namespace test0 {
diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp
deleted file mode 100644
index b4bc78aa9a6d..000000000000
--- a/test/SemaCXX/exception-spec.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions %s
-
-// Straight from the standard:
-// Plain function with spec
-void f() throw(int);
-// Pointer to function with spec
-void (*fp)() throw (int);
-// Function taking reference to function with spec
-void g(void pfa() throw(int));
-// Typedef for pointer to function with spec
-typedef int (*pf)() throw(int); // expected-error {{specifications are not allowed in typedefs}}
-
-// Some more:
-// Function returning function with spec
-void (*h())() throw(int);
-// Ultimate parser thrill: function with spec returning function with spec and
-// taking pointer to function with spec.
-// The actual function throws int, the return type double, the argument float.
-void (*i() throw(int))(void (*)() throw(float)) throw(double);
-// Pointer to pointer to function taking function with spec
-void (**k)(void pfa() throw(int)); // no-error
-// Pointer to pointer to function with spec
-void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
-// Pointer to function returning pointer to pointer to function with spec
-void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
-
-struct Incomplete; // expected-note 3 {{forward declaration}}
-
-// Exception spec must not have incomplete types, or pointers to them, except
-// void.
-void ic1() throw(void); // expected-error {{incomplete type 'void' is not allowed in exception specification}}
-void ic2() throw(Incomplete); // expected-error {{incomplete type 'Incomplete' is not allowed in exception specification}}
-void ic3() throw(void*);
-void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'Incomplete' is not allowed in exception specification}}
-void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'Incomplete' is not allowed in exception specification}}
-
-// Redeclarations
-typedef int INT;
-void r1() throw(int);
-void r1() throw(int);
-
-void r2() throw(int);
-void r2() throw(INT);
-
-// throw-any spec and no spec at all are semantically equivalent
-void r4() throw(int, float);
-void r4() throw(float, int);
-
-void r5() throw(int); // expected-note {{previous declaration}}
-void r5(); // expected-warning {{missing exception specification}}
-
-void r7() throw(int); // expected-note {{previous declaration}}
-void r7() throw(float); // expected-error {{exception specification in declaration does not match}}
-
-// Top-level const doesn't matter.
-void r8() throw(int);
-void r8() throw(const int);
-
-// Multiple appearances don't matter.
-void r9() throw(int, int);
-void r9() throw(int, int);
-
-struct A
-{
-};
-
-struct B1 : A
-{
-};
-
-struct B2 : A
-{
-};
-
-struct D : B1, B2
-{
-};
-
-struct P : private A
-{
-};
-
-struct Base
-{
- virtual void f1() throw();
- virtual void f4() throw(int, float);
-
- virtual void f5() throw(int, float);
- virtual void f6() throw(A);
- virtual void f7() throw(A, int, float);
- virtual void f8();
-
- virtual void g1() throw(); // expected-note {{overridden virtual function is here}}
- virtual void g2() throw(int); // expected-note {{overridden virtual function is here}}
- virtual void g3() throw(A); // expected-note {{overridden virtual function is here}}
- virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}}
- virtual void g5() throw(A); // expected-note {{overridden virtual function is here}}
-};
-struct Derived : Base
-{
- virtual void f1() throw();
- virtual void f4() throw(float, int);
-
- virtual void f5() throw(float);
- virtual void f6() throw(B1);
- virtual void f7() throw(B1, B2, int);
- virtual void f8() throw(B2, B2, int, float, char, double, bool);
-
- virtual void g1() throw(int); // expected-error {{exception specification of overriding function is more lax}}
- virtual void g2(); // expected-error {{exception specification of overriding function is more lax}}
- virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}}
- virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}}
- virtual void g5() throw(P); // expected-error {{exception specification of overriding function is more lax}}
-};
-
-// Some functions to play with below.
-void s1() throw();
-void s2() throw(int);
-void s3() throw(A);
-void s4() throw(B1);
-void s5() throw(D);
-void s6();
-void s7() throw(int, float);
-void (*s8())() throw(B1); // s8 returns a pointer to function with spec
-void s9(void (*)() throw(B1)); // s9 takes pointer to function with spec
-
-void fnptrs()
-{
- // Assignment and initialization of function pointers.
- void (*t1)() throw() = &s1; // valid
- t1 = &s2; // expected-error {{not superset}} expected-error {{incompatible type}}
- t1 = &s3; // expected-error {{not superset}} expected-error {{incompatible type}}
- void (&t2)() throw() = s2; // expected-error {{not superset}}
- void (*t3)() throw(int) = &s2; // valid
- void (*t4)() throw(A) = &s1; // valid
- t4 = &s3; // valid
- t4 = &s4; // valid
- t4 = &s5; // expected-error {{not superset}} expected-error {{incompatible type}}
- void (*t5)() = &s1; // valid
- t5 = &s2; // valid
- t5 = &s6; // valid
- t5 = &s7; // valid
- t1 = t3; // expected-error {{not superset}} expected-error {{incompatible type}}
- t3 = t1; // valid
- void (*t6)() throw(B1);
- t6 = t4; // expected-error {{not superset}} expected-error {{incompatible type}}
- t4 = t6; // valid
- t5 = t1; // valid
- t1 = t5; // expected-error {{not superset}} expected-error {{incompatible type}}
-
- // return types and arguments must match exactly, no inheritance allowed
- void (*(*t7)())() throw(B1) = &s8; // valid
- void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}}
- void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}}
- void (*t10)(void (*)() throw(B1)) = &s9; // valid expected-warning{{disambiguated}}
- void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}}
- void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}}
-}
-
-// Member function stuff
-
-struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}}
-void Str1::f() // expected-warning {{missing exception specification}}
-{
-}
-
-void mfnptr()
-{
- void (Str1::*pfn1)() throw(int) = &Str1::f; // valid
- void (Str1::*pfn2)() = &Str1::f; // valid
- void (Str1::*pfn3)() throw() = &Str1::f; // expected-error {{not superset}}
-}
-
-// Don't suppress errors in template instantiation.
-template <typename T> struct TEx; // expected-note {{template is declared here}}
-
-void tf() throw(TEx<int>); // expected-error {{implicit instantiation of undefined template}}
-
-// DR 437, class throws itself.
-struct DR437 {
- void f() throw(DR437);
- void g() throw(DR437*);
- void h() throw(DR437&);
-};
-
-// DR 437 within a nested class
-struct DR437_out {
- struct DR437_in {
- void f() throw(DR437_out);
- void g() throw(DR437_out*);
- void h() throw(DR437_out&);
- };
-};
diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp
index bda4a3d2ec54..e2bfe1839467 100644
--- a/test/SemaCXX/exceptions.cpp
+++ b/test/SemaCXX/exceptions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
struct A; // expected-note 4 {{forward declaration of 'A'}}
diff --git a/test/SemaCXX/expression-traits.cpp b/test/SemaCXX/expression-traits.cpp
new file mode 100644
index 000000000000..4555192280f0
--- /dev/null
+++ b/test/SemaCXX/expression-traits.cpp
@@ -0,0 +1,620 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fcxx-exceptions %s
+
+//
+// Tests for "expression traits" intrinsics such as __is_lvalue_expr.
+//
+// For the time being, these tests are written against the 2003 C++
+// standard (ISO/IEC 14882:2003 -- see draft at
+// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2001/n1316/).
+//
+// C++0x has its own, more-refined, idea of lvalues and rvalues.
+// If/when we need to support those, we'll need to track both
+// standard documents.
+
+#if !__has_feature(cxx_static_assert)
+# define CONCAT_(X_, Y_) CONCAT1_(X_, Y_)
+# define CONCAT1_(X_, Y_) X_ ## Y_
+
+// This emulation can be used multiple times on one line (and thus in
+// a macro), except at class scope
+# define static_assert(b_, m_) \
+ typedef int CONCAT_(sa_, __LINE__)[b_ ? 1 : -1]
+#endif
+
+// Tests are broken down according to section of the C++03 standard
+// (ISO/IEC 14882:2003(E))
+
+// Assertion macros encoding the following two paragraphs
+//
+// basic.lval/1 Every expression is either an lvalue or an rvalue.
+//
+// expr.prim/5 A parenthesized expression is a primary expression whose type
+// and value are identical to those of the enclosed expression. The
+// presence of parentheses does not affect whether the expression is
+// an lvalue.
+//
+// Note: these asserts cannot be made at class scope in C++03. Put
+// them in a member function instead.
+#define ASSERT_LVALUE(expr) \
+ static_assert(__is_lvalue_expr(expr), "should be an lvalue"); \
+ static_assert(__is_lvalue_expr((expr)), \
+ "the presence of parentheses should have" \
+ " no effect on lvalueness (expr.prim/5)"); \
+ static_assert(!__is_rvalue_expr(expr), "should be an lvalue"); \
+ static_assert(!__is_rvalue_expr((expr)), \
+ "the presence of parentheses should have" \
+ " no effect on lvalueness (expr.prim/5)")
+
+#define ASSERT_RVALUE(expr); \
+ static_assert(__is_rvalue_expr(expr), "should be an rvalue"); \
+ static_assert(__is_rvalue_expr((expr)), \
+ "the presence of parentheses should have" \
+ " no effect on lvalueness (expr.prim/5)"); \
+ static_assert(!__is_lvalue_expr(expr), "should be an rvalue"); \
+ static_assert(!__is_lvalue_expr((expr)), \
+ "the presence of parentheses should have" \
+ " no effect on lvalueness (expr.prim/5)")
+
+enum Enum { Enumerator };
+
+int ReturnInt();
+void ReturnVoid();
+Enum ReturnEnum();
+
+void basic_lval_5()
+{
+ // basic.lval/5: The result of calling a function that does not return
+ // a reference is an rvalue.
+ ASSERT_RVALUE(ReturnInt());
+ ASSERT_RVALUE(ReturnVoid());
+ ASSERT_RVALUE(ReturnEnum());
+}
+
+int& ReturnIntReference();
+extern Enum& ReturnEnumReference();
+
+void basic_lval_6()
+{
+ // basic.lval/6: An expression which holds a temporary object resulting
+ // from a cast to a nonreference type is an rvalue (this includes
+ // the explicit creation of an object using functional notation
+ struct IntClass
+ {
+ explicit IntClass(int = 0);
+ IntClass(char const*);
+ operator int() const;
+ };
+
+ struct ConvertibleToIntClass
+ {
+ operator IntClass() const;
+ };
+
+ ConvertibleToIntClass b;
+
+ // Make sure even trivial conversions are not detected as lvalues
+ int intLvalue = 0;
+ ASSERT_RVALUE((int)intLvalue);
+ ASSERT_RVALUE((short)intLvalue);
+ ASSERT_RVALUE((long)intLvalue);
+
+ // Same tests with function-call notation
+ ASSERT_RVALUE(int(intLvalue));
+ ASSERT_RVALUE(short(intLvalue));
+ ASSERT_RVALUE(long(intLvalue));
+
+ char charLValue = 'x';
+ ASSERT_RVALUE((signed char)charLValue);
+ ASSERT_RVALUE((unsigned char)charLValue);
+
+ ASSERT_RVALUE(static_cast<int>(IntClass()));
+ IntClass intClassLValue;
+ ASSERT_RVALUE(static_cast<int>(intClassLValue));
+ ASSERT_RVALUE(static_cast<IntClass>(ConvertibleToIntClass()));
+ ConvertibleToIntClass convertibleToIntClassLValue;
+ ASSERT_RVALUE(static_cast<IntClass>(convertibleToIntClassLValue));
+
+
+ typedef signed char signed_char;
+ typedef unsigned char unsigned_char;
+ ASSERT_RVALUE(signed_char(charLValue));
+ ASSERT_RVALUE(unsigned_char(charLValue));
+
+ ASSERT_RVALUE(int(IntClass()));
+ ASSERT_RVALUE(int(intClassLValue));
+ ASSERT_RVALUE(IntClass(ConvertibleToIntClass()));
+ ASSERT_RVALUE(IntClass(convertibleToIntClassLValue));
+}
+
+void conv_ptr_1()
+{
+ // conv.ptr/1: A null pointer constant is an integral constant
+ // expression (5.19) rvalue of integer type that evaluates to
+ // zero.
+ ASSERT_RVALUE(0);
+}
+
+void expr_6()
+{
+ // expr/6: If an expression initially has the type “reference to T”
+ // (8.3.2, 8.5.3), ... the expression is an lvalue.
+ int x = 0;
+ int& referenceToInt = x;
+ ASSERT_LVALUE(referenceToInt);
+ ASSERT_LVALUE(ReturnIntReference());
+}
+
+void expr_prim_2()
+{
+ // 5.1/2 A string literal is an lvalue; all other
+ // literals are rvalues.
+ ASSERT_LVALUE("foo");
+ ASSERT_RVALUE(1);
+ ASSERT_RVALUE(1.2);
+ ASSERT_RVALUE(10UL);
+}
+
+void expr_prim_3()
+{
+ // 5.1/3: The keyword "this" names a pointer to the object for
+ // which a nonstatic member function (9.3.2) is invoked. ...The
+ // expression is an rvalue.
+ struct ThisTest
+ {
+ void f() { ASSERT_RVALUE(this); }
+ };
+}
+
+extern int variable;
+void Function();
+
+struct BaseClass
+{
+ virtual ~BaseClass();
+
+ int BaseNonstaticMemberFunction();
+ static int BaseStaticMemberFunction();
+ int baseDataMember;
+};
+
+struct Class : BaseClass
+{
+ static void function();
+ static int variable;
+
+ template <class T>
+ struct NestedClassTemplate {};
+
+ template <class T>
+ static int& NestedFuncTemplate() { return variable; } // expected-note{{candidate function}}
+
+ template <class T>
+ int& NestedMemfunTemplate() { return variable; }
+
+ int operator*() const;
+
+ template <class T>
+ int operator+(T) const;
+
+ int NonstaticMemberFunction();
+ static int StaticMemberFunction();
+ int dataMember;
+
+ int& referenceDataMember;
+ static int& staticReferenceDataMember;
+ static int staticNonreferenceDataMember;
+
+ enum Enum { Enumerator };
+
+ operator long() const;
+
+ Class();
+ Class(int,int);
+
+ void expr_prim_4()
+ {
+ // 5.1/4: The operator :: followed by an identifier, a
+ // qualified-id, or an operator-function-id is a primary-
+ // expression. ...The result is an lvalue if the entity is
+ // a function or variable.
+ ASSERT_LVALUE(::Function); // identifier: function
+ ASSERT_LVALUE(::variable); // identifier: variable
+
+ // the only qualified-id form that can start without "::" (and thus
+ // be legal after "::" ) is
+ //
+ // ::<sub>opt</sub> nested-name-specifier template<sub>opt</sub> unqualified-id
+ ASSERT_LVALUE(::Class::function); // qualified-id: function
+ ASSERT_LVALUE(::Class::variable); // qualified-id: variable
+
+ // The standard doesn't give a clear answer about whether these
+ // should really be lvalues or rvalues without some surrounding
+ // context that forces them to be interpreted as naming a
+ // particular function template specialization (that situation
+ // doesn't come up in legal pure C++ programs). This language
+ // extension simply rejects them as requiring additional context
+ __is_lvalue_expr(::Class::NestedFuncTemplate); // qualified-id: template \
+ // expected-error{{cannot resolve overloaded function 'NestedFuncTemplate' from context}}
+
+ __is_lvalue_expr(::Class::NestedMemfunTemplate); // qualified-id: template \
+ // expected-error{{a bound member function may only be called}}
+
+ __is_lvalue_expr(::Class::operator+); // operator-function-id: template \
+ // expected-error{{a bound member function may only be called}}
+
+ //ASSERT_RVALUE(::Class::operator*); // operator-function-id: member function
+ }
+
+ void expr_prim_7()
+ {
+ // expr.prim/7 An identifier is an id-expression provided it has been
+ // suitably declared (clause 7). [Note: ... ] The type of the
+ // expression is the type of the identifier. The result is the
+ // entity denoted by the identifier. The result is an lvalue if
+ // the entity is a function, variable, or data member... (cont'd)
+ ASSERT_LVALUE(Function); // identifier: function
+ ASSERT_LVALUE(StaticMemberFunction); // identifier: function
+ ASSERT_LVALUE(variable); // identifier: variable
+ ASSERT_LVALUE(dataMember); // identifier: data member
+ //ASSERT_RVALUE(NonstaticMemberFunction); // identifier: member function
+
+ // (cont'd)...A nested-name-specifier that names a class,
+ // optionally followed by the keyword template (14.2), and then
+ // followed by the name of a member of either that class (9.2) or
+ // one of its base classes... is a qualified-id... The result is
+ // the member. The type of the result is the type of the
+ // member. The result is an lvalue if the member is a static
+ // member function or a data member.
+ ASSERT_LVALUE(Class::dataMember);
+ ASSERT_LVALUE(Class::StaticMemberFunction);
+ //ASSERT_RVALUE(Class::NonstaticMemberFunction); // identifier: member function
+
+ ASSERT_LVALUE(Class::baseDataMember);
+ ASSERT_LVALUE(Class::BaseStaticMemberFunction);
+ //ASSERT_RVALUE(Class::BaseNonstaticMemberFunction); // identifier: member function
+ }
+};
+
+void expr_call_10()
+{
+ // expr.call/10: A function call is an lvalue if and only if the
+ // result type is a reference. This statement is partially
+ // redundant with basic.lval/5
+ basic_lval_5();
+
+ ASSERT_LVALUE(ReturnIntReference());
+ ASSERT_LVALUE(ReturnEnumReference());
+}
+
+namespace Namespace
+{
+ int x;
+ void function();
+}
+
+void expr_prim_8()
+{
+ // expr.prim/8 A nested-name-specifier that names a namespace
+ // (7.3), followed by the name of a member of that namespace (or
+ // the name of a member of a namespace made visible by a
+ // using-directive ) is a qualified-id; 3.4.3.2 describes name
+ // lookup for namespace members that appear in qualified-ids. The
+ // result is the member. The type of the result is the type of the
+ // member. The result is an lvalue if the member is a function or
+ // a variable.
+ ASSERT_LVALUE(Namespace::x);
+ ASSERT_LVALUE(Namespace::function);
+}
+
+void expr_sub_1(int* pointer)
+{
+ // expr.sub/1 A postfix expression followed by an expression in
+ // square brackets is a postfix expression. One of the expressions
+ // shall have the type “pointer to T” and the other shall have
+ // enumeration or integral type. The result is an lvalue of type
+ // “T.”
+ ASSERT_LVALUE(pointer[1]);
+
+ // The expression E1[E2] is identical (by definition) to *((E1)+(E2)).
+ ASSERT_LVALUE(*(pointer+1));
+}
+
+void expr_type_conv_1()
+{
+ // expr.type.conv/1 A simple-type-specifier (7.1.5) followed by a
+ // parenthesized expression-list constructs a value of the specified
+ // type given the expression list. ... If the expression list
+ // specifies more than a single value, the type shall be a class with
+ // a suitably declared constructor (8.5, 12.1), and the expression
+ // T(x1, x2, ...) is equivalent in effect to the declaration T t(x1,
+ // x2, ...); for some invented temporary variable t, with the result
+ // being the value of t as an rvalue.
+ ASSERT_RVALUE(Class(2,2));
+}
+
+void expr_type_conv_2()
+{
+ // expr.type.conv/2 The expression T(), where T is a
+ // simple-type-specifier (7.1.5.2) for a non-array complete object
+ // type or the (possibly cv-qualified) void type, creates an
+ // rvalue of the specified type,
+ ASSERT_RVALUE(int());
+ ASSERT_RVALUE(Class());
+ ASSERT_RVALUE(void());
+}
+
+
+void expr_ref_4()
+{
+ // Applies to expressions of the form E1.E2
+
+ // If E2 is declared to have type “reference to T”, then E1.E2 is
+ // an lvalue;.... Otherwise, one of the following rules applies.
+ ASSERT_LVALUE(Class().staticReferenceDataMember);
+ ASSERT_LVALUE(Class().referenceDataMember);
+
+ // — If E2 is a static data member, and the type of E2 is T, then
+ // E1.E2 is an lvalue; ...
+ ASSERT_LVALUE(Class().staticNonreferenceDataMember);
+ ASSERT_LVALUE(Class().staticReferenceDataMember);
+
+
+ // — If E2 is a non-static data member, ... If E1 is an lvalue,
+ // then E1.E2 is an lvalue...
+ Class lvalue;
+ ASSERT_LVALUE(lvalue.dataMember);
+ ASSERT_RVALUE(Class().dataMember);
+
+ // — If E1.E2 refers to a static member function, ... then E1.E2
+ // is an lvalue
+ ASSERT_LVALUE(Class().StaticMemberFunction);
+
+ // — Otherwise, if E1.E2 refers to a non-static member function,
+ // then E1.E2 is not an lvalue.
+ //ASSERT_RVALUE(Class().NonstaticMemberFunction);
+
+ // — If E2 is a member enumerator, and the type of E2 is T, the
+ // expression E1.E2 is not an lvalue. The type of E1.E2 is T.
+ ASSERT_RVALUE(Class().Enumerator);
+ ASSERT_RVALUE(lvalue.Enumerator);
+}
+
+
+void expr_post_incr_1(int x)
+{
+ // expr.post.incr/1 The value obtained by applying a postfix ++ is
+ // the value that the operand had before applying the
+ // operator... The result is an rvalue.
+ ASSERT_RVALUE(x++);
+}
+
+void expr_dynamic_cast_2()
+{
+ // expr.dynamic.cast/2: If T is a pointer type, v shall be an
+ // rvalue of a pointer to complete class type, and the result is
+ // an rvalue of type T.
+ Class instance;
+ ASSERT_RVALUE(dynamic_cast<Class*>(&instance));
+
+ // If T is a reference type, v shall be an
+ // lvalue of a complete class type, and the result is an lvalue of
+ // the type referred to by T.
+ ASSERT_LVALUE(dynamic_cast<Class&>(instance));
+}
+
+void expr_dynamic_cast_5()
+{
+ // expr.dynamic.cast/5: If T is “reference to cv1 B” and v has type
+ // “cv2 D” such that B is a base class of D, the result is an
+ // lvalue for the unique B sub-object of the D object referred
+ // to by v.
+ typedef BaseClass B;
+ typedef Class D;
+ D object;
+ ASSERT_LVALUE(dynamic_cast<B&>(object));
+}
+
+// expr.dynamic.cast/8: The run-time check logically executes as follows:
+//
+// — If, in the most derived object pointed (referred) to by v, v
+// points (refers) to a public base class subobject of a T object, and
+// if only one object of type T is derived from the sub-object pointed
+// (referred) to by v, the result is a pointer (an lvalue referring)
+// to that T object.
+//
+// — Otherwise, if v points (refers) to a public base class sub-object
+// of the most derived object, and the type of the most derived object
+// has a base class, of type T, that is unambiguous and public, the
+// result is a pointer (an lvalue referring) to the T sub-object of
+// the most derived object.
+//
+// The mention of "lvalue" in the text above appears to be a
+// defect that is being corrected by the response to UK65 (see
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2841.html).
+
+#if 0
+void expr_typeid_1()
+{
+ // expr.typeid/1: The result of a typeid expression is an lvalue...
+ ASSERT_LVALUE(typeid(1));
+}
+#endif
+
+void expr_static_cast_1(int x)
+{
+ // expr.static.cast/1: The result of the expression
+ // static_cast<T>(v) is the result of converting the expression v
+ // to type T. If T is a reference type, the result is an lvalue;
+ // otherwise, the result is an rvalue.
+ ASSERT_LVALUE(static_cast<int&>(x));
+ ASSERT_RVALUE(static_cast<int>(x));
+}
+
+void expr_reinterpret_cast_1()
+{
+ // expr.reinterpret.cast/1: The result of the expression
+ // reinterpret_cast<T>(v) is the result of converting the
+ // expression v to type T. If T is a reference type, the result is
+ // an lvalue; otherwise, the result is an rvalue
+ ASSERT_RVALUE(reinterpret_cast<int*>(0));
+ char const v = 0;
+ ASSERT_LVALUE(reinterpret_cast<char const&>(v));
+}
+
+void expr_unary_op_1(int* pointer, struct incomplete* pointerToIncompleteType)
+{
+ // expr.unary.op/1: The unary * operator performs indirection: the
+ // expression to which it is applied shall be a pointer to an
+ // object type, or a pointer to a function type and the result is
+ // an lvalue referring to the object or function to which the
+ // expression points.
+ ASSERT_LVALUE(*pointer);
+ ASSERT_LVALUE(*Function);
+
+ // [Note: a pointer to an incomplete type
+ // (other than cv void ) can be dereferenced. ]
+ ASSERT_LVALUE(*pointerToIncompleteType);
+}
+
+void expr_pre_incr_1(int operand)
+{
+ // expr.pre.incr/1: The operand of prefix ++ ... shall be a
+ // modifiable lvalue.... The value is the new value of the
+ // operand; it is an lvalue.
+ ASSERT_LVALUE(++operand);
+}
+
+void expr_cast_1(int x)
+{
+ // expr.cast/1: The result of the expression (T) cast-expression
+ // is of type T. The result is an lvalue if T is a reference type,
+ // otherwise the result is an rvalue.
+ ASSERT_LVALUE((void(&)())expr_cast_1);
+ ASSERT_LVALUE((int&)x);
+ ASSERT_RVALUE((void(*)())expr_cast_1);
+ ASSERT_RVALUE((int)x);
+}
+
+void expr_mptr_oper()
+{
+ // expr.mptr.oper/6: The result of a .* expression is an lvalue
+ // only if its first operand is an lvalue and its second operand
+ // is a pointer to data member... (cont'd)
+ typedef Class MakeRValue;
+ ASSERT_RVALUE(MakeRValue().*(&Class::dataMember));
+ //ASSERT_RVALUE(MakeRValue().*(&Class::NonstaticMemberFunction));
+ Class lvalue;
+ ASSERT_LVALUE(lvalue.*(&Class::dataMember));
+ //ASSERT_RVALUE(lvalue.*(&Class::NonstaticMemberFunction));
+
+ // (cont'd)...The result of an ->* expression is an lvalue only
+ // if its second operand is a pointer to data member. If the
+ // second operand is the null pointer to member value (4.11), the
+ // behavior is undefined.
+ ASSERT_LVALUE((&lvalue)->*(&Class::dataMember));
+ //ASSERT_RVALUE((&lvalue)->*(&Class::NonstaticMemberFunction));
+}
+
+void expr_cond(bool cond)
+{
+ // 5.16 Conditional operator [expr.cond]
+ //
+ // 2 If either the second or the third operand has type (possibly
+ // cv-qualified) void, then the lvalue-to-rvalue (4.1),
+ // array-to-pointer (4.2), and function-to-pointer (4.3) standard
+ // conversions are performed on the second and third operands, and one
+ // of the following shall hold:
+ //
+ // — The second or the third operand (but not both) is a
+ // throw-expression (15.1); the result is of the type of the other and
+ // is an rvalue.
+
+ Class classLvalue;
+ ASSERT_RVALUE(cond ? throw 1 : (void)0);
+ ASSERT_RVALUE(cond ? (void)0 : throw 1);
+ ASSERT_RVALUE(cond ? throw 1 : classLvalue);
+ ASSERT_RVALUE(cond ? classLvalue : throw 1);
+
+ // — Both the second and the third operands have type void; the result
+ // is of type void and is an rvalue. [Note: this includes the case
+ // where both operands are throw-expressions. ]
+ ASSERT_RVALUE(cond ? (void)1 : (void)0);
+ ASSERT_RVALUE(cond ? throw 1 : throw 0);
+
+ // expr.cond/4: If the second and third operands are lvalues and
+ // have the same type, the result is of that type and is an
+ // lvalue.
+ ASSERT_LVALUE(cond ? classLvalue : classLvalue);
+ int intLvalue = 0;
+ ASSERT_LVALUE(cond ? intLvalue : intLvalue);
+
+ // expr.cond/5:Otherwise, the result is an rvalue.
+ typedef Class MakeRValue;
+ ASSERT_RVALUE(cond ? MakeRValue() : classLvalue);
+ ASSERT_RVALUE(cond ? classLvalue : MakeRValue());
+ ASSERT_RVALUE(cond ? MakeRValue() : MakeRValue());
+ ASSERT_RVALUE(cond ? classLvalue : intLvalue);
+ ASSERT_RVALUE(cond ? intLvalue : int());
+}
+
+void expr_ass_1(int x)
+{
+ // expr.ass/1: There are several assignment operators, all of
+ // which group right-to-left. All require a modifiable lvalue as
+ // their left operand, and the type of an assignment expression is
+ // that of its left operand. The result of the assignment
+ // operation is the value stored in the left operand after the
+ // assignment has taken place; the result is an lvalue.
+ ASSERT_LVALUE(x = 1);
+ ASSERT_LVALUE(x += 1);
+ ASSERT_LVALUE(x -= 1);
+ ASSERT_LVALUE(x *= 1);
+ ASSERT_LVALUE(x /= 1);
+ ASSERT_LVALUE(x %= 1);
+ ASSERT_LVALUE(x ^= 1);
+ ASSERT_LVALUE(x &= 1);
+ ASSERT_LVALUE(x |= 1);
+}
+
+void expr_comma(int x)
+{
+ // expr.comma: A pair of expressions separated by a comma is
+ // evaluated left-to-right and the value of the left expression is
+ // discarded... result is an lvalue if its right operand is.
+
+ // Can't use the ASSERT_XXXX macros without adding parens around
+ // the comma expression.
+ static_assert(__is_lvalue_expr(x,x), "expected an lvalue");
+ static_assert(__is_rvalue_expr(x,1), "expected an rvalue");
+ static_assert(__is_lvalue_expr(1,x), "expected an lvalue");
+ static_assert(__is_rvalue_expr(1,1), "expected an rvalue");
+}
+
+#if 0
+template<typename T> void f();
+
+// FIXME These currently fail
+void expr_fun_lvalue()
+{
+ ASSERT_LVALUE(&f<int>);
+}
+
+void expr_fun_rvalue()
+{
+ ASSERT_RVALUE(f<int>);
+}
+#endif
+
+template <int NonTypeNonReferenceParameter, int& NonTypeReferenceParameter>
+void check_temp_param_6()
+{
+ ASSERT_RVALUE(NonTypeNonReferenceParameter);
+ ASSERT_LVALUE(NonTypeReferenceParameter);
+}
+
+int AnInt = 0;
+
+void temp_param_6()
+{
+ check_temp_param_6<3,AnInt>();
+}
diff --git a/test/SemaCXX/flexible-array-test.cpp b/test/SemaCXX/flexible-array-test.cpp
index 95d8bb1aa413..e6c3132801f8 100644
--- a/test/SemaCXX/flexible-array-test.cpp
+++ b/test/SemaCXX/flexible-array-test.cpp
@@ -51,5 +51,19 @@ class A {
union B {
int s;
- char c[]; // expected-error {{field has incomplete type 'char []'}}
+ char c[];
+};
+
+namespace rdar9065507 {
+
+struct StorageBase {
+ long ref_count;
+ unsigned size;
+ unsigned capacity;
};
+
+struct Storage : StorageBase {
+ int data[];
+};
+
+}
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
new file mode 100644
index 000000000000..810f1de441a1
--- /dev/null
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -0,0 +1,150 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+namespace value_range_detail {
+ template<typename T>
+ class value_range_iter {
+ T t;
+ public:
+ value_range_iter(const T &t) : t(t) {}
+ T operator*() const { return t; }
+ bool operator!=(const value_range_iter &o) const { return t != o.t; }
+ value_range_iter &operator++() { ++t; return *this; }
+ };
+
+ template<typename T>
+ struct value_range {
+ value_range(const T &a, const T &b) : begin_(a), end_(b) {}
+ value_range_iter<T> begin_, end_;
+ };
+
+ template<typename T>
+ value_range_iter<T> begin(const value_range<T> &r) { return r.begin_; }
+ template<typename T>
+ value_range_iter<T> end(const value_range<T> &r) { return r.end_; }
+
+
+ struct end_t {};
+
+ template<typename T>
+ class value_range_step_iter {
+ T it, step;
+ public:
+ value_range_step_iter(const T &it, const T &step) : it(it), step(step) {}
+ T operator*() const { return it; }
+ bool operator!=(value_range_step_iter end) const { return it != end.it; }
+ value_range_step_iter &operator++() { it += step; return *this; }
+ };
+
+ template<typename T>
+ class value_range_step {
+ T it, step, end_;
+ public:
+ value_range_step(const T &it, const T &end, const T &step) :
+ it(it), end_(end), step(step) {}
+ typedef value_range_step_iter<T> iterator;
+ iterator begin() const { return iterator(it, step); }
+ iterator end() const { return iterator(end_, step); }
+ };
+}
+
+template<typename T>
+value_range_detail::value_range<T> range(const T &a, const T &b) { return value_range_detail::value_range<T>(a, b); }
+
+template<typename T>
+value_range_detail::value_range_step<T> range(const T &a, const T &b, const T &step) { return value_range_detail::value_range_step<T>(a, b, step); }
+
+
+namespace map_range {
+ template<typename T>
+ class vector {
+ T storage[100];
+ decltype(sizeof(char)) size;
+ public:
+ vector() : size() {}
+ void push_back(T t) { storage[size++] = t; }
+ T *begin() { return storage; }
+ T *end() { return storage + size; }
+ };
+
+ template<typename T> struct tuple_elem {
+ T t;
+ tuple_elem() {}
+ tuple_elem(T t) : t(t) {}
+ };
+ template<typename... A>
+ struct tuple : tuple_elem<A>... {
+ tuple() : tuple_elem<A>()... {}
+ tuple(A... a) : tuple_elem<A>(a)... {}
+ template<typename B> B &get() { return tuple_elem<B>::t; }
+ };
+
+ template<typename F, typename I>
+ class map_iter {
+ F f;
+ I i;
+ public:
+ map_iter(F f, I i) : f(f), i(i) {}
+ auto operator*() const -> decltype(f(*i)) { return f(*i); }
+ bool operator!=(const map_iter &o) const { return i != o.i; }
+ map_iter &operator++() { ++i; return *this; }
+ };
+
+ template<typename T>
+ struct iter_pair {
+ T begin_, end_;
+ iter_pair(T begin, T end) : begin_(begin), end_(end) {}
+ };
+ template<typename T> T begin(iter_pair<T> p) { return p.begin_; }
+ template<typename T> T end(iter_pair<T> p) { return p.end_; }
+
+ template<typename...> class mem_fun_impl;
+ template<typename R, typename T, typename... A>
+ class mem_fun_impl<R (T::*)(A...)> {
+ typedef R (T::*F)(A...);
+ F f;
+ public:
+ mem_fun_impl(F f) : f(f) {}
+ R operator()(T &t, A &&...a) const { return (t.*f)(static_cast<A&&>(a)...); }
+ };
+ template<typename F> mem_fun_impl<F> mem_fun(F f) { return mem_fun_impl<F>(f); }
+
+ template<typename F, typename T>
+ auto map(const F &f, T &t) -> iter_pair<map_iter<F, decltype(t.begin())>> {
+ typedef map_iter<F, decltype(t.begin())> iter;
+ return iter_pair<iter>(iter(f, t.begin()), iter(f, t.end()));
+ }
+}
+
+#define assert(b) if (!b) { return 1; }
+int main() {
+ int total = 0;
+
+ for (auto n : range(1, 5)) {
+ total += n;
+ }
+ assert(total == 10);
+
+ for (auto n : range(10, 100, 10)) {
+ total += n;
+ }
+ assert(total == 460);
+
+ map_range::vector<char> chars;
+ chars.push_back('a');
+ chars.push_back('b');
+ chars.push_back('c');
+ for (char c : chars) {
+ ++total;
+ }
+ assert(total == 463);
+
+ typedef map_range::tuple<int, double> T;
+ map_range::vector<T> pairs;
+ pairs.push_back(T(42, 12.9));
+ pairs.push_back(T(6, 4.2));
+ pairs.push_back(T(9, 1.1));
+ for (auto a : map(map_range::mem_fun(&T::get<int>), pairs)) {
+ total += a;
+ }
+ assert(total == 500);
+}
diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp
new file mode 100644
index 000000000000..8cc71e5111a2
--- /dev/null
+++ b/test/SemaCXX/for-range-no-std.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+struct S {
+ int *begin();
+ int *end();
+};
+
+struct T {
+};
+
+struct Range {};
+int begin(Range); // expected-note {{not viable}}
+int end(Range);
+
+namespace NS {
+ struct ADL {};
+ struct iter {
+ int operator*();
+ bool operator!=(iter);
+ void operator++();
+ };
+ iter begin(ADL); // expected-note {{not viable}}
+ iter end(ADL);
+
+ struct NoADL {};
+}
+NS::iter begin(NS::NoADL); // expected-note {{not viable}}
+NS::iter end(NS::NoADL);
+
+void f() {
+ int a[] = {1, 2, 3};
+ for (auto b : S()) {} // ok
+ for (auto b : T()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+ for (auto b : a) {} // ok
+ for (int b : NS::ADL()) {} // ok
+ for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
+}
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
index 1222dd0940da..b1ef220e534c 100644
--- a/test/SemaCXX/friend.cpp
+++ b/test/SemaCXX/friend.cpp
@@ -64,11 +64,11 @@ namespace test4 {
}
namespace rdar8529993 {
-struct A { ~A(); }; // expected-note {{nearly matches}}
+struct A { ~A(); };
struct B : A
{
- template<int> friend A::~A(); // expected-error {{does not match}}
+ template<int> friend A::~A(); // expected-error {{destructor cannot be declared as a template}}
};
}
diff --git a/test/SemaCXX/generic-selection.cpp b/test/SemaCXX/generic-selection.cpp
new file mode 100644
index 000000000000..b171fce540d8
--- /dev/null
+++ b/test/SemaCXX/generic-selection.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template <typename T, typename U = void*>
+struct A {
+ enum {
+ id = _Generic(T(), // expected-error {{controlling expression type 'char' not compatible with any generic association type}}
+ int: 1, // expected-note {{compatible type 'int' specified here}}
+ float: 2,
+ U: 3) // expected-error {{type 'int' in generic association compatible with previously specified type 'int'}}
+ };
+};
+
+static_assert(A<int>::id == 1, "fail");
+static_assert(A<float>::id == 2, "fail");
+static_assert(A<double, double>::id == 3, "fail");
+
+A<char> a1; // expected-note {{in instantiation of template class 'A<char, void *>' requested here}}
+A<short, int> a2; // expected-note {{in instantiation of template class 'A<short, int>' requested here}}
+
+template <typename T, typename U>
+struct B {
+ enum {
+ id = _Generic(T(),
+ int: 1, // expected-note {{compatible type 'int' specified here}}
+ int: 2, // expected-error {{type 'int' in generic association compatible with previously specified type 'int'}}
+ U: 3)
+ };
+};
+
+template <unsigned Arg, unsigned... Args> struct Or {
+ enum { result = Arg | Or<Args...>::result };
+};
+
+template <unsigned Arg> struct Or<Arg> {
+ enum { result = Arg };
+};
+
+template <class... Args> struct TypeMask {
+ enum {
+ result = Or<_Generic(Args(), int: 1, long: 2, short: 4, float: 8)...>::result
+ };
+};
+
+static_assert(TypeMask<int, long, short>::result == 7, "fail");
+static_assert(TypeMask<float, short>::result == 12, "fail");
+static_assert(TypeMask<int, float, float>::result == 9, "fail");
diff --git a/test/SemaCXX/goto.cpp b/test/SemaCXX/goto.cpp
new file mode 100644
index 000000000000..d8d5ec51f6e4
--- /dev/null
+++ b/test/SemaCXX/goto.cpp
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -fblocks %s
+
+// PR9463
+double *end;
+void f(bool b1, bool b2) {
+ {
+ do {
+ int end = 0;
+ if (b2) {
+ do {
+ goto end;
+ } while (b2);
+ }
+ end = 1;
+ } while (b1);
+ }
+
+ end:
+ return;
+}
+
+namespace N {
+ float* end;
+ void f(bool b1, bool b2) {
+ {
+ do {
+ int end = 0;
+ if (b2) {
+ do {
+ goto end;
+ } while (b2);
+ }
+ end = 1;
+ } while (b1);
+ }
+
+ end:
+ return;
+ }
+}
+
+void g() {
+ end = 1; // expected-error{{assigning to 'double *' from incompatible type 'int'}}
+}
+
+void h(int end) {
+ {
+ goto end; // expected-error{{use of undeclared label 'end'}}
+ }
+}
+
+void h2(int end) {
+ {
+ __label__ end;
+ goto end;
+
+ end:
+ ::end = 0;
+ }
+ end: // expected-warning{{unused label 'end'}}
+ end = 1;
+}
+
+class X {
+public:
+ X();
+};
+
+void rdar9135994()
+{
+X:
+ goto X;
+}
+
+namespace PR9495 {
+ struct NonPOD { NonPOD(); ~NonPOD(); };
+
+ void f(bool b) {
+ NonPOD np;
+ if (b) {
+ goto undeclared; // expected-error{{use of undeclared label 'undeclared'}}
+ }
+ }
+
+ void g() {
+ (void)^(bool b){
+ NonPOD np;
+ if (b) {
+ goto undeclared; // expected-error{{use of undeclared label 'undeclared'}}
+ }
+ };
+ }
+}
+
+extern "C" {
+ void exit(int);
+}
+
+void f() {
+ {
+ goto exit;
+ }
+ exit:
+ return;
+}
diff --git a/test/SemaCXX/goto2.cpp b/test/SemaCXX/goto2.cpp
new file mode 100644
index 000000000000..01ea031ac2c1
--- /dev/null
+++ b/test/SemaCXX/goto2.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+//PR9463
+int subfun(const char *text) {
+ const char *tmp = text;
+ return 0;
+}
+
+void fun(const char* text) {
+ int count = 0;
+ bool check = true;
+
+ if (check)
+ {
+ const char *end = text;
+
+ if (check)
+ {
+ do
+ {
+ if (check)
+ {
+ count = subfun(end);
+ goto end;
+ }
+
+ check = !check;
+ }
+ while (check);
+ }
+ // also works, after commenting following line of source code
+ int e = subfun(end);
+ }
+ end:
+ if (check)
+ ++count;
+}
+
+const char *text = "some text";
+
+int main() {
+ const char *ptr = text;
+
+ fun(ptr);
+
+ return 0;
+}
diff --git a/test/SemaCXX/init-priority-attr.cpp b/test/SemaCXX/init-priority-attr.cpp
index 7605ee625ed4..6facebf0d000 100644
--- a/test/SemaCXX/init-priority-attr.cpp
+++ b/test/SemaCXX/init-priority-attr.cpp
@@ -19,7 +19,7 @@ extern Two koo[];
Two foo __attribute__((init_priority(101))) ( 5, 6 );
-Two goo __attribute__((init_priority(2,3))) ( 5, 6 ); // expected-error {{attribute requires 1 argument(s)}}
+Two goo __attribute__((init_priority(2,3))) ( 5, 6 ); // expected-error {{attribute takes one argument}}
Two coo[2] __attribute__((init_priority(3))); // expected-error {{init_priority attribute requires integer constant between 101 and 65535 inclusive}}
diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
index 2e9203219536..3581c796ce91 100644
--- a/test/SemaCXX/libstdcxx_is_pod_hack.cpp
+++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
@@ -11,3 +11,19 @@ struct __is_pod {
};
__is_pod<int> ipi;
+
+// Ditto for __is_same.
+template<typename T>
+struct __is_same {
+};
+
+__is_same<int> isi;
+
+// Another, similar egregious hack for __is_signed, which is a type
+// trait in Embarcadero's compiler but is used as an identifier in
+// libstdc++.
+struct test_is_signed {
+ static const bool __is_signed = true;
+};
+
+bool check_signed = test_is_signed::__is_signed;
diff --git a/test/SemaCXX/literal-type.cpp b/test/SemaCXX/literal-type.cpp
index 142dd756e5a3..6a61823adb28 100644
--- a/test/SemaCXX/literal-type.cpp
+++ b/test/SemaCXX/literal-type.cpp
@@ -1,10 +1,71 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
static_assert(__is_literal(int), "fail");
+static_assert(__is_literal_type(int), "fail"); // alternate spelling for GCC
static_assert(__is_literal(void*), "fail");
enum E { E1 };
static_assert(__is_literal(E), "fail");
static_assert(__is_literal(decltype(E1)), "fail");
typedef int IAR[10];
static_assert(__is_literal(IAR), "fail");
-// FIXME: Records
+typedef int Vector __attribute__((vector_size(16)));
+typedef int VectorExt __attribute__((ext_vector_type(4)));
+static_assert(__is_literal(Vector), "fail");
+static_assert(__is_literal(VectorExt), "fail");
+
+// C++0x [basic.types]p10:
+// A type is a literal type if it is:
+// [...]
+// -- a class type that has all of the following properties:
+// -- it has a trivial destructor
+// -- every constructor call and full-expression in the
+// brace-or-equal-initializers for non-static data members (if an) is
+// a constant expression,
+// -- it is an aggregate type or has at least one constexpr constructor
+// or constructor template that is not a copy or move constructor, and
+// -- it has all non-static data members and base classes of literal
+// types
+struct Empty {};
+struct LiteralType {
+ int x;
+ E e;
+ IAR arr;
+ Empty empty;
+ int method();
+};
+struct HasDtor { ~HasDtor(); };
+
+class NonAggregate { int x; };
+struct HasNonLiteralBase : NonAggregate {};
+struct HasNonLiteralMember { HasDtor x; };
+
+static_assert(__is_literal(Empty), "fail");
+static_assert(__is_literal(LiteralType), "fail");
+static_assert(!__is_literal(HasDtor), "fail");
+static_assert(!__is_literal(NonAggregate), "fail");
+static_assert(!__is_literal(HasNonLiteralBase), "fail");
+static_assert(!__is_literal(HasNonLiteralMember), "fail");
+
+// FIXME: Test constexpr constructors and non-static members with initializers
+// when Clang supports them:
+#if 0
+extern int f();
+struct HasNonConstExprMemInit {
+ int x = f();
+ constexpr HasNonConstExprMemInit(int y) {}
+};
+static_assert(!__is_literal(HasNonConstExprMemInit), "fail");
+
+class HasConstExprCtor {
+ int x;
+public:
+ constexpr HasConstExprCtor(int x) : x(x) {}
+};
+template <typename T> class HasConstExprCtorTemplate {
+ T x;
+public:
+ template <typename U> constexpr HasConstExprCtorTemplate(U y) : x(y) {}
+};
+static_assert(__is_literal(HasConstExprCtor), "fail");
+static_assert(__is_literal(HasConstExprCtorTemplate), "fail");
+#endif
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 3c3eb04e08fa..68af4152ef4e 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -135,4 +135,9 @@ namespace PR9025 {
int g3() {
return fun3.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
}
+
+ template <typename T> S fun4();
+ int g4() {
+ return fun4.x; // expected-error{{base of member reference is a function; perhaps you meant to call it?}}
+ }
}
diff --git a/test/SemaCXX/member-pointers-2.cpp b/test/SemaCXX/member-pointers-2.cpp
index 4b3b82c02975..6c39282e5a31 100644
--- a/test/SemaCXX/member-pointers-2.cpp
+++ b/test/SemaCXX/member-pointers-2.cpp
@@ -34,3 +34,18 @@ void test0() {
Test0 mytest;
mytest.test();
}
+
+namespace rdar9065289 {
+ typedef void (*FuncPtr)();
+ struct X0 { };
+
+ struct X1
+ {
+ X0* x0;
+ FuncPtr X0::*fptr;
+ };
+
+ void f(X1 p) {
+ (p.x0->*(p.fptr))();
+ }
+}
diff --git a/test/SemaCXX/neon-vector-types.cpp b/test/SemaCXX/neon-vector-types.cpp
new file mode 100644
index 000000000000..aa82b11e8cd7
--- /dev/null
+++ b/test/SemaCXX/neon-vector-types.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9208404
+
+typedef int MP4Err;
+typedef float Float32;
+typedef float float32_t;
+typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t;
+typedef float vFloat __attribute__((__vector_size__(16)));
+typedef vFloat VFLOAT;
+typedef unsigned long UInt32;
+
+extern int bar (float32x4_t const *p);
+
+int foo (const Float32 *realBufPtr) {
+ float32x4_t const *vRealPtr = (VFLOAT *)&realBufPtr[0];
+ return bar(vRealPtr);
+}
+
+MP4Err autoCorrelation2nd_Neon(Float32 *alphar, Float32 *alphai,
+ const Float32 *realBufPtr,
+ const Float32 *imagBufPtr,
+ const UInt32 len)
+{
+ float32x4_t const *vRealPtr = (VFLOAT *)&realBufPtr[0];
+ return 0;
+}
+
diff --git a/test/SemaCXX/nested-name-spec-locations.cpp b/test/SemaCXX/nested-name-spec-locations.cpp
index 25914df627bd..048d4baf135b 100644
--- a/test/SemaCXX/nested-name-spec-locations.cpp
+++ b/test/SemaCXX/nested-name-spec-locations.cpp
@@ -65,6 +65,98 @@ void PseudoDestructorExprCheck(
template<typename T>
struct DependentScopedDeclRefExpr {
void f() {
- outer_alias::inner::X0<T>::value = 17;
+ outer_alias::inner::X0<typename add_reference<T>::type
+ * // expected-error{{as a pointer to a reference of type}}
+ >::value = 17;
}
};
+
+void DependentScopedDeclRefExprCheck(DependentScopedDeclRefExpr<int> t) {
+ t.f(); // expected-note{{in instantiation of member function}}
+}
+
+
+template<typename T>
+struct TypenameTypeTester {
+ typedef typename outer::inner::X0<
+ typename add_reference<T>::type
+ * // expected-error{{declared as a pointer to a reference of type}}
+ >::type type;
+};
+
+TypenameTypeTester<int> TypenameTypeCheck; // expected-note{{in instantiation of template class}}
+
+template<typename T, typename U>
+struct DependentTemplateSpecializationTypeTester {
+ typedef typename T::template apply<typename add_reference<U>::type
+ * // expected-error{{declared as a pointer to a reference of type}}
+ >::type type;
+};
+
+struct HasApply {
+ template<typename T>
+ struct apply {
+ typedef T type;
+ };
+};
+
+DependentTemplateSpecializationTypeTester<HasApply, int> DTSTCheck; // expected-note{{in instantiation of template class}}
+
+template<typename T, typename U>
+struct DependentTemplateSpecializationTypeTester2 {
+ typedef typename T::template apply<typename add_reference<U>::type
+ * // expected-error{{declared as a pointer to a reference of type}}
+ > type;
+};
+
+DependentTemplateSpecializationTypeTester2<HasApply, int> DTSTCheck2; // expected-note{{in instantiation of template class}}
+
+template<typename T, typename U>
+struct DependentTemplateSpecializationTypeTester3 :
+ T::template apply<typename add_reference<U>::type
+ * // expected-error{{declared as a pointer to a reference of type}}
+ >
+{};
+
+DependentTemplateSpecializationTypeTester3<HasApply, int> DTSTCheck3; // expected-note{{in instantiation of template class}}
+
+template<typename T, typename U>
+struct DependentTemplateSpecializationTypeTester4 {
+ typedef class T::template apply<typename add_reference<U>::type
+ * // expected-error{{declared as a pointer to a reference of type}}
+ > type;
+};
+
+DependentTemplateSpecializationTypeTester4<HasApply, int> DTSTCheck4; // expected-note{{in instantiation of template class}}
+
+template<template<class T> class TTP>
+struct AcceptedTemplateTemplateParameter {
+};
+
+template<typename T, typename U>
+struct DependentTemplateTemplateArgumentTester {
+ typedef AcceptedTemplateTemplateParameter<
+ T::
+ template apply<
+ typename add_reference<U>::type
+ * // expected-error{{declared as a pointer to a reference of type}}
+ >::
+ template X>
+ type;
+};
+
+DependentTemplateTemplateArgumentTester<HasApply, int> DTTACheck; // expected-note{{in instantiation of template class}}
+
+namespace PR9388 {
+ namespace std {
+ template<typename T> class vector {
+ };
+ }
+ template<typename T> static void foo(std::vector<T*> &V) {
+ __PRETTY_FUNCTION__; // expected-warning{{expression result unused}}
+ }
+ void bar(std::vector<int*> &Blocks) {
+ foo(Blocks); // expected-note{{in instantiation of}}
+ }
+
+}
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
index 01f3d9367935..84c80aa286c2 100644
--- a/test/SemaCXX/nullptr.cpp
+++ b/test/SemaCXX/nullptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify -std=c++0x -ffreestanding %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x -ffreestanding %s
#include <stdint.h>
typedef decltype(nullptr) nullptr_t;
diff --git a/test/SemaCXX/operator-arrow-temporary.cpp b/test/SemaCXX/operator-arrow-temporary.cpp
new file mode 100644
index 000000000000..8e79609342b5
--- /dev/null
+++ b/test/SemaCXX/operator-arrow-temporary.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// PR9615
+
+struct Resource {
+ void doit();
+};
+
+template<int x> struct Lock {
+ ~Lock() { int a[x]; } // expected-error {{declared as an array with a negative size}}
+ Resource* operator->() { return 0; }
+};
+
+struct Accessor {
+ Lock<-1> operator->();
+};
+
+// Make sure we try to instantiate the destructor for Lock here
+void f() { Accessor acc; acc->doit(); } // expected-note {{requested here}}
+
diff --git a/test/SemaCXX/overloaded-name.cpp b/test/SemaCXX/overloaded-name.cpp
index 289d5c92ecff..5a87cc8e67e6 100644
--- a/test/SemaCXX/overloaded-name.cpp
+++ b/test/SemaCXX/overloaded-name.cpp
@@ -1,14 +1,14 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int ovl(int);
-float ovl(float);
+int ovl(int); // expected-note 3{{candidate function}}
+float ovl(float); // expected-note 3{{candidate function}}
-template<typename T> T ovl(T);
+template<typename T> T ovl(T); // expected-note 3{{candidate function}}
void test(bool b) {
- (void)((void)0, ovl); // expected-error{{cannot resolve overloaded function from context}}
+ (void)((void)0, ovl); // expected-error{{cannot resolve overloaded function 'ovl' from context}}
// PR7863
- (void)(b? ovl : &ovl); // expected-error{{cannot resolve overloaded function from context}}
- (void)(b? ovl<float> : &ovl); // expected-error{{cannot resolve overloaded function from context}}
+ (void)(b? ovl : &ovl); // expected-error{{cannot resolve overloaded function 'ovl' from context}}
+ (void)(b? ovl<float> : &ovl); // expected-error{{cannot resolve overloaded function 'ovl' from context}}
(void)(b? ovl<float> : ovl<float>);
}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 4399a026eaf4..44d013fe796e 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -384,3 +384,18 @@ void test_lookup_through_using() {
N::X2 x;
x << 17;
}
+
+namespace rdar9136502 {
+ struct X {
+ int i();
+ int i(int);
+ };
+
+ struct Y {
+ Y &operator<<(int); // expected-note{{candidate function not viable: no known conversion from '<bound member function type>' to 'int'}}
+ };
+
+ void f(X x, Y y) {
+ y << x.i; // expected-error{{a bound member function may only be called}}
+ }
+}
diff --git a/test/SemaCXX/pascal-strings.cpp b/test/SemaCXX/pascal-strings.cpp
new file mode 100644
index 000000000000..89194b54aa8d
--- /dev/null
+++ b/test/SemaCXX/pascal-strings.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fpascal-strings
+const wchar_t *pascalString = L"\pThis is a Pascal string";
+
+unsigned char a[3] = "\pa";
+unsigned char b[3] = "\pab";
+unsigned char c[3] = "\pabc"; // expected-error {{initializer-string for char array is too long}}
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index 30d9faac2e28..d71304e28b11 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -2,7 +2,7 @@
struct A {};
enum Foo { F };
-typedef Foo Bar;
+typedef Foo Bar; // expected-note{{type 'Bar' (aka 'Foo') is declared here}}
typedef int Integer;
typedef double Double;
@@ -23,10 +23,9 @@ void f(A* a, Foo *f, int *i, double *d) {
a->~A();
a->A::~A();
- a->~foo(); // expected-error{{identifier 'foo' in pseudo-destructor expression does not name a type}}
+ a->~foo(); // expected-error{{identifier 'foo' in object destruction expression does not name a type}}
- // FIXME: the diagnostic below isn't wonderful
- a->~Bar(); // expected-error{{does not name a type}}
+ a->~Bar(); // expected-error{{destructor type 'Bar' (aka 'Foo') in object destruction expression does not match the type 'A' of the object being destroyed}}
f->~Bar();
f->~Foo();
diff --git a/test/SemaCXX/ptrtomember.cpp b/test/SemaCXX/ptrtomember.cpp
index 1038de9a1d3b..c3917333a540 100644
--- a/test/SemaCXX/ptrtomember.cpp
+++ b/test/SemaCXX/ptrtomember.cpp
@@ -27,6 +27,7 @@ void f3(S3* p, void (S3::*m)()) {
(void)(void*)(p->*m); // expected-error {{a bound member function may only be called}}
(void)reinterpret_cast<void*>(p->*m); // expected-error {{a bound member function may only be called}}
if (p->*m) {} // expected-error {{a bound member function may only be called}}
-
- p->m; // expected-error {{a bound member function may only be called}}
+ if (!(p->*m)) {} // expected-error {{a bound member function may only be called}}
+ if (p->m) {}; // expected-error {{a bound member function may only be called}}
+ if (!p->m) {}; // expected-error {{a bound member function may only be called}}
}
diff --git a/test/SemaCXX/reinterpret-cast.cpp b/test/SemaCXX/reinterpret-cast.cpp
index 74dbc01ee5ac..f5262496c4b0 100644
--- a/test/SemaCXX/reinterpret-cast.cpp
+++ b/test/SemaCXX/reinterpret-cast.cpp
@@ -45,9 +45,9 @@ void constness()
// Valid: T1* -> T2 const*
int const *icp = reinterpret_cast<int const*>(ipppc);
// Invalid: T1 const* -> T2*
- (void)reinterpret_cast<int*>(icp); // expected-error {{reinterpret_cast from 'const int *' to 'int *' casts away constness}}
+ (void)reinterpret_cast<int*>(icp); // expected-error {{reinterpret_cast from 'const int *' to 'int *' casts away qualifiers}}
// Invalid: T1*** -> T2 const* const**
- int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***' to 'const int *const **' casts away constness}}
+ int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***' to 'const int *const **' casts away qualifiers}}
// Valid: T1* -> T2*
int *ip = reinterpret_cast<int*>(icpcpp);
// Valid: T* -> T const*
@@ -77,7 +77,7 @@ void memptrs()
{
const int structure::*psi = 0;
(void)reinterpret_cast<const float structure::*>(psi);
- (void)reinterpret_cast<int structure::*>(psi); // expected-error {{reinterpret_cast from 'const int structure::*' to 'int structure::*' casts away constness}}
+ (void)reinterpret_cast<int structure::*>(psi); // expected-error {{reinterpret_cast from 'const int structure::*' to 'int structure::*' casts away qualifiers}}
void (structure::*psf)() = 0;
(void)reinterpret_cast<int (structure::*)()>(psf);
@@ -105,6 +105,14 @@ void const_arrays() {
const STRING *s;
const char *c;
- (void)reinterpret_cast<char *>(s); // expected-error {{reinterpret_cast from 'const STRING *' (aka 'char const (*)[10]') to 'char *' casts away constness}}
+ (void)reinterpret_cast<char *>(s); // expected-error {{reinterpret_cast from 'const STRING *' (aka 'char const (*)[10]') to 'char *' casts away qualifiers}}
(void)reinterpret_cast<const STRING *>(c);
}
+
+namespace PR9564 {
+ struct a { int a : 10; }; a x;
+ int *y = &reinterpret_cast<int&>(x.a); // expected-error {{not allowed}}
+
+ __attribute((ext_vector_type(4))) typedef float v4;
+ float& w(v4 &a) { return reinterpret_cast<float&>(a[1]); } // expected-error {{not allowed}}
+}
diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp
index 7e0a69c266b5..53ed0d724527 100644
--- a/test/SemaCXX/return-noreturn.cpp
+++ b/test/SemaCXX/return-noreturn.cpp
@@ -1,18 +1,69 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code
-// XFAIL: *
// A destructor may be marked noreturn and should still influence the CFG.
-namespace PR6884 {
- struct abort_struct {
- abort_struct() {} // Make this non-POD so the destructor is invoked.
- ~abort_struct() __attribute__((noreturn));
- };
-
- int f() {
- abort_struct();
+void pr6884_abort() __attribute__((noreturn));
+
+struct pr6884_abort_struct {
+ pr6884_abort_struct() {}
+ ~pr6884_abort_struct() __attribute__((noreturn)) { pr6884_abort(); }
+};
+
+int pr6884_f(int x) {
+ switch (x) { default: pr6884_abort(); }
+}
+
+int pr6884_g(int x) {
+ switch (x) { default: pr6884_abort_struct(); }
+}
+
+int pr6884_g_positive(int x) {
+ switch (x) { default: ; }
+} // expected-warning {{control reaches end of non-void function}}
+
+int pr6884_h(int x) {
+ switch (x) {
+ default: {
+ pr6884_abort_struct a;
+ }
}
+}
- int f2() {
- abort_struct s;
+// PR9380
+struct PR9380 {
+ ~PR9380();
+};
+struct PR9380_B : public PR9380 {
+ PR9380_B( const PR9380& str );
+};
+void test_PR9380(const PR9380& aKey) {
+ const PR9380& flatKey = PR9380_B(aKey);
+}
+
+// Array of objects with destructors. This is purely a coverage test case.
+void test_array() {
+ PR9380 a[2];
+}
+
+// Test classes wrapped in typedefs. This is purely a coverage test case
+// for CFGImplictDtor::getDestructorDecl().
+void test_typedefs() {
+ typedef PR9380 PR9380_Ty;
+ PR9380_Ty test;
+ PR9380_Ty test2[20];
+}
+
+// PR9412 - Handle CFG traversal with null successors.
+enum PR9412_MatchType { PR9412_Exact };
+
+template <PR9412_MatchType type> int PR9412_t() {
+ switch (type) {
+ case PR9412_Exact:
+ default:
+ break;
}
+} // expected-warning {{control reaches end of non-void function}}
+
+void PR9412_f() {
+ PR9412_t<PR9412_Exact>(); // expected-note {{in instantiation of function template specialization 'PR9412_t<0>' requested here}}
}
+
diff --git a/test/SemaCXX/return.cpp b/test/SemaCXX/return.cpp
index 46524fccfcc5..af7f50ce44b3 100644
--- a/test/SemaCXX/return.cpp
+++ b/test/SemaCXX/return.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fexceptions -fsyntax-only -Wignored-qualifiers -verify
+// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -Wignored-qualifiers -verify
int test1() {
throw;
@@ -41,3 +41,15 @@ char* volatile i(); // expected-warning{{'volatile' type qualifier on return typ
const volatile int scalar_cv(); // expected-warning{{'const volatile' type qualifiers on return type have no effect}}
}
+
+namespace PR9328 {
+ typedef char *PCHAR;
+ class Test
+ {
+ const PCHAR GetName() { return 0; } // expected-warning{{'const' type qualifier on return type has no effect}}
+ };
+}
+
+class foo {
+ operator int * const ();
+};
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
index 11187cba5d82..74afdbe41043 100644
--- a/test/SemaCXX/rval-references.cpp
+++ b/test/SemaCXX/rval-references.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++0x %s
typedef int&& irr;
typedef irr& ilr_c1; // Collapses to int&
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index d462af06d730..3a90cc08f6a2 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-unreachable-code
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu++0x %s -Wno-unreachable-code
namespace test0 {
struct D { ~D(); };
@@ -151,3 +152,22 @@ namespace test8 {
l2: x++;
}
}
+
+namespace test9 {
+ struct S { int i; };
+ void test1() {
+ goto foo;
+ S s;
+ foo:
+ return;
+ }
+ unsigned test2(unsigned x, unsigned y) {
+ switch (x) {
+ case 2:
+ S s;
+ if (y > 42) return x + y;
+ default:
+ return x - 2;
+ }
+ }
+}
diff --git a/test/SemaCXX/short-enums.cpp b/test/SemaCXX/short-enums.cpp
new file mode 100644
index 000000000000..ca713b733410
--- /dev/null
+++ b/test/SemaCXX/short-enums.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fshort-enums -fsyntax-only %s
+
+// This shouldn't crash: PR9474
+
+enum E { VALUE_1 };
+
+template <typename T>
+struct A {};
+
+template <E Enum>
+struct B : A<B<Enum> > {};
+
+void bar(int x) {
+ switch (x) {
+ case sizeof(B<VALUE_1>): ;
+ }
+} \ No newline at end of file
diff --git a/test/SemaCXX/short-wchar-sign.cpp b/test/SemaCXX/short-wchar-sign.cpp
new file mode 100644
index 000000000000..9a177c04b104
--- /dev/null
+++ b/test/SemaCXX/short-wchar-sign.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fshort-wchar -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -pedantic -verify %s
+
+// Check that short wchar_t is unsigned, and that regular wchar_t is not.
+int test[(wchar_t(-1)<wchar_t(0)) == (sizeof(wchar_t) == 4) ?1:-1];
diff --git a/test/SemaCXX/sourceranges.cpp b/test/SemaCXX/sourceranges.cpp
index 602d76baa9db..0537aa20d5e9 100644
--- a/test/SemaCXX/sourceranges.cpp
+++ b/test/SemaCXX/sourceranges.cpp
@@ -13,15 +13,15 @@ typedef int C;
}
int main() {
- // CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::class A *'
+ // CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::A *'
P<foo::A> p14 = new foo::A;
- // CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::enum B *'
+ // CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::B *'
P<foo::B> p24 = new foo::B;
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::C *'
P<foo::C> pr4 = new foo::C;
}
foo::A getName() {
- // CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:10, col:17> 'foo::class A'
+ // CHECK: CXXConstructExpr {{0x[0-9a-fA-F]+}} <col:10, col:17> 'foo::A'
return foo::A();
}
diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp
index 46c6eee2c4e8..7fb016ea86d8 100644
--- a/test/SemaCXX/static-cast.cpp
+++ b/test/SemaCXX/static-cast.cpp
@@ -84,8 +84,8 @@ void t_529_5_8()
(void)static_cast<C1&>(*((A*)0)); // expected-error {{cannot cast 'A' to 'C1 &' via virtual base 'B'}}
(void)static_cast<D*>((A*)0); // expected-error {{cannot cast 'A *' to 'D *' via virtual base 'B'}}
(void)static_cast<D&>(*((A*)0)); // expected-error {{cannot cast 'A' to 'D &' via virtual base 'B'}}
- (void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'const A *' to 'B *' casts away constness}}
- (void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'const A' to 'B &' casts away constness}}
+ (void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'const A *' to 'B *' casts away qualifiers}}
+ (void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'const A' to 'B &' casts away qualifiers}}
(void)static_cast<E*>((A*)0); // expected-error {{cannot cast private base class 'A' to 'E'}}
(void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast private base class 'A' to 'E'}}
(void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'A' to derived 'H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
@@ -119,7 +119,7 @@ void t_529_10()
// Bad code below
- (void)static_cast<int*>((const void*)0); // expected-error {{static_cast from 'const void *' to 'int *' casts away constness}}
+ (void)static_cast<int*>((const void*)0); // expected-error {{static_cast from 'const void *' to 'int *' casts away qualifiers}}
(void)static_cast<void (*)()>((void*)0); // expected-error {{static_cast from 'void *' to 'void (*)()' is not allowed}}
}
diff --git a/test/SemaCXX/storage-class.cpp b/test/SemaCXX/storage-class.cpp
index a2e206323a07..01cfbfc51faa 100644
--- a/test/SemaCXX/storage-class.cpp
+++ b/test/SemaCXX/storage-class.cpp
@@ -2,3 +2,6 @@
extern const int PR6495a = 42;
extern int PR6495b = 42; // expected-warning{{'extern' variable has an initializer}}
extern const int PR6495c[] = {42,43,44};
+
+extern struct Test1 {}; // expected-warning {{'extern' ignored on this declaration}}
+extern "C" struct Test0 {}; // no warning
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index ff9a6bf51a6f..96e9696a041c 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
@@ -27,22 +27,37 @@ struct HasAnonymousUnion {
};
};
+typedef int Vector __attribute__((vector_size(16)));
+typedef int VectorExt __attribute__((ext_vector_type(4)));
+
// Not PODs
typedef const void cvoid;
struct Derives : POD {};
+typedef Derives DerivesAr[10];
+typedef Derives DerivesArNB[];
struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
+struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; // \
+ // expected-warning {{rvalue references}}
struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} };
struct HasNonPOD { NonPOD np; };
struct HasVirt { virtual void Virt() {}; };
-typedef Derives NonPODAr[10];
+typedef NonPOD NonPODAr[10];
typedef HasVirt VirtAr[10];
-typedef HasCons NonPODArNB[];
+typedef NonPOD NonPODArNB[];
union NonPODUnion { int i; Derives n; };
+struct DerivesHasCons : HasCons {};
+struct DerivesHasCopyAssign : HasCopyAssign {};
+struct DerivesHasMoveAssign : HasMoveAssign {};
+struct DerivesHasDest : HasDest {};
+struct DerivesHasPriv : HasPriv {};
+struct DerivesHasProt : HasProt {};
+struct DerivesHasRef : HasRef {};
+struct DerivesHasVirt : HasVirt {};
struct HasNoThrowCopyAssign {
void operator =(const HasNoThrowCopyAssign&) throw();
@@ -77,37 +92,51 @@ typedef HasVirtDest VirtDestAr[1];
void is_pod()
{
- int t01[T(__is_pod(int))];
- int t02[T(__is_pod(Enum))];
- int t03[T(__is_pod(POD))];
- int t04[T(__is_pod(Int))];
- int t05[T(__is_pod(IntAr))];
- int t06[T(__is_pod(Statics))];
- int t07[T(__is_pod(Empty))];
- int t08[T(__is_pod(EmptyUnion))];
- int t09[T(__is_pod(Union))];
- int t10[T(__is_pod(HasFunc))];
- int t11[T(__is_pod(HasOp))];
- int t12[T(__is_pod(HasConv))];
- int t13[T(__is_pod(HasAssign))];
- int t14[T(__is_pod(IntArNB))];
- int t15[T(__is_pod(HasAnonymousUnion))];
-
- int t21[F(__is_pod(Derives))];
- int t22[F(__is_pod(HasCons))];
- int t23[F(__is_pod(HasCopyAssign))];
- int t24[F(__is_pod(HasDest))];
- int t25[F(__is_pod(HasPriv))];
- int t26[F(__is_pod(HasProt))];
- int t27[F(__is_pod(HasRef))];
- int t28[F(__is_pod(HasNonPOD))];
- int t29[F(__is_pod(HasVirt))];
- int t30[F(__is_pod(NonPODAr))];
- int t31[F(__is_pod(DerivesEmpty))];
- int t32[F(__is_pod(void))];
- int t33[F(__is_pod(cvoid))];
- int t34[F(__is_pod(NonPODArNB))];
- // int t32[F(__is_pod(NonPODUnion))];
+ { int arr[T(__is_pod(int))]; }
+ { int arr[T(__is_pod(Enum))]; }
+ { int arr[T(__is_pod(POD))]; }
+ { int arr[T(__is_pod(Int))]; }
+ { int arr[T(__is_pod(IntAr))]; }
+ { int arr[T(__is_pod(Statics))]; }
+ { int arr[T(__is_pod(Empty))]; }
+ { int arr[T(__is_pod(EmptyUnion))]; }
+ { int arr[T(__is_pod(Union))]; }
+ { int arr[T(__is_pod(HasFunc))]; }
+ { int arr[T(__is_pod(HasOp))]; }
+ { int arr[T(__is_pod(HasConv))]; }
+ { int arr[T(__is_pod(HasAssign))]; }
+ { int arr[T(__is_pod(IntArNB))]; }
+ { int arr[T(__is_pod(HasAnonymousUnion))]; }
+ { int arr[T(__is_pod(Vector))]; }
+ { int arr[T(__is_pod(VectorExt))]; }
+
+ { int arr[F(__is_pod(Derives))]; }
+ { int arr[F(__is_pod(DerivesAr))]; }
+ { int arr[F(__is_pod(DerivesArNB))]; }
+ { int arr[F(__is_pod(DerivesEmpty))]; }
+ { int arr[F(__is_pod(HasCons))]; }
+ { int arr[F(__is_pod(HasCopyAssign))]; }
+ { int arr[F(__is_pod(HasMoveAssign))]; }
+ { int arr[F(__is_pod(HasDest))]; }
+ { int arr[F(__is_pod(HasPriv))]; }
+ { int arr[F(__is_pod(HasProt))]; }
+ { int arr[F(__is_pod(HasRef))]; }
+ { int arr[F(__is_pod(HasVirt))]; }
+ { int arr[F(__is_pod(DerivesHasCons))]; }
+ { int arr[F(__is_pod(DerivesHasCopyAssign))]; }
+ { int arr[F(__is_pod(DerivesHasMoveAssign))]; }
+ { int arr[F(__is_pod(DerivesHasDest))]; }
+ { int arr[F(__is_pod(DerivesHasPriv))]; }
+ { int arr[F(__is_pod(DerivesHasProt))]; }
+ { int arr[F(__is_pod(DerivesHasRef))]; }
+ { int arr[F(__is_pod(DerivesHasVirt))]; }
+ { int arr[F(__is_pod(NonPOD))]; }
+ { int arr[F(__is_pod(HasNonPOD))]; }
+ { int arr[F(__is_pod(NonPODAr))]; }
+ { int arr[F(__is_pod(NonPODArNB))]; }
+ { int arr[F(__is_pod(void))]; }
+ { int arr[F(__is_pod(cvoid))]; }
+// { int arr[F(__is_pod(NonPODUnion))]; }
}
typedef Empty EmptyAr[10];
@@ -118,48 +147,49 @@ struct BitOnly { int x : 3; };
void is_empty()
{
- int t01[T(__is_empty(Empty))];
- int t02[T(__is_empty(DerivesEmpty))];
- int t03[T(__is_empty(HasCons))];
- int t04[T(__is_empty(HasCopyAssign))];
- int t05[T(__is_empty(HasDest))];
- int t06[T(__is_empty(HasFunc))];
- int t07[T(__is_empty(HasOp))];
- int t08[T(__is_empty(HasConv))];
- int t09[T(__is_empty(HasAssign))];
- int t10[T(__is_empty(Bit0))];
- int t11[T(__is_empty(Bit0Cons))];
-
- int t21[F(__is_empty(Int))];
- int t22[F(__is_empty(POD))];
- int t23[F(__is_empty(EmptyUnion))];
- int t24[F(__is_empty(EmptyAr))];
- int t25[F(__is_empty(HasRef))];
- int t26[F(__is_empty(HasVirt))];
- int t27[F(__is_empty(BitOnly))];
- int t28[F(__is_empty(void))];
- int t29[F(__is_empty(IntArNB))];
- int t30[F(__is_empty(HasAnonymousUnion))];
-// int t27[F(__is_empty(DerivesVirt))];
+ { int arr[T(__is_empty(Empty))]; }
+ { int arr[T(__is_empty(DerivesEmpty))]; }
+ { int arr[T(__is_empty(HasCons))]; }
+ { int arr[T(__is_empty(HasCopyAssign))]; }
+ { int arr[T(__is_empty(HasMoveAssign))]; }
+ { int arr[T(__is_empty(HasDest))]; }
+ { int arr[T(__is_empty(HasFunc))]; }
+ { int arr[T(__is_empty(HasOp))]; }
+ { int arr[T(__is_empty(HasConv))]; }
+ { int arr[T(__is_empty(HasAssign))]; }
+ { int arr[T(__is_empty(Bit0))]; }
+ { int arr[T(__is_empty(Bit0Cons))]; }
+
+ { int arr[F(__is_empty(Int))]; }
+ { int arr[F(__is_empty(POD))]; }
+ { int arr[F(__is_empty(EmptyUnion))]; }
+ { int arr[F(__is_empty(EmptyAr))]; }
+ { int arr[F(__is_empty(HasRef))]; }
+ { int arr[F(__is_empty(HasVirt))]; }
+ { int arr[F(__is_empty(BitOnly))]; }
+ { int arr[F(__is_empty(void))]; }
+ { int arr[F(__is_empty(IntArNB))]; }
+ { int arr[F(__is_empty(HasAnonymousUnion))]; }
+// { int arr[F(__is_empty(DerivesVirt))]; }
}
typedef Derives ClassType;
void is_class()
{
- int t01[T(__is_class(Derives))];
- int t02[T(__is_class(HasPriv))];
- int t03[T(__is_class(ClassType))];
- int t04[T(__is_class(HasAnonymousUnion))];
+ { int arr[T(__is_class(Derives))]; }
+ { int arr[T(__is_class(HasPriv))]; }
+ { int arr[T(__is_class(ClassType))]; }
+ { int arr[T(__is_class(HasAnonymousUnion))]; }
- int t11[F(__is_class(int))];
- int t12[F(__is_class(Enum))];
- int t13[F(__is_class(Int))];
- int t14[F(__is_class(IntAr))];
- int t15[F(__is_class(NonPODAr))];
- int t16[F(__is_class(Union))];
- int t17[F(__is_class(cvoid))];
- int t18[F(__is_class(IntArNB))];
+ { int arr[F(__is_class(int))]; }
+ { int arr[F(__is_class(Enum))]; }
+ { int arr[F(__is_class(Int))]; }
+ { int arr[F(__is_class(IntAr))]; }
+ { int arr[F(__is_class(DerivesAr))]; }
+ { int arr[F(__is_class(Union))]; }
+ { int arr[F(__is_class(cvoid))]; }
+ { int arr[F(__is_class(IntArNB))]; }
}
typedef Union UnionAr[10];
@@ -167,36 +197,36 @@ typedef Union UnionType;
void is_union()
{
- int t01[T(__is_union(Union))];
- int t02[T(__is_union(UnionType))];
+ { int arr[T(__is_union(Union))]; }
+ { int arr[T(__is_union(UnionType))]; }
- int t11[F(__is_union(int))];
- int t12[F(__is_union(Enum))];
- int t13[F(__is_union(Int))];
- int t14[F(__is_union(IntAr))];
- int t15[F(__is_union(UnionAr))];
- int t16[F(__is_union(cvoid))];
- int t17[F(__is_union(IntArNB))];
- int t18[F(__is_union(HasAnonymousUnion))];
+ { int arr[F(__is_union(int))]; }
+ { int arr[F(__is_union(Enum))]; }
+ { int arr[F(__is_union(Int))]; }
+ { int arr[F(__is_union(IntAr))]; }
+ { int arr[F(__is_union(UnionAr))]; }
+ { int arr[F(__is_union(cvoid))]; }
+ { int arr[F(__is_union(IntArNB))]; }
+ { int arr[F(__is_union(HasAnonymousUnion))]; }
}
typedef Enum EnumType;
void is_enum()
{
- int t01[T(__is_enum(Enum))];
- int t02[T(__is_enum(EnumType))];
+ { int arr[T(__is_enum(Enum))]; }
+ { int arr[T(__is_enum(EnumType))]; }
- int t11[F(__is_enum(int))];
- int t12[F(__is_enum(Union))];
- int t13[F(__is_enum(Int))];
- int t14[F(__is_enum(IntAr))];
- int t15[F(__is_enum(UnionAr))];
- int t16[F(__is_enum(Derives))];
- int t17[F(__is_enum(ClassType))];
- int t18[F(__is_enum(cvoid))];
- int t19[F(__is_enum(IntArNB))];
- int t20[F(__is_enum(HasAnonymousUnion))];
+ { int arr[F(__is_enum(int))]; }
+ { int arr[F(__is_enum(Union))]; }
+ { int arr[F(__is_enum(Int))]; }
+ { int arr[F(__is_enum(IntAr))]; }
+ { int arr[F(__is_enum(UnionAr))]; }
+ { int arr[F(__is_enum(Derives))]; }
+ { int arr[F(__is_enum(ClassType))]; }
+ { int arr[F(__is_enum(cvoid))]; }
+ { int arr[F(__is_enum(IntArNB))]; }
+ { int arr[F(__is_enum(HasAnonymousUnion))]; }
}
typedef HasVirt Polymorph;
@@ -204,19 +234,788 @@ struct InheritPolymorph : Polymorph {};
void is_polymorphic()
{
- int t01[T(__is_polymorphic(Polymorph))];
- int t02[T(__is_polymorphic(InheritPolymorph))];
+ { int arr[T(__is_polymorphic(Polymorph))]; }
+ { int arr[T(__is_polymorphic(InheritPolymorph))]; }
+
+ { int arr[F(__is_polymorphic(int))]; }
+ { int arr[F(__is_polymorphic(Union))]; }
+ { int arr[F(__is_polymorphic(Int))]; }
+ { int arr[F(__is_polymorphic(IntAr))]; }
+ { int arr[F(__is_polymorphic(UnionAr))]; }
+ { int arr[F(__is_polymorphic(Derives))]; }
+ { int arr[F(__is_polymorphic(ClassType))]; }
+ { int arr[F(__is_polymorphic(Enum))]; }
+ { int arr[F(__is_polymorphic(cvoid))]; }
+ { int arr[F(__is_polymorphic(IntArNB))]; }
+}
+
+void is_integral()
+{
+ int t01[T(__is_integral(bool))];
+ int t02[T(__is_integral(char))];
+ int t03[T(__is_integral(signed char))];
+ int t04[T(__is_integral(unsigned char))];
+ //int t05[T(__is_integral(char16_t))];
+ //int t06[T(__is_integral(char32_t))];
+ int t07[T(__is_integral(wchar_t))];
+ int t08[T(__is_integral(short))];
+ int t09[T(__is_integral(unsigned short))];
+ int t10[T(__is_integral(int))];
+ int t11[T(__is_integral(unsigned int))];
+ int t12[T(__is_integral(long))];
+ int t13[T(__is_integral(unsigned long))];
+
+ int t21[F(__is_integral(float))];
+ int t22[F(__is_integral(double))];
+ int t23[F(__is_integral(long double))];
+ int t24[F(__is_integral(Union))];
+ int t25[F(__is_integral(UnionAr))];
+ int t26[F(__is_integral(Derives))];
+ int t27[F(__is_integral(ClassType))];
+ int t28[F(__is_integral(Enum))];
+ int t29[F(__is_integral(void))];
+ int t30[F(__is_integral(cvoid))];
+ int t31[F(__is_integral(IntArNB))];
+}
+
+void is_floating_point()
+{
+ int t01[T(__is_floating_point(float))];
+ int t02[T(__is_floating_point(double))];
+ int t03[T(__is_floating_point(long double))];
+
+ int t11[F(__is_floating_point(bool))];
+ int t12[F(__is_floating_point(char))];
+ int t13[F(__is_floating_point(signed char))];
+ int t14[F(__is_floating_point(unsigned char))];
+ //int t15[F(__is_floating_point(char16_t))];
+ //int t16[F(__is_floating_point(char32_t))];
+ int t17[F(__is_floating_point(wchar_t))];
+ int t18[F(__is_floating_point(short))];
+ int t19[F(__is_floating_point(unsigned short))];
+ int t20[F(__is_floating_point(int))];
+ int t21[F(__is_floating_point(unsigned int))];
+ int t22[F(__is_floating_point(long))];
+ int t23[F(__is_floating_point(unsigned long))];
+ int t24[F(__is_floating_point(Union))];
+ int t25[F(__is_floating_point(UnionAr))];
+ int t26[F(__is_floating_point(Derives))];
+ int t27[F(__is_floating_point(ClassType))];
+ int t28[F(__is_floating_point(Enum))];
+ int t29[F(__is_floating_point(void))];
+ int t30[F(__is_floating_point(cvoid))];
+ int t31[F(__is_floating_point(IntArNB))];
+}
+
+void is_arithmetic()
+{
+ int t01[T(__is_arithmetic(float))];
+ int t02[T(__is_arithmetic(double))];
+ int t03[T(__is_arithmetic(long double))];
+ int t11[T(__is_arithmetic(bool))];
+ int t12[T(__is_arithmetic(char))];
+ int t13[T(__is_arithmetic(signed char))];
+ int t14[T(__is_arithmetic(unsigned char))];
+ //int t15[T(__is_arithmetic(char16_t))];
+ //int t16[T(__is_arithmetic(char32_t))];
+ int t17[T(__is_arithmetic(wchar_t))];
+ int t18[T(__is_arithmetic(short))];
+ int t19[T(__is_arithmetic(unsigned short))];
+ int t20[T(__is_arithmetic(int))];
+ int t21[T(__is_arithmetic(unsigned int))];
+ int t22[T(__is_arithmetic(long))];
+ int t23[T(__is_arithmetic(unsigned long))];
+
+ int t24[F(__is_arithmetic(Union))];
+ int t25[F(__is_arithmetic(UnionAr))];
+ int t26[F(__is_arithmetic(Derives))];
+ int t27[F(__is_arithmetic(ClassType))];
+ int t28[F(__is_arithmetic(Enum))];
+ int t29[F(__is_arithmetic(void))];
+ int t30[F(__is_arithmetic(cvoid))];
+ int t31[F(__is_arithmetic(IntArNB))];
+}
+
+struct ACompleteType {};
+struct AnIncompleteType;
+
+void is_complete_type()
+{
+ int t01[T(__is_complete_type(float))];
+ int t02[T(__is_complete_type(double))];
+ int t03[T(__is_complete_type(long double))];
+ int t11[T(__is_complete_type(bool))];
+ int t12[T(__is_complete_type(char))];
+ int t13[T(__is_complete_type(signed char))];
+ int t14[T(__is_complete_type(unsigned char))];
+ //int t15[T(__is_complete_type(char16_t))];
+ //int t16[T(__is_complete_type(char32_t))];
+ int t17[T(__is_complete_type(wchar_t))];
+ int t18[T(__is_complete_type(short))];
+ int t19[T(__is_complete_type(unsigned short))];
+ int t20[T(__is_complete_type(int))];
+ int t21[T(__is_complete_type(unsigned int))];
+ int t22[T(__is_complete_type(long))];
+ int t23[T(__is_complete_type(unsigned long))];
+ int t24[T(__is_complete_type(ACompleteType))];
+
+ int t30[F(__is_complete_type(AnIncompleteType))];
+}
+
+void is_void()
+{
+ int t01[T(__is_void(void))];
+ int t02[T(__is_void(cvoid))];
+
+ int t10[F(__is_void(float))];
+ int t11[F(__is_void(double))];
+ int t12[F(__is_void(long double))];
+ int t13[F(__is_void(bool))];
+ int t14[F(__is_void(char))];
+ int t15[F(__is_void(signed char))];
+ int t16[F(__is_void(unsigned char))];
+ int t17[F(__is_void(wchar_t))];
+ int t18[F(__is_void(short))];
+ int t19[F(__is_void(unsigned short))];
+ int t20[F(__is_void(int))];
+ int t21[F(__is_void(unsigned int))];
+ int t22[F(__is_void(long))];
+ int t23[F(__is_void(unsigned long))];
+ int t24[F(__is_void(Union))];
+ int t25[F(__is_void(UnionAr))];
+ int t26[F(__is_void(Derives))];
+ int t27[F(__is_void(ClassType))];
+ int t28[F(__is_void(Enum))];
+ int t29[F(__is_void(IntArNB))];
+ int t30[F(__is_void(void*))];
+ int t31[F(__is_void(cvoid*))];
+}
+
+void is_array()
+{
+ int t01[T(__is_array(IntAr))];
+ int t02[T(__is_array(IntArNB))];
+ int t03[T(__is_array(UnionAr))];
+
+ int t10[F(__is_array(void))];
+ int t11[F(__is_array(cvoid))];
+ int t12[F(__is_array(float))];
+ int t13[F(__is_array(double))];
+ int t14[F(__is_array(long double))];
+ int t15[F(__is_array(bool))];
+ int t16[F(__is_array(char))];
+ int t17[F(__is_array(signed char))];
+ int t18[F(__is_array(unsigned char))];
+ int t19[F(__is_array(wchar_t))];
+ int t20[F(__is_array(short))];
+ int t21[F(__is_array(unsigned short))];
+ int t22[F(__is_array(int))];
+ int t23[F(__is_array(unsigned int))];
+ int t24[F(__is_array(long))];
+ int t25[F(__is_array(unsigned long))];
+ int t26[F(__is_array(Union))];
+ int t27[F(__is_array(Derives))];
+ int t28[F(__is_array(ClassType))];
+ int t29[F(__is_array(Enum))];
+ int t30[F(__is_array(void*))];
+ int t31[F(__is_array(cvoid*))];
+}
+
+template <typename T> void tmpl_func(T&) {}
+
+template <typename T> struct type_wrapper {
+ typedef T type;
+ typedef T* ptrtype;
+ typedef T& reftype;
+};
+
+void is_function()
+{
+ int t01[T(__is_function(type_wrapper<void(void)>::type))];
+ int t02[T(__is_function(typeof(tmpl_func<int>)))];
+
+ typedef void (*ptr_to_func_type)(void);
+
+ int t10[F(__is_function(void))];
+ int t11[F(__is_function(cvoid))];
+ int t12[F(__is_function(float))];
+ int t13[F(__is_function(double))];
+ int t14[F(__is_function(long double))];
+ int t15[F(__is_function(bool))];
+ int t16[F(__is_function(char))];
+ int t17[F(__is_function(signed char))];
+ int t18[F(__is_function(unsigned char))];
+ int t19[F(__is_function(wchar_t))];
+ int t20[F(__is_function(short))];
+ int t21[F(__is_function(unsigned short))];
+ int t22[F(__is_function(int))];
+ int t23[F(__is_function(unsigned int))];
+ int t24[F(__is_function(long))];
+ int t25[F(__is_function(unsigned long))];
+ int t26[F(__is_function(Union))];
+ int t27[F(__is_function(Derives))];
+ int t28[F(__is_function(ClassType))];
+ int t29[F(__is_function(Enum))];
+ int t30[F(__is_function(void*))];
+ int t31[F(__is_function(cvoid*))];
+ int t32[F(__is_function(void(*)()))];
+ int t33[F(__is_function(ptr_to_func_type))];
+ int t34[F(__is_function(type_wrapper<void(void)>::ptrtype))];
+ int t35[F(__is_function(type_wrapper<void(void)>::reftype))];
+}
+
+void is_reference()
+{
+ int t01[T(__is_reference(int&))];
+ int t02[T(__is_reference(const int&))];
+ int t03[T(__is_reference(void *&))];
+
+ int t10[F(__is_reference(int))];
+ int t11[F(__is_reference(const int))];
+ int t12[F(__is_reference(void *))];
+}
+
+void is_lvalue_reference()
+{
+ int t01[T(__is_lvalue_reference(int&))];
+ int t02[T(__is_lvalue_reference(void *&))];
+ int t03[T(__is_lvalue_reference(const int&))];
+ int t04[T(__is_lvalue_reference(void * const &))];
+
+ int t10[F(__is_lvalue_reference(int))];
+ int t11[F(__is_lvalue_reference(const int))];
+ int t12[F(__is_lvalue_reference(void *))];
+}
+
+#if __has_feature(cxx_rvalue_references)
+
+void is_rvalue_reference()
+{
+ int t01[T(__is_rvalue_reference(const int&&))];
+ int t02[T(__is_rvalue_reference(void * const &&))];
+
+ int t10[F(__is_rvalue_reference(int&))];
+ int t11[F(__is_rvalue_reference(void *&))];
+ int t12[F(__is_rvalue_reference(const int&))];
+ int t13[F(__is_rvalue_reference(void * const &))];
+ int t14[F(__is_rvalue_reference(int))];
+ int t15[F(__is_rvalue_reference(const int))];
+ int t16[F(__is_rvalue_reference(void *))];
+}
+
+#endif
+
+void is_fundamental()
+{
+ int t01[T(__is_fundamental(float))];
+ int t02[T(__is_fundamental(double))];
+ int t03[T(__is_fundamental(long double))];
+ int t11[T(__is_fundamental(bool))];
+ int t12[T(__is_fundamental(char))];
+ int t13[T(__is_fundamental(signed char))];
+ int t14[T(__is_fundamental(unsigned char))];
+ //int t15[T(__is_fundamental(char16_t))];
+ //int t16[T(__is_fundamental(char32_t))];
+ int t17[T(__is_fundamental(wchar_t))];
+ int t18[T(__is_fundamental(short))];
+ int t19[T(__is_fundamental(unsigned short))];
+ int t20[T(__is_fundamental(int))];
+ int t21[T(__is_fundamental(unsigned int))];
+ int t22[T(__is_fundamental(long))];
+ int t23[T(__is_fundamental(unsigned long))];
+ int t24[T(__is_fundamental(void))];
+ int t25[T(__is_fundamental(cvoid))];
+
+ int t30[F(__is_fundamental(Union))];
+ int t31[F(__is_fundamental(UnionAr))];
+ int t32[F(__is_fundamental(Derives))];
+ int t33[F(__is_fundamental(ClassType))];
+ int t34[F(__is_fundamental(Enum))];
+ int t35[F(__is_fundamental(IntArNB))];
+}
+
+void is_object()
+{
+ int t01[T(__is_object(int))];
+ int t02[T(__is_object(int *))];
+ int t03[T(__is_object(void *))];
+ int t04[T(__is_object(Union))];
+ int t05[T(__is_object(UnionAr))];
+ int t06[T(__is_object(ClassType))];
+ int t07[T(__is_object(Enum))];
+
+ int t10[F(__is_object(type_wrapper<void(void)>::type))];
+ int t11[F(__is_object(int&))];
+ int t12[F(__is_object(void))];
+}
+
+void is_scalar()
+{
+ int t01[T(__is_scalar(float))];
+ int t02[T(__is_scalar(double))];
+ int t03[T(__is_scalar(long double))];
+ int t04[T(__is_scalar(bool))];
+ int t05[T(__is_scalar(char))];
+ int t06[T(__is_scalar(signed char))];
+ int t07[T(__is_scalar(unsigned char))];
+ int t08[T(__is_scalar(wchar_t))];
+ int t09[T(__is_scalar(short))];
+ int t10[T(__is_scalar(unsigned short))];
+ int t11[T(__is_scalar(int))];
+ int t12[T(__is_scalar(unsigned int))];
+ int t13[T(__is_scalar(long))];
+ int t14[T(__is_scalar(unsigned long))];
+ int t15[T(__is_scalar(Enum))];
+ int t16[T(__is_scalar(void*))];
+ int t17[T(__is_scalar(cvoid*))];
+
+ int t20[F(__is_scalar(void))];
+ int t21[F(__is_scalar(cvoid))];
+ int t22[F(__is_scalar(Union))];
+ int t23[F(__is_scalar(UnionAr))];
+ int t24[F(__is_scalar(Derives))];
+ int t25[F(__is_scalar(ClassType))];
+ int t26[F(__is_scalar(IntArNB))];
+}
+
+struct StructWithMembers {
+ int member;
+ void method() {}
+};
+
+void is_compound()
+{
+ int t01[T(__is_compound(void*))];
+ int t02[T(__is_compound(cvoid*))];
+ int t03[T(__is_compound(void (*)()))];
+ int t04[T(__is_compound(int StructWithMembers::*))];
+ int t05[T(__is_compound(void (StructWithMembers::*)()))];
+ int t06[T(__is_compound(int&))];
+ int t07[T(__is_compound(Union))];
+ int t08[T(__is_compound(UnionAr))];
+ int t09[T(__is_compound(Derives))];
+ int t10[T(__is_compound(ClassType))];
+ int t11[T(__is_compound(IntArNB))];
+ int t12[T(__is_compound(Enum))];
+
+ int t20[F(__is_compound(float))];
+ int t21[F(__is_compound(double))];
+ int t22[F(__is_compound(long double))];
+ int t23[F(__is_compound(bool))];
+ int t24[F(__is_compound(char))];
+ int t25[F(__is_compound(signed char))];
+ int t26[F(__is_compound(unsigned char))];
+ int t27[F(__is_compound(wchar_t))];
+ int t28[F(__is_compound(short))];
+ int t29[F(__is_compound(unsigned short))];
+ int t30[F(__is_compound(int))];
+ int t31[F(__is_compound(unsigned int))];
+ int t32[F(__is_compound(long))];
+ int t33[F(__is_compound(unsigned long))];
+ int t34[F(__is_compound(void))];
+ int t35[F(__is_compound(cvoid))];
+}
+
+void is_pointer()
+{
+ StructWithMembers x;
+
+ int t01[T(__is_pointer(void*))];
+ int t02[T(__is_pointer(cvoid*))];
+ int t03[T(__is_pointer(cvoid*))];
+ int t04[T(__is_pointer(char*))];
+ int t05[T(__is_pointer(int*))];
+ int t06[T(__is_pointer(int**))];
+ int t07[T(__is_pointer(ClassType*))];
+ int t08[T(__is_pointer(Derives*))];
+ int t09[T(__is_pointer(Enum*))];
+ int t10[T(__is_pointer(IntArNB*))];
+ int t11[T(__is_pointer(Union*))];
+ int t12[T(__is_pointer(UnionAr*))];
+ int t13[T(__is_pointer(StructWithMembers*))];
+ int t14[T(__is_pointer(void (*)()))];
+
+ int t20[F(__is_pointer(void))];
+ int t21[F(__is_pointer(cvoid))];
+ int t22[F(__is_pointer(cvoid))];
+ int t23[F(__is_pointer(char))];
+ int t24[F(__is_pointer(int))];
+ int t25[F(__is_pointer(int))];
+ int t26[F(__is_pointer(ClassType))];
+ int t27[F(__is_pointer(Derives))];
+ int t28[F(__is_pointer(Enum))];
+ int t29[F(__is_pointer(IntArNB))];
+ int t30[F(__is_pointer(Union))];
+ int t31[F(__is_pointer(UnionAr))];
+ int t32[F(__is_pointer(StructWithMembers))];
+ int t33[F(__is_pointer(int StructWithMembers::*))];
+ int t34[F(__is_pointer(void (StructWithMembers::*) ()))];
+}
+
+void is_member_object_pointer()
+{
+ StructWithMembers x;
+
+ int t01[T(__is_member_object_pointer(int StructWithMembers::*))];
+
+ int t10[F(__is_member_object_pointer(void (StructWithMembers::*) ()))];
+ int t11[F(__is_member_object_pointer(void*))];
+ int t12[F(__is_member_object_pointer(cvoid*))];
+ int t13[F(__is_member_object_pointer(cvoid*))];
+ int t14[F(__is_member_object_pointer(char*))];
+ int t15[F(__is_member_object_pointer(int*))];
+ int t16[F(__is_member_object_pointer(int**))];
+ int t17[F(__is_member_object_pointer(ClassType*))];
+ int t18[F(__is_member_object_pointer(Derives*))];
+ int t19[F(__is_member_object_pointer(Enum*))];
+ int t20[F(__is_member_object_pointer(IntArNB*))];
+ int t21[F(__is_member_object_pointer(Union*))];
+ int t22[F(__is_member_object_pointer(UnionAr*))];
+ int t23[F(__is_member_object_pointer(StructWithMembers*))];
+ int t24[F(__is_member_object_pointer(void))];
+ int t25[F(__is_member_object_pointer(cvoid))];
+ int t26[F(__is_member_object_pointer(cvoid))];
+ int t27[F(__is_member_object_pointer(char))];
+ int t28[F(__is_member_object_pointer(int))];
+ int t29[F(__is_member_object_pointer(int))];
+ int t30[F(__is_member_object_pointer(ClassType))];
+ int t31[F(__is_member_object_pointer(Derives))];
+ int t32[F(__is_member_object_pointer(Enum))];
+ int t33[F(__is_member_object_pointer(IntArNB))];
+ int t34[F(__is_member_object_pointer(Union))];
+ int t35[F(__is_member_object_pointer(UnionAr))];
+ int t36[F(__is_member_object_pointer(StructWithMembers))];
+ int t37[F(__is_member_object_pointer(void (*)()))];
+}
+
+void is_member_function_pointer()
+{
+ StructWithMembers x;
- int t11[F(__is_polymorphic(int))];
- int t12[F(__is_polymorphic(Union))];
- int t13[F(__is_polymorphic(Int))];
- int t14[F(__is_polymorphic(IntAr))];
- int t15[F(__is_polymorphic(UnionAr))];
- int t16[F(__is_polymorphic(Derives))];
- int t17[F(__is_polymorphic(ClassType))];
- int t18[F(__is_polymorphic(Enum))];
- int t19[F(__is_polymorphic(cvoid))];
- int t20[F(__is_polymorphic(IntArNB))];
+ int t01[T(__is_member_function_pointer(void (StructWithMembers::*) ()))];
+
+ int t10[F(__is_member_function_pointer(int StructWithMembers::*))];
+ int t11[F(__is_member_function_pointer(void*))];
+ int t12[F(__is_member_function_pointer(cvoid*))];
+ int t13[F(__is_member_function_pointer(cvoid*))];
+ int t14[F(__is_member_function_pointer(char*))];
+ int t15[F(__is_member_function_pointer(int*))];
+ int t16[F(__is_member_function_pointer(int**))];
+ int t17[F(__is_member_function_pointer(ClassType*))];
+ int t18[F(__is_member_function_pointer(Derives*))];
+ int t19[F(__is_member_function_pointer(Enum*))];
+ int t20[F(__is_member_function_pointer(IntArNB*))];
+ int t21[F(__is_member_function_pointer(Union*))];
+ int t22[F(__is_member_function_pointer(UnionAr*))];
+ int t23[F(__is_member_function_pointer(StructWithMembers*))];
+ int t24[F(__is_member_function_pointer(void))];
+ int t25[F(__is_member_function_pointer(cvoid))];
+ int t26[F(__is_member_function_pointer(cvoid))];
+ int t27[F(__is_member_function_pointer(char))];
+ int t28[F(__is_member_function_pointer(int))];
+ int t29[F(__is_member_function_pointer(int))];
+ int t30[F(__is_member_function_pointer(ClassType))];
+ int t31[F(__is_member_function_pointer(Derives))];
+ int t32[F(__is_member_function_pointer(Enum))];
+ int t33[F(__is_member_function_pointer(IntArNB))];
+ int t34[F(__is_member_function_pointer(Union))];
+ int t35[F(__is_member_function_pointer(UnionAr))];
+ int t36[F(__is_member_function_pointer(StructWithMembers))];
+ int t37[F(__is_member_function_pointer(void (*)()))];
+}
+
+void is_member_pointer()
+{
+ StructWithMembers x;
+
+ int t01[T(__is_member_pointer(int StructWithMembers::*))];
+ int t02[T(__is_member_pointer(void (StructWithMembers::*) ()))];
+
+ int t10[F(__is_member_pointer(void*))];
+ int t11[F(__is_member_pointer(cvoid*))];
+ int t12[F(__is_member_pointer(cvoid*))];
+ int t13[F(__is_member_pointer(char*))];
+ int t14[F(__is_member_pointer(int*))];
+ int t15[F(__is_member_pointer(int**))];
+ int t16[F(__is_member_pointer(ClassType*))];
+ int t17[F(__is_member_pointer(Derives*))];
+ int t18[F(__is_member_pointer(Enum*))];
+ int t19[F(__is_member_pointer(IntArNB*))];
+ int t20[F(__is_member_pointer(Union*))];
+ int t21[F(__is_member_pointer(UnionAr*))];
+ int t22[F(__is_member_pointer(StructWithMembers*))];
+ int t23[F(__is_member_pointer(void))];
+ int t24[F(__is_member_pointer(cvoid))];
+ int t25[F(__is_member_pointer(cvoid))];
+ int t26[F(__is_member_pointer(char))];
+ int t27[F(__is_member_pointer(int))];
+ int t28[F(__is_member_pointer(int))];
+ int t29[F(__is_member_pointer(ClassType))];
+ int t30[F(__is_member_pointer(Derives))];
+ int t31[F(__is_member_pointer(Enum))];
+ int t32[F(__is_member_pointer(IntArNB))];
+ int t33[F(__is_member_pointer(Union))];
+ int t34[F(__is_member_pointer(UnionAr))];
+ int t35[F(__is_member_pointer(StructWithMembers))];
+ int t36[F(__is_member_pointer(void (*)()))];
+}
+
+void is_const()
+{
+ int t01[T(__is_const(cvoid))];
+ int t02[T(__is_const(const char))];
+ int t03[T(__is_const(const int))];
+ int t04[T(__is_const(const long))];
+ int t05[T(__is_const(const short))];
+ int t06[T(__is_const(const signed char))];
+ int t07[T(__is_const(const wchar_t))];
+ int t08[T(__is_const(const bool))];
+ int t09[T(__is_const(const float))];
+ int t10[T(__is_const(const double))];
+ int t11[T(__is_const(const long double))];
+ int t12[T(__is_const(const unsigned char))];
+ int t13[T(__is_const(const unsigned int))];
+ int t14[T(__is_const(const unsigned long long))];
+ int t15[T(__is_const(const unsigned long))];
+ int t16[T(__is_const(const unsigned short))];
+ int t17[T(__is_const(const void))];
+ int t18[T(__is_const(const ClassType))];
+ int t19[T(__is_const(const Derives))];
+ int t20[T(__is_const(const Enum))];
+ int t21[T(__is_const(const IntArNB))];
+ int t22[T(__is_const(const Union))];
+ int t23[T(__is_const(const UnionAr))];
+
+ int t30[F(__is_const(char))];
+ int t31[F(__is_const(int))];
+ int t32[F(__is_const(long))];
+ int t33[F(__is_const(short))];
+ int t34[F(__is_const(signed char))];
+ int t35[F(__is_const(wchar_t))];
+ int t36[F(__is_const(bool))];
+ int t37[F(__is_const(float))];
+ int t38[F(__is_const(double))];
+ int t39[F(__is_const(long double))];
+ int t40[F(__is_const(unsigned char))];
+ int t41[F(__is_const(unsigned int))];
+ int t42[F(__is_const(unsigned long long))];
+ int t43[F(__is_const(unsigned long))];
+ int t44[F(__is_const(unsigned short))];
+ int t45[F(__is_const(void))];
+ int t46[F(__is_const(ClassType))];
+ int t47[F(__is_const(Derives))];
+ int t48[F(__is_const(Enum))];
+ int t49[F(__is_const(IntArNB))];
+ int t50[F(__is_const(Union))];
+ int t51[F(__is_const(UnionAr))];
+}
+
+void is_volatile()
+{
+ int t02[T(__is_volatile(volatile char))];
+ int t03[T(__is_volatile(volatile int))];
+ int t04[T(__is_volatile(volatile long))];
+ int t05[T(__is_volatile(volatile short))];
+ int t06[T(__is_volatile(volatile signed char))];
+ int t07[T(__is_volatile(volatile wchar_t))];
+ int t08[T(__is_volatile(volatile bool))];
+ int t09[T(__is_volatile(volatile float))];
+ int t10[T(__is_volatile(volatile double))];
+ int t11[T(__is_volatile(volatile long double))];
+ int t12[T(__is_volatile(volatile unsigned char))];
+ int t13[T(__is_volatile(volatile unsigned int))];
+ int t14[T(__is_volatile(volatile unsigned long long))];
+ int t15[T(__is_volatile(volatile unsigned long))];
+ int t16[T(__is_volatile(volatile unsigned short))];
+ int t17[T(__is_volatile(volatile void))];
+ int t18[T(__is_volatile(volatile ClassType))];
+ int t19[T(__is_volatile(volatile Derives))];
+ int t20[T(__is_volatile(volatile Enum))];
+ int t21[T(__is_volatile(volatile IntArNB))];
+ int t22[T(__is_volatile(volatile Union))];
+ int t23[T(__is_volatile(volatile UnionAr))];
+
+ int t30[F(__is_volatile(char))];
+ int t31[F(__is_volatile(int))];
+ int t32[F(__is_volatile(long))];
+ int t33[F(__is_volatile(short))];
+ int t34[F(__is_volatile(signed char))];
+ int t35[F(__is_volatile(wchar_t))];
+ int t36[F(__is_volatile(bool))];
+ int t37[F(__is_volatile(float))];
+ int t38[F(__is_volatile(double))];
+ int t39[F(__is_volatile(long double))];
+ int t40[F(__is_volatile(unsigned char))];
+ int t41[F(__is_volatile(unsigned int))];
+ int t42[F(__is_volatile(unsigned long long))];
+ int t43[F(__is_volatile(unsigned long))];
+ int t44[F(__is_volatile(unsigned short))];
+ int t45[F(__is_volatile(void))];
+ int t46[F(__is_volatile(ClassType))];
+ int t47[F(__is_volatile(Derives))];
+ int t48[F(__is_volatile(Enum))];
+ int t49[F(__is_volatile(IntArNB))];
+ int t50[F(__is_volatile(Union))];
+ int t51[F(__is_volatile(UnionAr))];
+}
+
+struct TrivialStruct {
+ int member;
+};
+
+struct NonTrivialStruct {
+ int member;
+ NonTrivialStruct() {
+ member = 0;
+ }
+};
+
+void is_trivial2()
+{
+ int t01[T(__is_trivial(char))];
+ int t02[T(__is_trivial(int))];
+ int t03[T(__is_trivial(long))];
+ int t04[T(__is_trivial(short))];
+ int t05[T(__is_trivial(signed char))];
+ int t06[T(__is_trivial(wchar_t))];
+ int t07[T(__is_trivial(bool))];
+ int t08[T(__is_trivial(float))];
+ int t09[T(__is_trivial(double))];
+ int t10[T(__is_trivial(long double))];
+ int t11[T(__is_trivial(unsigned char))];
+ int t12[T(__is_trivial(unsigned int))];
+ int t13[T(__is_trivial(unsigned long long))];
+ int t14[T(__is_trivial(unsigned long))];
+ int t15[T(__is_trivial(unsigned short))];
+ int t16[T(__is_trivial(ClassType))];
+ int t17[T(__is_trivial(Derives))];
+ int t18[T(__is_trivial(Enum))];
+ int t19[T(__is_trivial(IntAr))];
+ int t20[T(__is_trivial(Union))];
+ int t21[T(__is_trivial(UnionAr))];
+ int t22[T(__is_trivial(TrivialStruct))];
+
+ int t30[F(__is_trivial(void))];
+ int t31[F(__is_trivial(NonTrivialStruct))];
+}
+
+struct CStruct {
+ int one;
+ int two;
+};
+
+struct CEmptyStruct {};
+
+struct CppEmptyStruct : CStruct {};
+struct CppStructStandard : CEmptyStruct {
+ int three;
+ int four;
+};
+struct CppStructNonStandardByBase : CStruct {
+ int three;
+ int four;
+};
+struct CppStructNonStandardByVirt : CStruct {
+ virtual void method() {}
+};
+struct CppStructNonStandardByMemb : CStruct {
+ CppStructNonStandardByVirt member;
+};
+struct CppStructNonStandardByProt : CStruct {
+ int five;
+protected:
+ int six;
+};
+struct CppStructNonStandardByVirtBase : virtual CStruct {
+};
+struct CppStructNonStandardBySameBase : CEmptyStruct {
+ CEmptyStruct member;
+};
+struct CppStructNonStandardBy2ndVirtBase : CEmptyStruct {
+ CEmptyStruct member;
+};
+
+void is_standard_layout()
+{
+ typedef const int ConstInt;
+ typedef ConstInt ConstIntAr[4];
+ typedef CppStructStandard CppStructStandardAr[4];
+
+ int t01[T(__is_standard_layout(int))];
+ int t02[T(__is_standard_layout(ConstInt))];
+ int t03[T(__is_standard_layout(ConstIntAr))];
+ int t04[T(__is_standard_layout(CStruct))];
+ int t05[T(__is_standard_layout(CppStructStandard))];
+ int t06[T(__is_standard_layout(CppStructStandardAr))];
+ int t07[T(__is_standard_layout(Vector))];
+ int t08[T(__is_standard_layout(VectorExt))];
+
+ typedef CppStructNonStandardByBase CppStructNonStandardByBaseAr[4];
+
+ int t10[F(__is_standard_layout(CppStructNonStandardByVirt))];
+ int t11[F(__is_standard_layout(CppStructNonStandardByMemb))];
+ int t12[F(__is_standard_layout(CppStructNonStandardByProt))];
+ int t13[F(__is_standard_layout(CppStructNonStandardByVirtBase))];
+ int t14[F(__is_standard_layout(CppStructNonStandardByBase))];
+ int t15[F(__is_standard_layout(CppStructNonStandardByBaseAr))];
+ int t16[F(__is_standard_layout(CppStructNonStandardBySameBase))];
+ int t17[F(__is_standard_layout(CppStructNonStandardBy2ndVirtBase))];
+}
+
+void is_signed()
+{
+ //int t01[T(__is_signed(char))];
+ int t02[T(__is_signed(int))];
+ int t03[T(__is_signed(long))];
+ int t04[T(__is_signed(short))];
+ int t05[T(__is_signed(signed char))];
+ int t06[T(__is_signed(wchar_t))];
+
+ int t10[F(__is_signed(bool))];
+ int t11[F(__is_signed(cvoid))];
+ int t12[F(__is_signed(float))];
+ int t13[F(__is_signed(double))];
+ int t14[F(__is_signed(long double))];
+ int t15[F(__is_signed(unsigned char))];
+ int t16[F(__is_signed(unsigned int))];
+ int t17[F(__is_signed(unsigned long long))];
+ int t18[F(__is_signed(unsigned long))];
+ int t19[F(__is_signed(unsigned short))];
+ int t20[F(__is_signed(void))];
+ int t21[F(__is_signed(ClassType))];
+ int t22[F(__is_signed(Derives))];
+ int t23[F(__is_signed(Enum))];
+ int t24[F(__is_signed(IntArNB))];
+ int t25[F(__is_signed(Union))];
+ int t26[F(__is_signed(UnionAr))];
+}
+
+void is_unsigned()
+{
+ int t01[T(__is_unsigned(bool))];
+ int t02[T(__is_unsigned(unsigned char))];
+ int t03[T(__is_unsigned(unsigned short))];
+ int t04[T(__is_unsigned(unsigned int))];
+ int t05[T(__is_unsigned(unsigned long))];
+ int t06[T(__is_unsigned(unsigned long long))];
+ int t07[T(__is_unsigned(Enum))];
+
+ int t10[F(__is_unsigned(void))];
+ int t11[F(__is_unsigned(cvoid))];
+ int t12[F(__is_unsigned(float))];
+ int t13[F(__is_unsigned(double))];
+ int t14[F(__is_unsigned(long double))];
+ int t16[F(__is_unsigned(char))];
+ int t17[F(__is_unsigned(signed char))];
+ int t18[F(__is_unsigned(wchar_t))];
+ int t19[F(__is_unsigned(short))];
+ int t20[F(__is_unsigned(int))];
+ int t21[F(__is_unsigned(long))];
+ int t22[F(__is_unsigned(Union))];
+ int t23[F(__is_unsigned(UnionAr))];
+ int t24[F(__is_unsigned(Derives))];
+ int t25[F(__is_unsigned(ClassType))];
+ int t26[F(__is_unsigned(IntArNB))];
}
typedef Int& IntRef;
@@ -227,6 +1026,10 @@ struct HasCopy {
HasCopy(HasCopy& cp);
};
+struct HasMove {
+ HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
+};
+
struct HasTemplateCons {
HasVirt Annoying;
@@ -235,216 +1038,235 @@ struct HasTemplateCons {
};
void has_trivial_default_constructor() {
- int t01[T(__has_trivial_constructor(Int))];
- int t02[T(__has_trivial_constructor(IntAr))];
- int t03[T(__has_trivial_constructor(Union))];
- int t04[T(__has_trivial_constructor(UnionAr))];
- int t05[T(__has_trivial_constructor(POD))];
- int t06[T(__has_trivial_constructor(Derives))];
- int t07[T(__has_trivial_constructor(ConstIntAr))];
- int t08[T(__has_trivial_constructor(ConstIntArAr))];
- int t09[T(__has_trivial_constructor(HasDest))];
- int t10[T(__has_trivial_constructor(HasPriv))];
- int t11[F(__has_trivial_constructor(HasCons))];
- int t12[F(__has_trivial_constructor(HasRef))];
- int t13[F(__has_trivial_constructor(HasCopy))];
- int t14[F(__has_trivial_constructor(IntRef))];
- int t15[T(__has_trivial_constructor(HasCopyAssign))];
- int t16[T(__has_trivial_constructor(const Int))];
- int t17[T(__has_trivial_constructor(NonPODAr))];
- int t18[F(__has_trivial_constructor(VirtAr))];
- int t19[F(__has_trivial_constructor(void))];
- int t20[F(__has_trivial_constructor(cvoid))];
- int t21[F(__has_trivial_constructor(HasTemplateCons))];
+ { int arr[T(__has_trivial_constructor(Int))]; }
+ { int arr[T(__has_trivial_constructor(IntAr))]; }
+ { int arr[T(__has_trivial_constructor(Union))]; }
+ { int arr[T(__has_trivial_constructor(UnionAr))]; }
+ { int arr[T(__has_trivial_constructor(POD))]; }
+ { int arr[T(__has_trivial_constructor(Derives))]; }
+ { int arr[T(__has_trivial_constructor(DerivesAr))]; }
+ { int arr[T(__has_trivial_constructor(ConstIntAr))]; }
+ { int arr[T(__has_trivial_constructor(ConstIntArAr))]; }
+ { int arr[T(__has_trivial_constructor(HasDest))]; }
+ { int arr[T(__has_trivial_constructor(HasPriv))]; }
+ { int arr[T(__has_trivial_constructor(HasCopyAssign))]; }
+ { int arr[T(__has_trivial_constructor(HasMoveAssign))]; }
+ { int arr[T(__has_trivial_constructor(const Int))]; }
+
+ { int arr[F(__has_trivial_constructor(HasCons))]; }
+ { int arr[F(__has_trivial_constructor(HasRef))]; }
+ { int arr[F(__has_trivial_constructor(HasCopy))]; }
+ { int arr[F(__has_trivial_constructor(IntRef))]; }
+ { int arr[F(__has_trivial_constructor(VirtAr))]; }
+ { int arr[F(__has_trivial_constructor(void))]; }
+ { int arr[F(__has_trivial_constructor(cvoid))]; }
+ { int arr[F(__has_trivial_constructor(HasTemplateCons))]; }
}
void has_trivial_copy_constructor() {
- int t01[T(__has_trivial_copy(Int))];
- int t02[T(__has_trivial_copy(IntAr))];
- int t03[T(__has_trivial_copy(Union))];
- int t04[T(__has_trivial_copy(UnionAr))];
- int t05[T(__has_trivial_copy(POD))];
- int t06[T(__has_trivial_copy(Derives))];
- int t07[T(__has_trivial_copy(ConstIntAr))];
- int t08[T(__has_trivial_copy(ConstIntArAr))];
- int t09[T(__has_trivial_copy(HasDest))];
- int t10[T(__has_trivial_copy(HasPriv))];
- int t11[T(__has_trivial_copy(HasCons))];
- int t12[T(__has_trivial_copy(HasRef))];
- int t13[F(__has_trivial_copy(HasCopy))];
- int t14[T(__has_trivial_copy(IntRef))];
- int t15[T(__has_trivial_copy(HasCopyAssign))];
- int t16[T(__has_trivial_copy(const Int))];
- int t17[F(__has_trivial_copy(NonPODAr))];
- int t18[F(__has_trivial_copy(VirtAr))];
- int t19[F(__has_trivial_copy(void))];
- int t20[F(__has_trivial_copy(cvoid))];
- int t21[F(__has_trivial_copy(HasTemplateCons))];
+ { int arr[T(__has_trivial_copy(Int))]; }
+ { int arr[T(__has_trivial_copy(IntAr))]; }
+ { int arr[T(__has_trivial_copy(Union))]; }
+ { int arr[T(__has_trivial_copy(UnionAr))]; }
+ { int arr[T(__has_trivial_copy(POD))]; }
+ { int arr[T(__has_trivial_copy(Derives))]; }
+ { int arr[T(__has_trivial_copy(ConstIntAr))]; }
+ { int arr[T(__has_trivial_copy(ConstIntArAr))]; }
+ { int arr[T(__has_trivial_copy(HasDest))]; }
+ { int arr[T(__has_trivial_copy(HasPriv))]; }
+ { int arr[T(__has_trivial_copy(HasCons))]; }
+ { int arr[T(__has_trivial_copy(HasRef))]; }
+ { int arr[T(__has_trivial_copy(HasMove))]; }
+ { int arr[T(__has_trivial_copy(IntRef))]; }
+ { int arr[T(__has_trivial_copy(HasCopyAssign))]; }
+ { int arr[T(__has_trivial_copy(HasMoveAssign))]; }
+ { int arr[T(__has_trivial_copy(const Int))]; }
+
+ { int arr[F(__has_trivial_copy(HasCopy))]; }
+ { int arr[F(__has_trivial_copy(HasTemplateCons))]; }
+ { int arr[F(__has_trivial_copy(DerivesAr))]; }
+ { int arr[F(__has_trivial_copy(VirtAr))]; }
+ { int arr[F(__has_trivial_copy(void))]; }
+ { int arr[F(__has_trivial_copy(cvoid))]; }
}
void has_trivial_copy_assignment() {
- int t01[T(__has_trivial_assign(Int))];
- int t02[T(__has_trivial_assign(IntAr))];
- int t03[T(__has_trivial_assign(Union))];
- int t04[T(__has_trivial_assign(UnionAr))];
- int t05[T(__has_trivial_assign(POD))];
- int t06[T(__has_trivial_assign(Derives))];
- int t07[F(__has_trivial_assign(ConstIntAr))];
- int t08[F(__has_trivial_assign(ConstIntArAr))];
- int t09[T(__has_trivial_assign(HasDest))];
- int t10[T(__has_trivial_assign(HasPriv))];
- int t11[T(__has_trivial_assign(HasCons))];
- int t12[T(__has_trivial_assign(HasRef))];
- int t13[T(__has_trivial_assign(HasCopy))];
- int t14[F(__has_trivial_assign(IntRef))];
- int t15[F(__has_trivial_assign(HasCopyAssign))];
- int t16[F(__has_trivial_assign(const Int))];
- int t17[F(__has_trivial_assign(NonPODAr))];
- int t18[F(__has_trivial_assign(VirtAr))];
- int t19[F(__has_trivial_assign(void))];
- int t20[F(__has_trivial_assign(cvoid))];
+ { int arr[T(__has_trivial_assign(Int))]; }
+ { int arr[T(__has_trivial_assign(IntAr))]; }
+ { int arr[T(__has_trivial_assign(Union))]; }
+ { int arr[T(__has_trivial_assign(UnionAr))]; }
+ { int arr[T(__has_trivial_assign(POD))]; }
+ { int arr[T(__has_trivial_assign(Derives))]; }
+ { int arr[T(__has_trivial_assign(HasDest))]; }
+ { int arr[T(__has_trivial_assign(HasPriv))]; }
+ { int arr[T(__has_trivial_assign(HasCons))]; }
+ { int arr[T(__has_trivial_assign(HasRef))]; }
+ { int arr[T(__has_trivial_assign(HasCopy))]; }
+ { int arr[T(__has_trivial_assign(HasMove))]; }
+ { int arr[T(__has_trivial_assign(HasMoveAssign))]; }
+
+ { int arr[F(__has_trivial_assign(IntRef))]; }
+ { int arr[F(__has_trivial_assign(HasCopyAssign))]; }
+ { int arr[F(__has_trivial_assign(const Int))]; }
+ { int arr[F(__has_trivial_assign(ConstIntAr))]; }
+ { int arr[F(__has_trivial_assign(ConstIntArAr))]; }
+ { int arr[F(__has_trivial_assign(DerivesAr))]; }
+ { int arr[F(__has_trivial_assign(VirtAr))]; }
+ { int arr[F(__has_trivial_assign(void))]; }
+ { int arr[F(__has_trivial_assign(cvoid))]; }
}
void has_trivial_destructor() {
- int t01[T(__has_trivial_destructor(Int))];
- int t02[T(__has_trivial_destructor(IntAr))];
- int t03[T(__has_trivial_destructor(Union))];
- int t04[T(__has_trivial_destructor(UnionAr))];
- int t05[T(__has_trivial_destructor(POD))];
- int t06[T(__has_trivial_destructor(Derives))];
- int t07[T(__has_trivial_destructor(ConstIntAr))];
- int t08[T(__has_trivial_destructor(ConstIntArAr))];
- int t09[F(__has_trivial_destructor(HasDest))];
- int t10[T(__has_trivial_destructor(HasPriv))];
- int t11[T(__has_trivial_destructor(HasCons))];
- int t12[T(__has_trivial_destructor(HasRef))];
- int t13[T(__has_trivial_destructor(HasCopy))];
- int t14[T(__has_trivial_destructor(IntRef))];
- int t15[T(__has_trivial_destructor(HasCopyAssign))];
- int t16[T(__has_trivial_destructor(const Int))];
- int t17[T(__has_trivial_destructor(NonPODAr))];
- int t18[T(__has_trivial_destructor(VirtAr))];
- int t19[F(__has_trivial_destructor(void))];
- int t20[F(__has_trivial_destructor(cvoid))];
+ { int arr[T(__has_trivial_destructor(Int))]; }
+ { int arr[T(__has_trivial_destructor(IntAr))]; }
+ { int arr[T(__has_trivial_destructor(Union))]; }
+ { int arr[T(__has_trivial_destructor(UnionAr))]; }
+ { int arr[T(__has_trivial_destructor(POD))]; }
+ { int arr[T(__has_trivial_destructor(Derives))]; }
+ { int arr[T(__has_trivial_destructor(ConstIntAr))]; }
+ { int arr[T(__has_trivial_destructor(ConstIntArAr))]; }
+ { int arr[T(__has_trivial_destructor(HasPriv))]; }
+ { int arr[T(__has_trivial_destructor(HasCons))]; }
+ { int arr[T(__has_trivial_destructor(HasRef))]; }
+ { int arr[T(__has_trivial_destructor(HasCopy))]; }
+ { int arr[T(__has_trivial_destructor(HasMove))]; }
+ { int arr[T(__has_trivial_destructor(IntRef))]; }
+ { int arr[T(__has_trivial_destructor(HasCopyAssign))]; }
+ { int arr[T(__has_trivial_destructor(HasMoveAssign))]; }
+ { int arr[T(__has_trivial_destructor(const Int))]; }
+ { int arr[T(__has_trivial_destructor(DerivesAr))]; }
+ { int arr[T(__has_trivial_destructor(VirtAr))]; }
+
+ { int arr[F(__has_trivial_destructor(HasDest))]; }
+ { int arr[F(__has_trivial_destructor(void))]; }
+ { int arr[F(__has_trivial_destructor(cvoid))]; }
}
struct A { ~A() {} };
template<typename> struct B : A { };
void f() {
- int t01[F(__has_trivial_destructor(A))];
- int t02[F(__has_trivial_destructor(B<int>))];
+ { int arr[F(__has_trivial_destructor(A))]; }
+ { int arr[F(__has_trivial_destructor(B<int>))]; }
}
void has_nothrow_assign() {
- int t01[T(__has_nothrow_assign(Int))];
- int t02[T(__has_nothrow_assign(IntAr))];
- int t03[T(__has_nothrow_assign(Union))];
- int t04[T(__has_nothrow_assign(UnionAr))];
- int t05[T(__has_nothrow_assign(POD))];
- int t06[T(__has_nothrow_assign(Derives))];
- int t07[F(__has_nothrow_assign(ConstIntAr))];
- int t08[F(__has_nothrow_assign(ConstIntArAr))];
- int t09[T(__has_nothrow_assign(HasDest))];
- int t10[T(__has_nothrow_assign(HasPriv))];
- int t11[T(__has_nothrow_assign(HasCons))];
- int t12[T(__has_nothrow_assign(HasRef))];
- int t13[T(__has_nothrow_assign(HasCopy))];
- int t14[F(__has_nothrow_assign(IntRef))];
- int t15[F(__has_nothrow_assign(HasCopyAssign))];
- int t16[F(__has_nothrow_assign(const Int))];
- int t17[F(__has_nothrow_assign(NonPODAr))];
- int t18[F(__has_nothrow_assign(VirtAr))];
- int t19[T(__has_nothrow_assign(HasNoThrowCopyAssign))];
- int t20[F(__has_nothrow_assign(HasMultipleCopyAssign))];
- int t21[T(__has_nothrow_assign(HasMultipleNoThrowCopyAssign))];
- int t22[F(__has_nothrow_assign(void))];
- int t23[F(__has_nothrow_assign(cvoid))];
- int t24[T(__has_nothrow_assign(HasVirtDest))];
+ { int arr[T(__has_nothrow_assign(Int))]; }
+ { int arr[T(__has_nothrow_assign(IntAr))]; }
+ { int arr[T(__has_nothrow_assign(Union))]; }
+ { int arr[T(__has_nothrow_assign(UnionAr))]; }
+ { int arr[T(__has_nothrow_assign(POD))]; }
+ { int arr[T(__has_nothrow_assign(Derives))]; }
+ { int arr[T(__has_nothrow_assign(HasDest))]; }
+ { int arr[T(__has_nothrow_assign(HasPriv))]; }
+ { int arr[T(__has_nothrow_assign(HasCons))]; }
+ { int arr[T(__has_nothrow_assign(HasRef))]; }
+ { int arr[T(__has_nothrow_assign(HasCopy))]; }
+ { int arr[T(__has_nothrow_assign(HasMove))]; }
+ { int arr[T(__has_nothrow_assign(HasMoveAssign))]; }
+ { int arr[T(__has_nothrow_assign(HasNoThrowCopyAssign))]; }
+ { int arr[T(__has_nothrow_assign(HasMultipleNoThrowCopyAssign))]; }
+ { int arr[T(__has_nothrow_assign(HasVirtDest))]; }
+
+ { int arr[F(__has_nothrow_assign(IntRef))]; }
+ { int arr[F(__has_nothrow_assign(HasCopyAssign))]; }
+ { int arr[F(__has_nothrow_assign(HasMultipleCopyAssign))]; }
+ { int arr[F(__has_nothrow_assign(const Int))]; }
+ { int arr[F(__has_nothrow_assign(ConstIntAr))]; }
+ { int arr[F(__has_nothrow_assign(ConstIntArAr))]; }
+ { int arr[F(__has_nothrow_assign(DerivesAr))]; }
+ { int arr[F(__has_nothrow_assign(VirtAr))]; }
+ { int arr[F(__has_nothrow_assign(void))]; }
+ { int arr[F(__has_nothrow_assign(cvoid))]; }
}
void has_nothrow_copy() {
- int t01[T(__has_nothrow_copy(Int))];
- int t02[T(__has_nothrow_copy(IntAr))];
- int t03[T(__has_nothrow_copy(Union))];
- int t04[T(__has_nothrow_copy(UnionAr))];
- int t05[T(__has_nothrow_copy(POD))];
- int t06[T(__has_nothrow_copy(Derives))];
- int t07[T(__has_nothrow_copy(ConstIntAr))];
- int t08[T(__has_nothrow_copy(ConstIntArAr))];
- int t09[T(__has_nothrow_copy(HasDest))];
- int t10[T(__has_nothrow_copy(HasPriv))];
- int t11[T(__has_nothrow_copy(HasCons))];
- int t12[T(__has_nothrow_copy(HasRef))];
- int t13[F(__has_nothrow_copy(HasCopy))];
- int t14[T(__has_nothrow_copy(IntRef))];
- int t15[T(__has_nothrow_copy(HasCopyAssign))];
- int t16[T(__has_nothrow_copy(const Int))];
- int t17[F(__has_nothrow_copy(NonPODAr))];
- int t18[F(__has_nothrow_copy(VirtAr))];
-
- int t19[T(__has_nothrow_copy(HasNoThrowCopy))];
- int t20[F(__has_nothrow_copy(HasMultipleCopy))];
- int t21[T(__has_nothrow_copy(HasMultipleNoThrowCopy))];
- int t22[F(__has_nothrow_copy(void))];
- int t23[F(__has_nothrow_copy(cvoid))];
- int t24[T(__has_nothrow_copy(HasVirtDest))];
- int t25[T(__has_nothrow_copy(HasTemplateCons))];
+ { int arr[T(__has_nothrow_copy(Int))]; }
+ { int arr[T(__has_nothrow_copy(IntAr))]; }
+ { int arr[T(__has_nothrow_copy(Union))]; }
+ { int arr[T(__has_nothrow_copy(UnionAr))]; }
+ { int arr[T(__has_nothrow_copy(POD))]; }
+ { int arr[T(__has_nothrow_copy(const Int))]; }
+ { int arr[T(__has_nothrow_copy(ConstIntAr))]; }
+ { int arr[T(__has_nothrow_copy(ConstIntArAr))]; }
+ { int arr[T(__has_nothrow_copy(Derives))]; }
+ { int arr[T(__has_nothrow_copy(IntRef))]; }
+ { int arr[T(__has_nothrow_copy(HasDest))]; }
+ { int arr[T(__has_nothrow_copy(HasPriv))]; }
+ { int arr[T(__has_nothrow_copy(HasCons))]; }
+ { int arr[T(__has_nothrow_copy(HasRef))]; }
+ { int arr[T(__has_nothrow_copy(HasMove))]; }
+ { int arr[T(__has_nothrow_copy(HasCopyAssign))]; }
+ { int arr[T(__has_nothrow_copy(HasMoveAssign))]; }
+ { int arr[T(__has_nothrow_copy(HasNoThrowCopy))]; }
+ { int arr[T(__has_nothrow_copy(HasMultipleNoThrowCopy))]; }
+ { int arr[T(__has_nothrow_copy(HasVirtDest))]; }
+ { int arr[T(__has_nothrow_copy(HasTemplateCons))]; }
+
+ { int arr[F(__has_nothrow_copy(HasCopy))]; }
+ { int arr[F(__has_nothrow_copy(HasMultipleCopy))]; }
+ { int arr[F(__has_nothrow_copy(DerivesAr))]; }
+ { int arr[F(__has_nothrow_copy(VirtAr))]; }
+ { int arr[F(__has_nothrow_copy(void))]; }
+ { int arr[F(__has_nothrow_copy(cvoid))]; }
}
void has_nothrow_constructor() {
- int t01[T(__has_nothrow_constructor(Int))];
- int t02[T(__has_nothrow_constructor(IntAr))];
- int t03[T(__has_nothrow_constructor(Union))];
- int t04[T(__has_nothrow_constructor(UnionAr))];
- int t05[T(__has_nothrow_constructor(POD))];
- int t06[T(__has_nothrow_constructor(Derives))];
- int t07[T(__has_nothrow_constructor(ConstIntAr))];
- int t08[T(__has_nothrow_constructor(ConstIntArAr))];
- int t09[T(__has_nothrow_constructor(HasDest))];
- int t10[T(__has_nothrow_constructor(HasPriv))];
- int t11[F(__has_nothrow_constructor(HasCons))];
- int t12[F(__has_nothrow_constructor(HasRef))];
- int t13[F(__has_nothrow_constructor(HasCopy))];
- int t14[F(__has_nothrow_constructor(IntRef))];
- int t15[T(__has_nothrow_constructor(HasCopyAssign))];
- int t16[T(__has_nothrow_constructor(const Int))];
- int t17[T(__has_nothrow_constructor(NonPODAr))];
- // int t18[T(__has_nothrow_constructor(VirtAr))]; // not implemented
-
- int t19[T(__has_nothrow_constructor(HasNoThrowConstructor))];
- int t20[F(__has_nothrow_constructor(HasNoThrowConstructorWithArgs))];
- int t21[F(__has_nothrow_constructor(void))];
- int t22[F(__has_nothrow_constructor(cvoid))];
- int t23[T(__has_nothrow_constructor(HasVirtDest))];
- int t24[F(__has_nothrow_constructor(HasTemplateCons))];
+ { int arr[T(__has_nothrow_constructor(Int))]; }
+ { int arr[T(__has_nothrow_constructor(IntAr))]; }
+ { int arr[T(__has_nothrow_constructor(Union))]; }
+ { int arr[T(__has_nothrow_constructor(UnionAr))]; }
+ { int arr[T(__has_nothrow_constructor(POD))]; }
+ { int arr[T(__has_nothrow_constructor(Derives))]; }
+ { int arr[T(__has_nothrow_constructor(DerivesAr))]; }
+ { int arr[T(__has_nothrow_constructor(ConstIntAr))]; }
+ { int arr[T(__has_nothrow_constructor(ConstIntArAr))]; }
+ { int arr[T(__has_nothrow_constructor(HasDest))]; }
+ { int arr[T(__has_nothrow_constructor(HasPriv))]; }
+ { int arr[T(__has_nothrow_constructor(HasCopyAssign))]; }
+ { int arr[T(__has_nothrow_constructor(const Int))]; }
+ { int arr[T(__has_nothrow_constructor(HasNoThrowConstructor))]; }
+ { int arr[T(__has_nothrow_constructor(HasVirtDest))]; }
+ // { int arr[T(__has_nothrow_constructor(VirtAr))]; } // not implemented
+
+ { int arr[F(__has_nothrow_constructor(HasCons))]; }
+ { int arr[F(__has_nothrow_constructor(HasRef))]; }
+ { int arr[F(__has_nothrow_constructor(HasCopy))]; }
+ { int arr[F(__has_nothrow_constructor(HasMove))]; }
+ { int arr[F(__has_nothrow_constructor(HasNoThrowConstructorWithArgs))]; }
+ { int arr[F(__has_nothrow_constructor(IntRef))]; }
+ { int arr[F(__has_nothrow_constructor(void))]; }
+ { int arr[F(__has_nothrow_constructor(cvoid))]; }
+ { int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
}
void has_virtual_destructor() {
- int t01[F(__has_virtual_destructor(Int))];
- int t02[F(__has_virtual_destructor(IntAr))];
- int t03[F(__has_virtual_destructor(Union))];
- int t04[F(__has_virtual_destructor(UnionAr))];
- int t05[F(__has_virtual_destructor(POD))];
- int t06[F(__has_virtual_destructor(Derives))];
- int t07[F(__has_virtual_destructor(ConstIntAr))];
- int t08[F(__has_virtual_destructor(ConstIntArAr))];
- int t09[F(__has_virtual_destructor(HasDest))];
- int t10[F(__has_virtual_destructor(HasPriv))];
- int t11[F(__has_virtual_destructor(HasCons))];
- int t12[F(__has_virtual_destructor(HasRef))];
- int t13[F(__has_virtual_destructor(HasCopy))];
- int t14[F(__has_virtual_destructor(IntRef))];
- int t15[F(__has_virtual_destructor(HasCopyAssign))];
- int t16[F(__has_virtual_destructor(const Int))];
- int t17[F(__has_virtual_destructor(NonPODAr))];
- int t18[F(__has_virtual_destructor(VirtAr))];
-
- int t19[T(__has_virtual_destructor(HasVirtDest))];
- int t20[T(__has_virtual_destructor(DerivedVirtDest))];
- int t21[F(__has_virtual_destructor(VirtDestAr))];
- int t22[F(__has_virtual_destructor(void))];
- int t23[F(__has_virtual_destructor(cvoid))];
+ { int arr[F(__has_virtual_destructor(Int))]; }
+ { int arr[F(__has_virtual_destructor(IntAr))]; }
+ { int arr[F(__has_virtual_destructor(Union))]; }
+ { int arr[F(__has_virtual_destructor(UnionAr))]; }
+ { int arr[F(__has_virtual_destructor(POD))]; }
+ { int arr[F(__has_virtual_destructor(Derives))]; }
+ { int arr[F(__has_virtual_destructor(DerivesAr))]; }
+ { int arr[F(__has_virtual_destructor(const Int))]; }
+ { int arr[F(__has_virtual_destructor(ConstIntAr))]; }
+ { int arr[F(__has_virtual_destructor(ConstIntArAr))]; }
+ { int arr[F(__has_virtual_destructor(HasDest))]; }
+ { int arr[F(__has_virtual_destructor(HasPriv))]; }
+ { int arr[F(__has_virtual_destructor(HasCons))]; }
+ { int arr[F(__has_virtual_destructor(HasRef))]; }
+ { int arr[F(__has_virtual_destructor(HasCopy))]; }
+ { int arr[F(__has_virtual_destructor(HasMove))]; }
+ { int arr[F(__has_virtual_destructor(HasCopyAssign))]; }
+ { int arr[F(__has_virtual_destructor(HasMoveAssign))]; }
+ { int arr[F(__has_virtual_destructor(IntRef))]; }
+ { int arr[F(__has_virtual_destructor(VirtAr))]; }
+
+ { int arr[T(__has_virtual_destructor(HasVirtDest))]; }
+ { int arr[T(__has_virtual_destructor(DerivedVirtDest))]; }
+ { int arr[F(__has_virtual_destructor(VirtDestAr))]; }
+ { int arr[F(__has_virtual_destructor(void))]; }
+ { int arr[F(__has_virtual_destructor(cvoid))]; }
}
@@ -474,29 +1296,29 @@ template <class T> class NonderivedTemp {};
template <class T> class UndefinedTemp; // expected-note {{declared here}}
void is_base_of() {
- int t01[T(__is_base_of(Base, Derived))];
- int t02[T(__is_base_of(const Base, Derived))];
- int t03[F(__is_base_of(Derived, Base))];
- int t04[F(__is_base_of(Derived, int))];
- int t05[T(__is_base_of(Base, Base))];
- int t06[T(__is_base_of(Base, Derived3))];
- int t07[T(__is_base_of(Derived, Derived3))];
- int t08[T(__is_base_of(Derived2b, Derived3))];
- int t09[T(__is_base_of(Derived2a, Derived3))];
- int t10[T(__is_base_of(BaseA<int>, DerivedB<int>))];
- int t11[F(__is_base_of(DerivedB<int>, BaseA<int>))];
- int t12[T(__is_base_of(Base, CrazyDerived<Base>))];
- int t13[F(__is_base_of(Union, Union))];
- int t14[T(__is_base_of(Empty, Empty))];
- int t15[T(__is_base_of(class_forward, class_forward))];
- int t16[F(__is_base_of(Empty, class_forward))]; // expected-error {{incomplete type 'class_forward' used in type trait expression}}
- int t17[F(__is_base_of(Base&, Derived&))];
+ { int arr[T(__is_base_of(Base, Derived))]; }
+ { int arr[T(__is_base_of(const Base, Derived))]; }
+ { int arr[F(__is_base_of(Derived, Base))]; }
+ { int arr[F(__is_base_of(Derived, int))]; }
+ { int arr[T(__is_base_of(Base, Base))]; }
+ { int arr[T(__is_base_of(Base, Derived3))]; }
+ { int arr[T(__is_base_of(Derived, Derived3))]; }
+ { int arr[T(__is_base_of(Derived2b, Derived3))]; }
+ { int arr[T(__is_base_of(Derived2a, Derived3))]; }
+ { int arr[T(__is_base_of(BaseA<int>, DerivedB<int>))]; }
+ { int arr[F(__is_base_of(DerivedB<int>, BaseA<int>))]; }
+ { int arr[T(__is_base_of(Base, CrazyDerived<Base>))]; }
+ { int arr[F(__is_base_of(Union, Union))]; }
+ { int arr[T(__is_base_of(Empty, Empty))]; }
+ { int arr[T(__is_base_of(class_forward, class_forward))]; }
+ { int arr[F(__is_base_of(Empty, class_forward))]; } // expected-error {{incomplete type 'class_forward' used in type trait expression}}
+ { int arr[F(__is_base_of(Base&, Derived&))]; }
int t18[F(__is_base_of(Base[10], Derived[10]))];
- int t19[F(__is_base_of(int, int))];
- int t20[F(__is_base_of(long, int))];
- int t21[T(__is_base_of(Base, DerivedTemp<int>))];
- int t22[F(__is_base_of(Base, NonderivedTemp<int>))];
- int t23[F(__is_base_of(Base, UndefinedTemp<int>))]; // expected-error {{implicit instantiation of undefined template 'UndefinedTemp<int>'}}
+ { int arr[F(__is_base_of(int, int))]; }
+ { int arr[F(__is_base_of(long, int))]; }
+ { int arr[T(__is_base_of(Base, DerivedTemp<int>))]; }
+ { int arr[F(__is_base_of(Base, NonderivedTemp<int>))]; }
+ { int arr[F(__is_base_of(Base, UndefinedTemp<int>))]; } // expected-error {{implicit instantiation of undefined template 'UndefinedTemp<int>'}}
isBaseOfT<Base, Derived>();
isBaseOfF<Derived, Base>();
@@ -508,6 +1330,64 @@ void is_base_of() {
isBaseOfF<DerivedB<int>, BaseA<int> >();
}
+#if 0
+template<class T, class U>
+class TemplateClass {};
+
+template<class T>
+using TemplateAlias = TemplateClass<T, int>;
+#endif
+
+typedef class Base BaseTypedef;
+
+void is_same()
+{
+ int t01[T(__is_same(Base, Base))];
+ int t02[T(__is_same(Base, BaseTypedef))];
+#if 0
+ int t03[T(__is_same(TemplateClass<int, int>, TemplateAlias<int>))];
+#endif
+
+ int t10[F(__is_same(Base, const Base))];
+ int t11[F(__is_same(Base, Base&))];
+ int t12[F(__is_same(Base, Derived))];
+}
+
+struct IntWrapper
+{
+ int value;
+ IntWrapper(int _value) : value(_value) {}
+ operator int() const {
+ return value;
+ }
+};
+
+struct FloatWrapper
+{
+ float value;
+ FloatWrapper(float _value) : value(_value) {}
+ FloatWrapper(const IntWrapper& obj)
+ : value(static_cast<float>(obj.value)) {}
+ operator float() const {
+ return value;
+ }
+ operator IntWrapper() const {
+ return IntWrapper(static_cast<int>(value));
+ }
+};
+
+void is_convertible()
+{
+ int t01[T(__is_convertible(IntWrapper, IntWrapper))];
+ int t02[T(__is_convertible(IntWrapper, const IntWrapper))];
+ int t03[T(__is_convertible(IntWrapper, int))];
+ int t04[T(__is_convertible(int, IntWrapper))];
+ int t05[T(__is_convertible(IntWrapper, FloatWrapper))];
+ int t06[T(__is_convertible(FloatWrapper, IntWrapper))];
+ int t07[T(__is_convertible(FloatWrapper, float))];
+ int t08[T(__is_convertible(float, FloatWrapper))];
+}
+
struct FromInt { FromInt(int); };
struct ToInt { operator int(); };
typedef void Function();
@@ -524,27 +1404,83 @@ struct X0 {
};
void is_convertible_to() {
- int t01[T(__is_convertible_to(Int, Int))];
- int t02[F(__is_convertible_to(Int, IntAr))];
- int t03[F(__is_convertible_to(IntAr, IntAr))];
- int t04[T(__is_convertible_to(void, void))];
- int t05[T(__is_convertible_to(cvoid, void))];
- int t06[T(__is_convertible_to(void, cvoid))];
- int t07[T(__is_convertible_to(cvoid, cvoid))];
- int t08[T(__is_convertible_to(int, FromInt))];
- int t09[T(__is_convertible_to(long, FromInt))];
- int t10[T(__is_convertible_to(double, FromInt))];
- int t11[T(__is_convertible_to(const int, FromInt))];
- int t12[T(__is_convertible_to(const int&, FromInt))];
- int t13[T(__is_convertible_to(ToInt, int))];
- int t14[T(__is_convertible_to(ToInt, const int&))];
- int t15[T(__is_convertible_to(ToInt, long))];
- int t16[F(__is_convertible_to(ToInt, int&))];
- int t17[F(__is_convertible_to(ToInt, FromInt))];
- int t18[T(__is_convertible_to(IntAr&, IntAr&))];
- int t19[T(__is_convertible_to(IntAr&, const IntAr&))];
- int t20[F(__is_convertible_to(const IntAr&, IntAr&))];
- int t21[F(__is_convertible_to(Function, Function))];
- int t22[F(__is_convertible_to(PrivateCopy, PrivateCopy))];
- int t23[T(__is_convertible_to(X0<int>, X0<float>))];
+ { int arr[T(__is_convertible_to(Int, Int))]; }
+ { int arr[F(__is_convertible_to(Int, IntAr))]; }
+ { int arr[F(__is_convertible_to(IntAr, IntAr))]; }
+ { int arr[T(__is_convertible_to(void, void))]; }
+ { int arr[T(__is_convertible_to(cvoid, void))]; }
+ { int arr[T(__is_convertible_to(void, cvoid))]; }
+ { int arr[T(__is_convertible_to(cvoid, cvoid))]; }
+ { int arr[T(__is_convertible_to(int, FromInt))]; }
+ { int arr[T(__is_convertible_to(long, FromInt))]; }
+ { int arr[T(__is_convertible_to(double, FromInt))]; }
+ { int arr[T(__is_convertible_to(const int, FromInt))]; }
+ { int arr[T(__is_convertible_to(const int&, FromInt))]; }
+ { int arr[T(__is_convertible_to(ToInt, int))]; }
+ { int arr[T(__is_convertible_to(ToInt, const int&))]; }
+ { int arr[T(__is_convertible_to(ToInt, long))]; }
+ { int arr[F(__is_convertible_to(ToInt, int&))]; }
+ { int arr[F(__is_convertible_to(ToInt, FromInt))]; }
+ { int arr[T(__is_convertible_to(IntAr&, IntAr&))]; }
+ { int arr[T(__is_convertible_to(IntAr&, const IntAr&))]; }
+ { int arr[F(__is_convertible_to(const IntAr&, IntAr&))]; }
+ { int arr[F(__is_convertible_to(Function, Function))]; }
+ { int arr[F(__is_convertible_to(PrivateCopy, PrivateCopy))]; }
+ { int arr[T(__is_convertible_to(X0<int>, X0<float>))]; }
+}
+
+void is_trivial()
+{
+ { int arr[T(__is_trivial(int))]; }
+ { int arr[T(__is_trivial(Enum))]; }
+ { int arr[T(__is_trivial(POD))]; }
+ { int arr[T(__is_trivial(Int))]; }
+ { int arr[T(__is_trivial(IntAr))]; }
+ { int arr[T(__is_trivial(IntArNB))]; }
+ { int arr[T(__is_trivial(Statics))]; }
+ { int arr[T(__is_trivial(Empty))]; }
+ { int arr[T(__is_trivial(EmptyUnion))]; }
+ { int arr[T(__is_trivial(Union))]; }
+ { int arr[T(__is_trivial(Derives))]; }
+ { int arr[T(__is_trivial(DerivesAr))]; }
+ { int arr[T(__is_trivial(DerivesArNB))]; }
+ { int arr[T(__is_trivial(DerivesEmpty))]; }
+ { int arr[T(__is_trivial(HasFunc))]; }
+ { int arr[T(__is_trivial(HasOp))]; }
+ { int arr[T(__is_trivial(HasConv))]; }
+ { int arr[T(__is_trivial(HasAssign))]; }
+ { int arr[T(__is_trivial(HasAnonymousUnion))]; }
+ { int arr[T(__is_trivial(HasPriv))]; }
+ { int arr[T(__is_trivial(HasProt))]; }
+ { int arr[T(__is_trivial(DerivesHasPriv))]; }
+ { int arr[T(__is_trivial(DerivesHasProt))]; }
+ { int arr[T(__is_trivial(Vector))]; }
+ { int arr[T(__is_trivial(VectorExt))]; }
+
+ { int arr[F(__is_trivial(HasCons))]; }
+ { int arr[F(__is_trivial(HasCopyAssign))]; }
+ { int arr[F(__is_trivial(HasMoveAssign))]; }
+ { int arr[F(__is_trivial(HasDest))]; }
+ { int arr[F(__is_trivial(HasRef))]; }
+ { int arr[F(__is_trivial(HasNonPOD))]; }
+ { int arr[F(__is_trivial(HasVirt))]; }
+ { int arr[F(__is_trivial(DerivesHasCons))]; }
+ { int arr[F(__is_trivial(DerivesHasCopyAssign))]; }
+ { int arr[F(__is_trivial(DerivesHasMoveAssign))]; }
+ { int arr[F(__is_trivial(DerivesHasDest))]; }
+ { int arr[F(__is_trivial(DerivesHasRef))]; }
+ { int arr[F(__is_trivial(DerivesHasVirt))]; }
+ { int arr[F(__is_trivial(void))]; }
+ { int arr[F(__is_trivial(cvoid))]; }
+}
+
+void array_rank() {
+ int t01[T(__array_rank(IntAr) == 1)];
+ int t02[T(__array_rank(ConstIntArAr) == 2)];
+}
+
+void array_extent() {
+ int t01[T(__array_extent(IntAr, 0) == 10)];
+ int t02[T(__array_extent(ConstIntArAr, 0) == 4)];
+ int t03[T(__array_extent(ConstIntArAr, 1) == 10)];
}
diff --git a/test/SemaCXX/uninit-variables-conditional.cpp b/test/SemaCXX/uninit-variables-conditional.cpp
new file mode 100644
index 000000000000..3324215621bf
--- /dev/null
+++ b/test/SemaCXX/uninit-variables-conditional.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -Wconditional-uninitialized -fsyntax-only %s -verify
+
+class Foo {
+public:
+ Foo();
+ ~Foo();
+ operator bool();
+};
+
+int bar();
+int baz();
+int init(double *);
+
+// This case flags a false positive under -Wconditional-uninitialized because
+// the destructor in Foo fouls about the minor bit of path-sensitivity in
+// -Wuninitialized.
+double test() {
+ double x; // expected-note {{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}}
+ if (bar() || baz() || Foo() || init(&x))
+ return 1.0;
+
+ return x; // expected-warning {{variable 'x' may be uninitialized when used here}}
+}
diff --git a/test/SemaCXX/uninit-variables.cpp b/test/SemaCXX/uninit-variables.cpp
index 2bc7fb32547b..a0180e3d3a15 100644
--- a/test/SemaCXX/uninit-variables.cpp
+++ b/test/SemaCXX/uninit-variables.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only %s -verify
+// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only -fcxx-exceptions %s -verify
+
+// Stub out types for 'typeid' to work.
+namespace std { class type_info {}; }
int test1_aux(int &x);
int test1() {
@@ -13,6 +16,20 @@ int test2_aux() {
return x; // no-warning
}
+// Don't warn on unevaluated contexts.
+void unevaluated_tests() {
+ int x;
+ (void)sizeof(x);
+ (void)typeid(x);
+}
+
+// Warn for glvalue arguments to typeid whose type is polymorphic.
+struct A { virtual ~A() {} };
+void polymorphic_test() {
+ A *a; // expected-note{{declared here}} expected-note{{add initialization}}
+ (void)typeid(*a); // expected-warning{{variable 'a' is uninitialized when used here }}
+}
+
// Handle cases where the CFG may constant fold some branches, thus
// mitigating the need for some path-sensitivity in the analysis.
unsigned test3_aux();
@@ -38,7 +55,7 @@ unsigned test3_c() {
if (flag && (x = test3_aux()) == 0) {
x = 1;
}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
enum test4_A {
@@ -46,6 +63,49 @@ enum test4_A {
};
test4_A test4() {
test4_A a; // expected-note{{variable 'a' is declared here}}
- return a; // expected-warning{{variable 'a' is possibly uninitialized when used here}}
+ return a; // expected-warning{{variable 'a' is uninitialized when used here}}
}
+// This test previously crashed Sema.
+class Rdar9188004A {
+public:
+ virtual ~Rdar9188004A();
+};
+
+template< typename T > class Rdar9188004B : public Rdar9188004A {
+virtual double *foo(Rdar9188004B *next) const {
+ double *values = next->foo(0);
+ try {
+ }
+ catch(double e) {
+ values[0] = e;
+ }
+ return 0;
+ }
+};
+class Rdar9188004C : public Rdar9188004B<Rdar9188004A> {
+ virtual void bar(void) const;
+};
+void Rdar9188004C::bar(void) const {}
+
+// Don't warn about uninitialized variables in unreachable code.
+void PR9625() {
+ if (false) {
+ int x;
+ (void)static_cast<float>(x); // no-warning
+ }
+}
+
+// Don't warn about variables declared in "catch"
+void RDar9251392_bar(const char *msg);
+
+void RDar9251392() {
+ try {
+ throw "hi";
+ }
+ catch (const char* msg) {
+ RDar9251392_bar(msg); // no-warning
+ }
+}
+
+
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index 26202fbccc81..0a3b5d938dd3 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -1,14 +1,45 @@
// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -verify %s
-// Previously this triggered a warning on the sizeof(fieldB), indicating
-// a use of an uninitialized value.
-class Rdar8610363_A {
- int fieldA;
-public:
- Rdar8610363_A(int a);
-};
-class Rdar8610363_B {
- Rdar8610363_A fieldB;
-public:
- Rdar8610363_B(int b) : fieldB(sizeof(fieldB)) {} // no-warning
+int foo(int x);
+int bar(int* x);
+int boo(int& x);
+int far(const int& x);
+
+// Test self-references within initializers which are guaranteed to be
+// uninitialized.
+int a = a; // no-warning: used to signal intended lack of initialization.
+int b = b + 1; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}}
+int c = (c + c); // expected-warning 2 {{variable 'c' is uninitialized when used within its own initialization}}
+void test() {
+ int d = ({ d + d ;}); // expected-warning {{variable 'd' is uninitialized when used within its own initialization}}
+}
+int e = static_cast<long>(e) + 1; // expected-warning {{variable 'e' is uninitialized when used within its own initialization}}
+int f = foo(f); // expected-warning {{variable 'f' is uninitialized when used within its own initialization}}
+
+// Thes don't warn as they don't require the value.
+int g = sizeof(g);
+void* ptr = &ptr;
+int h = bar(&h);
+int i = boo(i);
+int j = far(j);
+int k = __alignof__(k);
+
+// Also test similar constructs in a field's initializer.
+struct S {
+ int x;
+ void *ptr;
+
+ S(bool (*)[1]) : x(x) {} // expected-warning {{field is uninitialized when used here}}
+ S(bool (*)[2]) : x(x + 1) {} // expected-warning {{field is uninitialized when used here}}
+ S(bool (*)[3]) : x(x + x) {} // expected-warning {{field is uninitialized when used here}}
+ S(bool (*)[4]) : x(static_cast<long>(x) + 1) {} // expected-warning {{field is uninitialized when used here}}
+ S(bool (*)[5]) : x(foo(x)) {} // FIXME: This should warn!
+
+ // These don't actually require the value of x and so shouldn't warn.
+ S(char (*)[1]) : x(sizeof(x)) {} // rdar://8610363
+ S(char (*)[2]) : ptr(&ptr) {}
+ S(char (*)[3]) : x(__alignof__(x)) {}
+ S(char (*)[4]) : x(bar(&x)) {}
+ S(char (*)[5]) : x(boo(x)) {}
+ S(char (*)[6]) : x(far(x)) {}
};
diff --git a/test/SemaCXX/unknown-anytype.cpp b/test/SemaCXX/unknown-anytype.cpp
new file mode 100644
index 000000000000..b0a2981f470d
--- /dev/null
+++ b/test/SemaCXX/unknown-anytype.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -funknown-anytype -fsyntax-only -verify %s
+
+namespace test0 {
+ extern __unknown_anytype test0;
+ extern __unknown_anytype test1();
+ extern __unknown_anytype test2(int);
+}
+
+namespace test1 {
+ extern __unknown_anytype foo;
+ int test() {
+ // TODO: it would be great if the 'cannot initialize' errors
+ // turned into something more interesting. It's just a matter of
+ // making sure that these locations check for placeholder types
+ // properly.
+
+ int x = foo; // expected-error {{cannot initialize}}
+ int y = 0 + foo; // expected-error {{'foo' has unknown type}}
+ return foo; // expected-error {{cannot initialize}}
+ }
+}
+
+namespace test2 {
+ extern __unknown_anytype foo();
+ void test() {
+ foo(); // expected-error {{'foo' has unknown return type}}
+ }
+}
+
+namespace test3 {
+ extern __unknown_anytype foo;
+ void test() {
+ foo(); // expected-error {{call to unsupported expression with unknown type}}
+ ((void(void)) foo)(); // expected-error {{variable 'foo' with unknown type cannot be given a function type}}
+ }
+}
diff --git a/test/SemaCXX/unreachable-catch-clauses.cpp b/test/SemaCXX/unreachable-catch-clauses.cpp
index e8158d449555..c75067f393ef 100644
--- a/test/SemaCXX/unreachable-catch-clauses.cpp
+++ b/test/SemaCXX/unreachable-catch-clauses.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
class BaseEx {};
class Ex1: public BaseEx {};
diff --git a/test/SemaCXX/unreachable-code.cpp b/test/SemaCXX/unreachable-code.cpp
index 03d44ab8ce47..743290e1b9e5 100644
--- a/test/SemaCXX/unreachable-code.cpp
+++ b/test/SemaCXX/unreachable-code.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -Wunreachable-code -fblocks -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -Wunreachable-code -fblocks -verify %s
int j;
void bar() { }
diff --git a/test/SemaCXX/unused-functions.cpp b/test/SemaCXX/unused-functions.cpp
index cefa9e118a48..f164bf276846 100644
--- a/test/SemaCXX/unused-functions.cpp
+++ b/test/SemaCXX/unused-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused -verify %s
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -Wunused -verify %s
static int foo(int x) { return x; }
@@ -6,3 +6,5 @@ template<typename T>
T get_from_foo(T y) { return foo(y); }
int g(int z) { return get_from_foo(z); }
+
+namespace { void f() = delete; }
diff --git a/test/SemaCXX/vtable-instantiation.cc b/test/SemaCXX/vtable-instantiation.cc
index 5a13d9505b3d..49949a773675 100644
--- a/test/SemaCXX/vtable-instantiation.cc
+++ b/test/SemaCXX/vtable-instantiation.cc
@@ -18,3 +18,29 @@ void f() {
c2.c2(); // expected-note {{in instantiation of member function}}
}
+namespace PR9325 {
+ template<typename T>
+ class Target
+ {
+ public:
+ virtual T Value() const
+ {
+ return 1; // expected-error{{cannot initialize return object of type 'int *' with an rvalue of type 'int'}}
+ }
+ };
+
+ template<typename T>
+ struct Provider
+ {
+ static Target<T> Instance;
+ };
+
+ template<typename T>
+ Target<T> Provider<T>::Instance; // expected-note{{in instantiation of}}
+
+ void f()
+ {
+ Target<int*>* traits = &Provider<int*>::Instance;
+ }
+
+}
diff --git a/test/SemaCXX/warn-assignment-condition.cpp b/test/SemaCXX/warn-assignment-condition.cpp
index 27eedb9128d7..c0ef35b252d8 100644
--- a/test/SemaCXX/warn-assignment-condition.cpp
+++ b/test/SemaCXX/warn-assignment-condition.cpp
@@ -125,3 +125,16 @@ void test2() {
if ((test2 == fn)) {}
}
+namespace rdar9027658 {
+template <typename T>
+void f() {
+ if ((T::g == 3)) { } // expected-warning {{equality comparison with extraneous parentheses}} \
+ // expected-note {{use '=' to turn this equality comparison into an assignment}} \
+ // expected-note {{remove extraneous parentheses around the comparison to silence this warning}}
+}
+
+struct S { int g; };
+void test() {
+ f<S>(); // expected-note {{in instantiation}}
+}
+}
diff --git a/test/SemaCXX/warn-bool-conversion.cpp b/test/SemaCXX/warn-bool-conversion.cpp
new file mode 100644
index 000000000000..f6fa9f28369d
--- /dev/null
+++ b/test/SemaCXX/warn-bool-conversion.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int* j = false; // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+
+void foo(int* i, int *j=(false)) // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+{
+ foo(false); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+ foo((int*)false); // no-warning: explicit cast
+ foo(0); // no-warning: not a bool, even though its convertible to bool
+
+ foo(false == true); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+ foo((42 + 24) < 32); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+
+ const bool kFlag = false;
+ foo(kFlag); // expected-warning{{ initialization of pointer of type 'int *' to NULL from a constant boolean expression}}
+}
+
+char f(struct Undefined*);
+double f(...);
+
+// Ensure that when using false in metaprogramming machinery its conversion
+// isn't flagged.
+template <int N> struct S {};
+S<sizeof(f(false))> s;
diff --git a/test/SemaCXX/warn-deprecated-header.cpp b/test/SemaCXX/warn-deprecated-header.cpp
new file mode 100644
index 000000000000..f6ac2cb6393a
--- /dev/null
+++ b/test/SemaCXX/warn-deprecated-header.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -fdeprecated-macro -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Werror %s
+
+#ifdef __DEPRECATED
+#warning This file is deprecated. // expected-warning {{This file is deprecated.}}
+#endif
diff --git a/test/SemaCXX/warn-exit-time-destructors.cpp b/test/SemaCXX/warn-exit-time-destructors.cpp
new file mode 100644
index 000000000000..f49134b71c97
--- /dev/null
+++ b/test/SemaCXX/warn-exit-time-destructors.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -Wexit-time-destructors %s -verify
+
+namespace test1 {
+ struct A { ~A(); };
+ A a; // expected-warning {{declaration requires an exit-time destructor}}
+ A b[10]; // expected-warning {{declaration requires an exit-time destructor}}
+ A c[10][10]; // expected-warning {{declaration requires an exit-time destructor}}
+
+ A &d = a;
+ A &e = b[5];
+ A &f = c[5][7];
+}
+
+namespace test2 {
+void f() {
+ struct A { ~A() { } };
+
+ static A a; // expected-warning {{declaration requires an exit-time destructor}}
+ static A b[10]; // expected-warning {{declaration requires an exit-time destructor}}
+ static A c[10][10]; // expected-warning {{declaration requires an exit-time destructor}}
+
+ static A &d = a;
+ static A &e = b[5];
+ static A &f = c[5][7];
+}
+
+}
diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp
index ad609545ece1..6330958df703 100644
--- a/test/SemaCXX/warn-global-constructors.cpp
+++ b/test/SemaCXX/warn-global-constructors.cpp
@@ -53,8 +53,8 @@ namespace test3 {
namespace test4 {
char a[] = "hello";
- char b[5] = "hello";
- char c[][5] = { "hello" };
+ char b[6] = "hello";
+ char c[][6] = { "hello" };
}
namespace test5 {
diff --git a/test/SemaCXX/warn-literal-conversion.cpp b/test/SemaCXX/warn-literal-conversion.cpp
index dab5c01bf6b0..b9c952873b9f 100644
--- a/test/SemaCXX/warn-literal-conversion.cpp
+++ b/test/SemaCXX/warn-literal-conversion.cpp
@@ -8,13 +8,18 @@ void test0() {
int y0 = 1.2222F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
int y1 = (1.2222F); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
int y2 = (((1.2222F))); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y3 = 12E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y4 = 1.2E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ int y3 = 12E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y4 = 1.2E1F; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
// Double
int y5 = 1.2222; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y6 = 12E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y7 = 1.2E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
- int y8 = (1.2E1); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ int y6 = 12E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y7 = 1.2E1; // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
+ int y8 = (1.2E1); // expected-warning {{implicit conversion turns literal floating-point number into integer}} \
+ // expected-note {{this can be rewritten as an integer literal with the exact same value}}
// Test assignment to an existing variable.
y8 = 2.22F; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
diff --git a/test/SemaCXX/warn-missing-prototypes.cpp b/test/SemaCXX/warn-missing-prototypes.cpp
index b6ebe820f39c..f7e8db38a4f6 100644
--- a/test/SemaCXX/warn-missing-prototypes.cpp
+++ b/test/SemaCXX/warn-missing-prototypes.cpp
@@ -24,3 +24,9 @@ template<typename> void h() { }
// Don't warn when instantiating function templates.
template void h<int>();
+
+// PR9519: don't warn about friend functions.
+class I {
+ friend void I_friend() {}
+};
+
diff --git a/test/SemaCXX/warn-non-pod-memset.cpp b/test/SemaCXX/warn-non-pod-memset.cpp
new file mode 100644
index 000000000000..fbdceadae29b
--- /dev/null
+++ b/test/SemaCXX/warn-non-pod-memset.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -Wnon-pod-memset -verify %s
+
+extern void *memset(void *, int, unsigned);
+
+// Several POD types that should not warn.
+struct S1 {} s1;
+struct S2 { int x; } s2;
+struct S3 { float x, y; S1 s[4]; void (*f)(S1**); } s3;
+
+// We use the C++11 concept of POD for this warning, so ensure a non-aggregate
+// still warns.
+class C1 {
+ int x, y, z;
+public:
+ void foo() {}
+} c1;
+
+// Non-POD types that should warn.
+struct X1 { X1(); } x1;
+struct X2 { ~X2(); } x2;
+struct X3 { virtual void f(); } x3;
+struct X4 : X2 {} x4;
+struct X5 : virtual S1 {} x5;
+
+void test_warn() {
+ memset(&x1, 0, sizeof x1); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x2, 0, sizeof x2); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x3, 0, sizeof x3); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x4, 0, sizeof x4); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x5, 0, sizeof x5); // \
+ // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+}
+
+void test_nowarn(void *void_ptr) {
+ int i, *iptr;
+ float y;
+ char c;
+
+ memset(&i, 0, sizeof i);
+ memset(&iptr, 0, sizeof iptr);
+ memset(&y, 0, sizeof y);
+ memset(&c, 0, sizeof c);
+ memset(void_ptr, 0, 42);
+ memset(&s1, 0, sizeof s1);
+ memset(&s2, 0, sizeof s2);
+ memset(&s3, 0, sizeof s3);
+ memset(&c1, 0, sizeof c1);
+
+ // Unevaluated code shouldn't warn.
+ (void)sizeof memset(&x1, 0, sizeof x1);
+
+ // Dead code shouldn't warn.
+ if (false) memset(&x1, 0, sizeof x1);
+}
diff --git a/test/SemaCXX/warn-overloaded-virtual.cpp b/test/SemaCXX/warn-overloaded-virtual.cpp
index 86b1d2365f93..8e2b671bf493 100644
--- a/test/SemaCXX/warn-overloaded-virtual.cpp
+++ b/test/SemaCXX/warn-overloaded-virtual.cpp
@@ -52,3 +52,15 @@ struct Derived : public Base {
void foo(int, int);
};
}
+
+namespace PR9396 {
+class A {
+public:
+ virtual void f(int) {}
+};
+
+class B : public A {
+public:
+ static void f() {}
+};
+}
diff --git a/test/SemaCXX/warn-shadow.cpp b/test/SemaCXX/warn-shadow.cpp
index 3bf9af414db0..68e9467a937b 100644
--- a/test/SemaCXX/warn-shadow.cpp
+++ b/test/SemaCXX/warn-shadow.cpp
@@ -70,3 +70,14 @@ struct S {
}
};
}
+
+extern int bob; // expected-note {{previous declaration is here}}
+
+// rdar://8883302
+void rdar8883302() {
+ extern int bob; // don't warn for shadowing.
+}
+
+void test8() {
+ int bob; // expected-warning {{declaration shadows a variable in the global namespace}}
+}
diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp
index 3c8a429b3e58..ea6755f2d6ce 100644
--- a/test/SemaCXX/warn-unreachable.cpp
+++ b/test/SemaCXX/warn-unreachable.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fexceptions -fsyntax-only -verify -fblocks -Wunreachable-code -Wno-unused-value
+// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -verify -fblocks -Wunreachable-code -Wno-unused-value
int &halt() __attribute__((noreturn));
int &live();
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index c32acb0b48be..dbff4b0e68c1 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -78,3 +78,12 @@ namespace test4 {
void test(A a); // expected-warning {{unused function}}
extern "C" void test4(A a);
}
+
+namespace rdar8733476 {
+ static void foo() { } // expected-warning {{not needed and will not be emitted}}
+
+ template <int>
+ void bar() {
+ foo();
+ }
+}
diff --git a/test/SemaCXX/warn-using-namespace-in-header.cpp b/test/SemaCXX/warn-using-namespace-in-header.cpp
new file mode 100644
index 000000000000..72c25529b40f
--- /dev/null
+++ b/test/SemaCXX/warn-using-namespace-in-header.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -fsyntax-only -Wheader-hygiene -verify %s
+
+#include "warn-using-namespace-in-header.h"
+
+namespace dont_warn {}
+using namespace dont_warn;
+
+// Warning is actually in the header but only the cpp file gets scanned.
+// expected-warning {{using namespace directive in global context in header}}
+
+
+
+
+
+
+
+
+
+// Warn inside linkage specs too.
+// expected-warning {{using namespace directive in global context in header}}
+
+
+
+
+
+
+// expected-warning {{using namespace directive in global context in header}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// expected-warning {{using namespace directive in global context in header}}
+
+// |using namespace| through a macro shouldn't warn if the instantiation is in a
+// cc file.
+USING_MACRO
diff --git a/test/SemaCXX/warn-using-namespace-in-header.h b/test/SemaCXX/warn-using-namespace-in-header.h
new file mode 100644
index 000000000000..b544c548ae9b
--- /dev/null
+++ b/test/SemaCXX/warn-using-namespace-in-header.h
@@ -0,0 +1,50 @@
+
+
+
+
+
+// Lots of vertical space to make the error line match up with the line of the
+// expected line in the source file.
+namespace warn_in_header_in_global_context {}
+using namespace warn_in_header_in_global_context;
+
+// While we want to error on the previous using directive, we don't when we are
+// inside a namespace
+namespace dont_warn_here {
+using namespace warn_in_header_in_global_context;
+}
+
+// We should warn in toplevel extern contexts.
+namespace warn_inside_linkage {}
+extern "C++" {
+using namespace warn_inside_linkage;
+}
+
+// This is really silly, but we should warn on it:
+extern "C++" {
+extern "C" {
+extern "C++" {
+using namespace warn_inside_linkage;
+}
+}
+}
+
+// But we shouldn't warn in extern contexts inside namespaces.
+namespace dont_warn_here {
+extern "C++" {
+using namespace warn_in_header_in_global_context;
+}
+}
+
+// We also shouldn't warn in case of functions.
+inline void foo() {
+ using namespace warn_in_header_in_global_context;
+}
+
+
+namespace macronamespace {}
+#define USING_MACRO using namespace macronamespace;
+
+// |using namespace| through a macro should warn if the instantiation is in a
+// header.
+USING_MACRO
diff --git a/test/SemaCXX/warn_false_to_pointer.cpp b/test/SemaCXX/warn_false_to_pointer.cpp
deleted file mode 100644
index fb6f9551a7ac..000000000000
--- a/test/SemaCXX/warn_false_to_pointer.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-int* j = false; // expected-warning{{ initialization of pointer of type 'int *' from literal 'false'}}
-
-void foo(int* i, int *j=(false)) // expected-warning{{ initialization of pointer of type 'int *' from literal 'false'}}
-{
- foo(false); // expected-warning{{ initialization of pointer of type 'int *' from literal 'false'}}
- foo((int*)false);
-}
-
diff --git a/test/SemaCXX/writable-strings-deprecated.cpp b/test/SemaCXX/writable-strings-deprecated.cpp
index c89c88256426..829540149563 100644
--- a/test/SemaCXX/writable-strings-deprecated.cpp
+++ b/test/SemaCXX/writable-strings-deprecated.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated-writable-strings -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fwritable-strings -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-write-strings -verify %s
// rdar://8827606
char *fun(void)
diff --git a/test/SemaObjC/assign-rvalue-message.m b/test/SemaObjC/assign-rvalue-message.m
new file mode 100644
index 000000000000..7e05c89afa43
--- /dev/null
+++ b/test/SemaObjC/assign-rvalue-message.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s
+// rdar://9005189
+
+@interface Foo
+@end
+
+struct Bar {
+ int x;
+};
+
+@implementation Foo {
+ struct Bar bar;
+}
+
+- (const struct Bar)bar {
+ return bar;
+}
+
+- (void)baz {
+ bar.x = 0;
+ [self bar].x = 10; // expected-error {{assigning to 'readonly' return result of an objective-c message not allowed}}
+}
+@end
diff --git a/test/SemaObjC/attr-objc-gc.m b/test/SemaObjC/attr-objc-gc.m
index 47da653afe6e..9ca12c9315a1 100644
--- a/test/SemaObjC/attr-objc-gc.m
+++ b/test/SemaObjC/attr-objc-gc.m
@@ -1,8 +1,30 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
static id __attribute((objc_gc(weak))) a;
static id __attribute((objc_gc(strong))) b;
static id __attribute((objc_gc())) c; // expected-error{{'objc_gc' attribute requires parameter 1 to be a string}}
static id __attribute((objc_gc(123))) d; // expected-error{{'objc_gc' attribute requires parameter 1 to be a string}}
-static id __attribute((objc_gc(foo, 456))) e; // expected-error{{attribute requires 1 argument(s)}}
+static id __attribute((objc_gc(foo, 456))) e; // expected-error{{attribute takes one argument}}
static id __attribute((objc_gc(hello))) f; // expected-warning{{'objc_gc' attribute argument not supported: 'hello'}}
+
+static int __attribute__((objc_gc(weak))) g; // expected-warning {{'objc_gc' only applies to pointer types; type here is 'int'}}
+
+static __weak int h; // expected-warning {{'__weak' only applies to pointer types; type here is 'int'}}
+
+// TODO: it would be great if this reported as __weak
+#define WEAK __weak
+static WEAK int h; // expected-warning {{'objc_gc' only applies to pointer types; type here is 'int'}}
+
+/* expected-warning {{'__weak' only applies to pointer types; type here is 'int'}}*/ static __we\
+ak int i;
+
+// rdar://problem/9126213
+void test2(id __attribute((objc_gc(strong))) *strong,
+ id __attribute((objc_gc(weak))) *weak) {
+ void *opaque;
+ opaque = strong;
+ strong = opaque;
+
+ opaque = weak;
+ weak = opaque;
+}
diff --git a/test/SemaObjC/auto-objective-c.m b/test/SemaObjC/auto-objective-c.m
deleted file mode 100644
index 5467e24a7951..000000000000
--- a/test/SemaObjC/auto-objective-c.m
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clang_cc1 -x objective-c -fblocks -fsyntax-only -verify %s
-
-@interface I
-{
- id pi;
-}
-- (id) Meth;
-@end
-
-// Objective-C does not support trailing return types, so check we don't get
-// the C++ diagnostic suggesting we forgot one.
-auto noTrailingReturnType(); // expected-error {{'auto' not allowed in function return type}}
-
-typedef int (^P) (int x);
-
-@implementation I
-- (id) Meth {
- auto p = [pi Meth];
- return p;
-}
-
-- (P) bfunc {
- auto my_block = ^int (int x) {return x; };
- my_block(1);
- return my_block;
-}
-@end
-
-
-// rdar://9036633
-int main() {
- auto int auto_i = 7; // expected-warning {{'auto' storage class specifier is redundant and will be removed in future releases}}
-}
diff --git a/test/SemaObjC/block-type-safety.m b/test/SemaObjC/block-type-safety.m
index c13e80618d51..ebc6777f7fbb 100644
--- a/test/SemaObjC/block-type-safety.m
+++ b/test/SemaObjC/block-type-safety.m
@@ -121,3 +121,20 @@ int test4 () {
return 0;
}
+// rdar:// 9118343
+
+@protocol NSCopying @end
+
+@interface NSAllArray <NSCopying>
+@end
+
+@interface NSAllArray (FooConformance) <Foo>
+@end
+
+int test5() {
+ NSAllArray *(^block)(id);
+ id <Foo> (^genericBlock)(id);
+ genericBlock = block;
+ return 0;
+}
+
diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m
index 84a625c404ec..d77b759ffa73 100644
--- a/test/SemaObjC/call-super-2.m
+++ b/test/SemaObjC/call-super-2.m
@@ -35,8 +35,8 @@ id objc_getClass(const char *s);
@implementation Derived
+ (int) class_func1
{
- int i = (size_t)[self class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}}
- return i + (size_t)[super class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}}
+ int i = (size_t)[self class_func0]; // expected-warning {{class method '+class_func0' not found (return type defaults to 'id')}}
+ return i + (size_t)[super class_func0]; // expected-warning {{class method '+class_func0' not found (return type defaults to 'id')}}
}
+ (int) class_func2
{
@@ -55,8 +55,8 @@ id objc_getClass(const char *s);
}
+ (int) class_func5
{
- int i = (size_t)[Derived class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}}
- return i + (size_t)[Object class_func0]; // expected-warning {{method '+class_func0' not found (return type defaults to 'id')}}
+ int i = (size_t)[Derived class_func0]; // expected-warning {{class method '+class_func0' not found (return type defaults to 'id')}}
+ return i + (size_t)[Object class_func0]; // expected-warning {{class method '+class_func0' not found (return type defaults to 'id')}}
}
+ (int) class_func6
{
@@ -68,7 +68,7 @@ id objc_getClass(const char *s);
}
- (int) instance_func1
{
- int i = (size_t)[self instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id'))}}
+ int i = (size_t)[self instance_func0]; // expected-warning {{instance method '-instance_func0' not found (return type defaults to 'id'))}}
return i + (size_t)[super instance_func0]; // expected-warning {{'Object' may not respond to 'instance_func0')}}
}
- (int) instance_func2
@@ -85,8 +85,8 @@ id objc_getClass(const char *s);
}
- (int) instance_func5
{
- int i = (size_t)[Derived instance_func1]; // expected-warning {{method '+instance_func1' not found (return type defaults to 'id')}}
- return i + (size_t)[Object instance_func1]; // expected-warning {{method '+instance_func1' not found (return type defaults to 'id')}}
+ int i = (size_t)[Derived instance_func1]; // expected-warning {{class method '+instance_func1' not found (return type defaults to 'id')}}
+ return i + (size_t)[Object instance_func1]; // expected-warning {{class method '+instance_func1' not found (return type defaults to 'id')}}
}
- (int) instance_func6
{
diff --git a/test/SemaObjC/class-message-protocol-lookup.m b/test/SemaObjC/class-message-protocol-lookup.m
new file mode 100644
index 000000000000..ae64ea86804b
--- /dev/null
+++ b/test/SemaObjC/class-message-protocol-lookup.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9224670
+
+@interface RandomObject {
+@private
+}
++ (id)alloc;
+@end
+
+@protocol TestProtocol
+- (void)nothingInteresting;
+@end
+
+@protocol Test2Protocol
++ (id)alloc;
+- (id)alloc2; // expected-note 2 {{method declared here}}
+@end
+
+@implementation RandomObject
+- (void) Meth {
+ Class<TestProtocol> c = [c alloc]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}}
+ Class<Test2Protocol> c1 = [c1 alloc2]; // expected-warning {{instance method 'alloc2' found instead of class method 'alloc2'}}
+ Class<Test2Protocol> c2 = [c2 alloc]; // ok
+}
++ (id)alloc { return 0; }
+@end
+
+int main ()
+{
+ Class<TestProtocol> c = [c alloc]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}}
+ Class<Test2Protocol> c1 = [c1 alloc2]; // expected-warning {{instance method 'alloc2' found instead of class method 'alloc2'}}
+ Class<Test2Protocol> c2 = [c2 alloc]; // ok
+ return 0;
+}
diff --git a/test/SemaObjC/class-unavail-warning.m b/test/SemaObjC/class-unavail-warning.m
new file mode 100644
index 000000000000..426ac772c8aa
--- /dev/null
+++ b/test/SemaObjC/class-unavail-warning.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9092208
+
+__attribute__((unavailable("not available")))
+@interface MyClass { // expected-note 5 {{function has been explicitly marked unavailable here}}
+@public
+ void *_test;
+}
+
+- (id)self;
+- new;
++ (void)addObject:(id)anObject;
+
+@end
+
+int main() {
+ [MyClass new]; // expected-error {{'MyClass' is unavailable: not available}}
+ [MyClass self]; // expected-error {{'MyClass' is unavailable: not available}}
+ [MyClass addObject:((void *)0)]; // expected-error {{'MyClass' is unavailable: not available}}
+
+ MyClass *foo = [MyClass new]; // expected-error 2 {{'MyClass' is unavailable: not available}}
+
+ return 0;
+}
diff --git a/test/SemaObjC/comptypes-4.m b/test/SemaObjC/comptypes-4.m
index 56b23b22458f..adc324c91ee5 100644
--- a/test/SemaObjC/comptypes-4.m
+++ b/test/SemaObjC/comptypes-4.m
@@ -12,7 +12,7 @@ int main()
MyClass *obj_cp;
obj_cp = obj_p;
- obj_p = obj_cp;
+ obj_p = obj_cp; // expected-warning {{incompatible pointer types assigning to 'MyClass<MyProtocol> *' from 'MyClass *'}}
if (obj_cp == obj_p)
foo();
diff --git a/test/SemaObjC/conditional-expr-8.m b/test/SemaObjC/conditional-expr-8.m
new file mode 100644
index 000000000000..6799983e3b16
--- /dev/null
+++ b/test/SemaObjC/conditional-expr-8.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9296866
+
+@interface NSResponder
+@end
+
+
+@interface NSView : NSResponder
+@end
+
+@interface WebView : NSView
+@end
+
+@protocol WebDocumentView
+@end
+
+@implementation NSView
+
+- (void) FUNC : (id)s {
+ WebView *m_webView;
+ NSView <WebDocumentView> *documentView;
+ NSView *coordinateView = s ? documentView : m_webView;
+}
+@end
+
diff --git a/test/SemaObjC/exprs.m b/test/SemaObjC/exprs.m
index 13c34e5650de..d7c122356f58 100644
--- a/test/SemaObjC/exprs.m
+++ b/test/SemaObjC/exprs.m
@@ -9,12 +9,12 @@ Class test1(Class X) {
// rdar://6079877
void test2() {
id str = @"foo"
- "bar\0" // expected-warning {{literal contains NUL character}}
+ "bar\0" // no-warning
@"baz" " blarg";
id str2 = @"foo"
"bar"
@"baz"
- " b\0larg"; // expected-warning {{literal contains NUL character}}
+ " b\0larg"; // no-warning
if (@encode(int) == "foo") { } // expected-warning {{result of comparison against @encode is unspecified}}
diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m
index 0f7fd9eea992..c865374e61af 100644
--- a/test/SemaObjC/foreach.m
+++ b/test/SemaObjC/foreach.m
@@ -16,3 +16,33 @@ void f(NSArray *a) {
for (id thisKey in keys);
for (id thisKey in keys);
}
+
+/* // rdar://9072298 */
+@protocol NSObject @end
+
+@interface NSObject <NSObject> {
+ Class isa;
+}
+@end
+
+typedef struct {
+ unsigned long state;
+ id *itemsPtr;
+ unsigned long *mutationsPtr;
+ unsigned long extra[5];
+} NSFastEnumerationState;
+
+@protocol NSFastEnumeration
+
+- (unsigned long)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(unsigned long)len;
+
+@end
+
+int main ()
+{
+ NSObject<NSFastEnumeration>* collection = ((void*)0);
+ for (id thing in collection) { }
+
+ return 0;
+}
+
diff --git a/test/SemaObjC/format-arg-attribute.m b/test/SemaObjC/format-arg-attribute.m
index 98dff3aa7a7b..6edb8fd99b31 100644
--- a/test/SemaObjC/format-arg-attribute.m
+++ b/test/SemaObjC/format-arg-attribute.m
@@ -5,16 +5,16 @@
extern NSString *fa2 (const NSString *) __attribute__((format_arg(1)));
extern NSString *fa3 (NSString *) __attribute__((format_arg(1)));
-extern void fc1 (const NSString *) __attribute__((format_arg)); // expected-error {{attribute requires 1 argument(s)}}
-extern void fc2 (const NSString *) __attribute__((format_arg())); // expected-error {{attribute requires 1 argument(s)}}
-extern void fc3 (const NSString *) __attribute__((format_arg(1, 2))); // expected-error {{attribute requires 1 argument(s)}}
+extern void fc1 (const NSString *) __attribute__((format_arg)); // expected-error {{attribute takes one argument}}
+extern void fc2 (const NSString *) __attribute__((format_arg())); // expected-error {{attribute takes one argument}}
+extern void fc3 (const NSString *) __attribute__((format_arg(1, 2))); // expected-error {{attribute takes one argument}}
struct s1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}}
union u1 { int i; } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}}
enum e1 { E1V0 } __attribute__((format_arg(1))); // expected-warning {{'format_arg' attribute only applies to functions}}
extern NSString *ff3 (const NSString *) __attribute__((format_arg(3-2)));
-extern NSString *ff4 (const NSString *) __attribute__((format_arg(foo))); // expected-error {{attribute requires 1 argument(s)}}
+extern NSString *ff4 (const NSString *) __attribute__((format_arg(foo))); // expected-error {{attribute takes one argument}}
/* format_arg formats must take and return a string. */
extern NSString *fi0 (int) __attribute__((format_arg(1))); // expected-error {{format argument not a string type}}
diff --git a/test/SemaObjC/iboutletcollection-attr.m b/test/SemaObjC/iboutletcollection-attr.m
index 217daa7c3b58..5c82c8308a43 100644
--- a/test/SemaObjC/iboutletcollection-attr.m
+++ b/test/SemaObjC/iboutletcollection-attr.m
@@ -16,13 +16,13 @@
typedef void *PV;
@interface BAD {
- __attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{attribute requires 1 argument(s)}}
+ __attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{attribute takes one argument}}
__attribute__((iboutletcollection(B))) id ivar2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
__attribute__((iboutletcollection(PV))) id ivar3; // expected-error {{invalid type 'PV' as argument of iboutletcollection attribute}}
__attribute__((iboutletcollection(PV))) void *ivar4; // expected-error {{ivar with iboutletcollection attribute must have object type (invalid 'void *')}}
__attribute__((iboutletcollection(int))) id ivar5; // expected-error {{type argument of iboutletcollection attribute cannot be a builtin type}}
}
-@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{attribute requires 1 argument(s)}}
+@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{attribute takes one argument}}
@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
@property __attribute__((iboutletcollection(BAD))) int prop3; // expected-error {{property with iboutletcollection attribute must have object type (invalid 'int')}}
diff --git a/test/SemaObjC/idiomatic-parentheses.m b/test/SemaObjC/idiomatic-parentheses.m
index 011efbc437bf..39e97e2df60a 100644
--- a/test/SemaObjC/idiomatic-parentheses.m
+++ b/test/SemaObjC/idiomatic-parentheses.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wparentheses %s
-// Don't warn about some common ObjC idioms unless we have -Wparentheses on.
+// Don't warn about some common ObjC idioms unless we have -Widiomatic-parentheses on.
// <rdar://problem/7382435>
@interface Object
diff --git a/test/SemaObjC/ignore-weakimport-method.m b/test/SemaObjC/ignore-weakimport-method.m
index f80312ac06f3..d71cebf2c79a 100644
--- a/test/SemaObjC/ignore-weakimport-method.m
+++ b/test/SemaObjC/ignore-weakimport-method.m
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-
@interface foo
+ (void) cx __attribute__((weak_import));
- (void) x __attribute__((weak_import));
diff --git a/test/SemaObjC/ivar-lookup.m b/test/SemaObjC/ivar-lookup.m
index 06e47116f73c..2b14bff85d84 100644
--- a/test/SemaObjC/ivar-lookup.m
+++ b/test/SemaObjC/ivar-lookup.m
@@ -35,3 +35,15 @@ extern struct foo x;
}
@end
+@interface TwoIvars {
+ int a;
+ int b;
+}
+@end
+
+@implementation TwoIvars
++ (int)classMethod {
+ return a + b; // expected-error{{instance variable 'a' accessed in class method}} \
+ // expected-error{{instance variable 'b' accessed in class method}}
+}
+@end
diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m
index 388e44724d5b..0a1b1cd06782 100644
--- a/test/SemaObjC/method-bad-param.m
+++ b/test/SemaObjC/method-bad-param.m
@@ -26,7 +26,7 @@ foo somefunc2() {} // expected-error {{Objective-C interface type 'foo' cannot b
// rdar://6780761
void f0(foo *a0) {
extern void g0(int x, ...);
- g0(1, *(foo*)0); // expected-error {{cannot pass object with interface type 'foo' by-value through variadic function}}
+ g0(1, *(foo*)a0); // expected-error {{cannot pass object with interface type 'foo' by-value through variadic function}}
}
// rdar://8421082
diff --git a/test/SemaObjC/method-not-defined.m b/test/SemaObjC/method-not-defined.m
index 78bf65027284..ed68b22945c4 100644
--- a/test/SemaObjC/method-not-defined.m
+++ b/test/SemaObjC/method-not-defined.m
@@ -7,7 +7,7 @@ void test() {
Foo *fooObj;
id obj;
- [[Foo alloc] init]; // expected-warning {{method '+alloc' not found (return type defaults to 'id')}} expected-warning {{method '-init' not found (return type defaults to 'id')}}
- [fooObj notdefined]; // expected-warning {{method '-notdefined' not found (return type defaults to 'id')}}
- [obj whatever:1 :2 :3]; // expected-warning {{method '-whatever:::' not found (return type defaults to 'id'))}}
+ [[Foo alloc] init]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}} expected-warning {{instance method '-init' not found (return type defaults to 'id')}}
+ [fooObj notdefined]; // expected-warning {{instance method '-notdefined' not found (return type defaults to 'id')}}
+ [obj whatever:1 :2 :3]; // expected-warning {{instance method '-whatever:::' not found (return type defaults to 'id'))}}
}
diff --git a/test/SemaObjC/method-prototype-scope.m b/test/SemaObjC/method-prototype-scope.m
index 2184172f35c9..b08faa65b22a 100644
--- a/test/SemaObjC/method-prototype-scope.m
+++ b/test/SemaObjC/method-prototype-scope.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wduplicate-method-arg -verify %s
// rdar://8877730
@@ -11,7 +11,7 @@ int object;
- doSomethingElseWith:(id)object;
-- (NSString *)doSomethingWith:(NSString *)object and:(NSArray *)object; // expected-warning {{redefinition of method parameter 'object'}} \
+- (NSString *)doSomethingWith:(NSString *)object and:(NSArray *)object; // expected-warning {{redeclaration of method parameter 'object'}} \
// expected-note {{previous declaration is here}}
@end
diff --git a/test/SemaObjC/method-sentinel-attr.m b/test/SemaObjC/method-sentinel-attr.m
index 5375408a2b66..274e93660653 100644
--- a/test/SemaObjC/method-sentinel-attr.m
+++ b/test/SemaObjC/method-sentinel-attr.m
@@ -13,7 +13,7 @@
- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a"))); // expected-error {{'sentinel' attribute requires parameter 1 to be an integer constant}}
- (void) foo9 : (int)x, ... __attribute__ ((__sentinel__(-1))); // expected-error {{'sentinel' parameter 1 less than zero}}
- (void) foo10 : (int)x, ... __attribute__ ((__sentinel__(1,1)));
-- (void) foo11 : (int)x, ... __attribute__ ((__sentinel__(1,1,3))); // expected-error {{attribute requires 0, 1 or 2 argument(s)}}
+- (void) foo11 : (int)x, ... __attribute__ ((__sentinel__(1,1,3))); // expected-error {{attribute takes no more than 2 arguments}}
- (void) foo12 : (int)x, ... ATTR; // expected-note {{method has been explicitly marked sentinel here}}
// rdar://7975788
diff --git a/test/SemaObjC/missing-atend-metadata.m b/test/SemaObjC/missing-atend-metadata.m
new file mode 100644
index 000000000000..434706d3fafc
--- /dev/null
+++ b/test/SemaObjC/missing-atend-metadata.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+@interface I0
+@end
+
+@implementation I0 // expected-error {{'@end' is missing in implementation context}}
+- meth { return 0; }
+
+@interface I1 : I0
+@end
+
+@implementation I1 // expected-error {{'@end' is missing in implementation context}}
+-(void) im0 { self = [super init]; } // expected-warning {{nstance method '-init' not found }}
+
+@interface I2 : I0
+- I2meth;
+@end
+
+@implementation I2 // expected-error {{'@end' is missing in implementation context}}
+- I2meth { return 0; }
+
+@implementation I2(CAT) // expected-error {{'@end' is missing in implementation context}}
diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m
index 6c45d97b0660..76c6ffa229ea 100644
--- a/test/SemaObjC/nonnull.m
+++ b/test/SemaObjC/nonnull.m
@@ -67,3 +67,30 @@ void func6(dispatch_object_t _head) {
_dispatch_queue_push_list(_head._do); // no warning
}
+// rdar://9287695
+#define NULL (void*)0
+
+@interface NSObject
+- (void)doSomethingWithNonNullPointer:(void *)ptr :(int)iarg : (void*)ptr1 __attribute__((nonnull(1, 3)));
++ (void)doSomethingClassyWithNonNullPointer:(void *)ptr __attribute__((nonnull(1)));
+@end
+
+extern void DoSomethingNotNull(void *db) __attribute__((nonnull(1)));
+
+@interface IMP
+{
+ void * vp;
+}
+@end
+
+@implementation IMP
+- (void) Meth {
+ NSObject *object;
+ [object doSomethingWithNonNullPointer:NULL:1:NULL]; // expected-warning 2 {{null passed to a callee which requires a non-null argument}}
+ [object doSomethingWithNonNullPointer:vp:1:NULL]; // expected-warning {{null passed to a callee which requires a non-null argument}}
+ [NSObject doSomethingClassyWithNonNullPointer:NULL]; // expected-warning {{null passed to a callee which requires a non-null argument}}
+ DoSomethingNotNull(NULL); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ [object doSomethingWithNonNullPointer:vp:1:vp];
+}
+@end
+
diff --git a/test/SemaObjC/objc-qualified-property-lookup.m b/test/SemaObjC/objc-qualified-property-lookup.m
new file mode 100644
index 000000000000..daf583de334b
--- /dev/null
+++ b/test/SemaObjC/objc-qualified-property-lookup.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9078584
+
+@interface NSObject @end
+
+@protocol TextInput
+-editRange;
+@end
+
+@interface I {
+ NSObject<TextInput>* editor;
+}
+- (id) Meth;
+@end
+
+@implementation I
+- (id) Meth {
+ return editor.editRange;
+}
+@end
+
diff --git a/test/SemaObjC/property-13.m b/test/SemaObjC/property-13.m
index 6d56dabb9c0e..2ca341652686 100644
--- a/test/SemaObjC/property-13.m
+++ b/test/SemaObjC/property-13.m
@@ -48,7 +48,7 @@ void abort(void);
int main ()
{
Test *x = [[Test alloc] init];
- /* 1. Test of a requred property */
+ /* 1. Test of a required property */
x.required1 = 100;
if (x.required1 != 100)
abort ();
diff --git a/test/SemaObjC/property-lookup-in-id.m b/test/SemaObjC/property-lookup-in-id.m
new file mode 100644
index 000000000000..86da48e85105
--- /dev/null
+++ b/test/SemaObjC/property-lookup-in-id.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9106929
+
+typedef struct objc_class *Class;
+
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+
+typedef struct __FSEventStream* FSEventStreamRef;
+
+extern id NSApp;
+
+@interface FileSystemMonitor {
+
+ FSEventStreamRef fsEventStream;
+}
+@property(assign) FSEventStreamRef fsEventStream;
+
+@end
+
+@implementation FileSystemMonitor
+@synthesize fsEventStream;
+
+- (void)startFSEventGathering:(id)sender
+{
+ fsEventStream = [NSApp delegate].fsEventStream; // expected-warning {{warning: instance method '-delegate' not found (return type defaults to 'id')}} \
+ // expected-error {{property 'fsEventStream' not found on object of type 'id'}}
+
+}
+@end
+
diff --git a/test/SemaObjC/protocol-attribute.m b/test/SemaObjC/protocol-attribute.m
index 52c980396eda..178774c6640f 100644
--- a/test/SemaObjC/protocol-attribute.m
+++ b/test/SemaObjC/protocol-attribute.m
@@ -40,7 +40,7 @@ Class <MyProto1> clsP1 = 0; // expected-warning {{'MyProto1' is deprecated}}
__attribute ((unavailable)) __attribute ((deprecated)) @protocol XProto; // expected-note{{marked unavailable}}
-id <XProto> idX = 0; // expected-error {{'XProto' is unavailable}} expected-warning {{'XProto' is deprecated}}
+id <XProto> idX = 0; // expected-error {{'XProto' is unavailable}}
int main ()
{
diff --git a/test/SemaObjC/self-declared-in-block.m b/test/SemaObjC/self-declared-in-block.m
new file mode 100644
index 000000000000..4bd720214438
--- /dev/null
+++ b/test/SemaObjC/self-declared-in-block.m
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -fobjc-nonfragile-abi -verify %s
+// rdar://9154582
+
+@interface Blocky @end
+
+@implementation Blocky {
+ int _a;
+}
+- (void)doAThing {
+ ^{
+ char self; // expected-note {{declared here}}
+ _a; // expected-error {{instance variable '_a' cannot be accessed because 'self' has been redeclared}}
+ }();
+}
+
+@end
+
+
+// rdar://9284603
+@interface ShadowSelf
+{
+ int _anIvar;
+}
+@end
+
+@interface C {
+ int _cIvar;
+}
+@end
+
+@implementation ShadowSelf
+- (void)doSomething {
+ __typeof(self) newSelf = self;
+ {
+ __typeof(self) self = newSelf;
+ (void)_anIvar;
+ }
+ {
+ C* self; // expected-note {{declared here}}
+ (void) _anIvar; // expected-error {{instance variable '_anIvar' cannot be accessed because 'self' has been redeclared}}
+ }
+}
+- (void)doAThing {
+ ^{
+ id self; // expected-note {{declared here}}
+ (void)_anIvar; // expected-error {{instance variable '_anIvar' cannot be accessed because 'self' has been redeclared}}
+ }();
+}
+@end
+
diff --git a/test/SemaObjC/self-in-function.m b/test/SemaObjC/self-in-function.m
new file mode 100644
index 000000000000..9027a947a03c
--- /dev/null
+++ b/test/SemaObjC/self-in-function.m
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// rdar://9181463
+
+typedef struct objc_class *Class;
+
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+@interface NSObject
++ (id) alloc;
+@end
+
+
+void foo(Class self) {
+ [self alloc];
+ (^() {
+ [self alloc];
+ })();
+}
+
+void bar(Class self) {
+ Class y = self;
+ [y alloc];
+}
+
diff --git a/test/SemaObjC/sizeof-interface.m b/test/SemaObjC/sizeof-interface.m
index 9d85f1f53fcc..3fe39645fddb 100644
--- a/test/SemaObjC/sizeof-interface.m
+++ b/test/SemaObjC/sizeof-interface.m
@@ -43,7 +43,7 @@ int g2[ sizeof(I0) // expected-error {{invalid application of 'sizeof' to inte
@synthesize p0 = _p0;
@end
-typedef struct { @defs(I1) } I1_defs; // expected-error {{invalid application of @defs in non-fragile ABI}}
+typedef struct { @defs(I1); } I1_defs; // expected-error {{invalid application of @defs in non-fragile ABI}}
// FIXME: This is currently broken due to the way the record layout we
// create is tied to whether we have seen synthesized properties. Ugh.
diff --git a/test/SemaObjC/special-dep-unavail-warning.m b/test/SemaObjC/special-dep-unavail-warning.m
index b7a2d663441c..1d07a49e619d 100644
--- a/test/SemaObjC/special-dep-unavail-warning.m
+++ b/test/SemaObjC/special-dep-unavail-warning.m
@@ -27,7 +27,7 @@
@end
-@class C;
+@class C; // expected-note 5 {{forward class is declared here}}
void test(C *c) {
[c depInA]; // expected-warning {{'depInA' maybe deprecated because receiver type is unknown}}
@@ -36,10 +36,8 @@ void test(C *c) {
[c unavailMeth1]; // expected-warning {{'unavailMeth1' maybe unavailable because receiver type is unknown}}
[c depInA2]; // expected-warning {{'depInA2' maybe deprecated because receiver type is unknown}}
[c unavailMeth2]; // expected-warning {{'unavailMeth2' maybe unavailable because receiver type is unknown}}
- [c depunavailInA]; // expected-warning {{'depunavailInA' maybe deprecated because receiver type is unknown}} \
- // expected-warning {{'depunavailInA' maybe unavailable because receiver type is unknown}}
- [c depunavailInA1]; // expected-warning {{'depunavailInA1' maybe deprecated because receiver type is unknown}} \
- // expected-warning {{'depunavailInA1' maybe unavailable because receiver type is unknown}}
+ [c depunavailInA]; // expected-warning {{'depunavailInA' maybe unavailable because receiver type is unknown}}
+ [c depunavailInA1];// expected-warning {{'depunavailInA1' maybe unavailable because receiver type is unknown}}
[c FuzzyMeth]; // expected-warning {{'FuzzyMeth' maybe deprecated because receiver type is unknown}}
[c FuzzyMeth1]; // expected-warning {{'FuzzyMeth1' maybe deprecated because receiver type is unknown}}
diff --git a/test/SemaObjC/uninit-variables.m b/test/SemaObjC/uninit-variables.m
index 63c214053b00..b5c49184f4bc 100644
--- a/test/SemaObjC/uninit-variables.m
+++ b/test/SemaObjC/uninit-variables.m
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only -fblocks %s -verify
+// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -fsyntax-only -fblocks %s -verify
// Duplicated from uninit-variables.c.
// Test just to ensure the analysis is working.
int test1() {
int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization}}
- return x; // expected-warning{{variable 'x' is possibly uninitialized when used here}}
+ return x; // expected-warning{{variable 'x' is uninitialized when used here}}
}
// Test ObjC fast enumeration.
diff --git a/test/SemaObjC/unqualified-to-qualified-class-warn.m b/test/SemaObjC/unqualified-to-qualified-class-warn.m
new file mode 100644
index 000000000000..e6fa13850fbd
--- /dev/null
+++ b/test/SemaObjC/unqualified-to-qualified-class-warn.m
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://9091389
+
+@protocol Fooable
+- (void)foo;
+@end
+
+@protocol SubFooable <Fooable>
+@end
+
+@interface AClass
+@end
+
+@interface BClass : AClass <SubFooable>
+@end
+
+@implementation BClass
+- (void)foo {
+}
+@end
+
+void functionTakingAClassConformingToAProtocol(AClass <Fooable> *instance) { // expected-note {{passing argument to parameter 'instance' here}}
+}
+
+int main () {
+ AClass *aobject = 0;
+ BClass *bobject = 0;
+ functionTakingAClassConformingToAProtocol(aobject); // expected-warning {{incompatible pointer types passing 'AClass *' to parameter of type 'AClass<Fooable> *'}}
+ functionTakingAClassConformingToAProtocol(bobject); // Shouldn't warn - does implement Fooable
+ return 0;
+}
+
+// rdar://9267196
+@interface NSObject @end
+
+@protocol MyProtocol
+@end
+
+@interface MyClass : NSObject
+{
+}
+@end
+
+@implementation MyClass
+@end
+
+@interface MySubclass : MyClass <MyProtocol>
+{
+}
+@end
+
+@interface MyTestClass : NSObject
+{
+@private
+ NSObject <MyProtocol> *someObj;
+}
+
+@property (nonatomic, assign) NSObject <MyProtocol> *someObj;
+
+@end
+
+@implementation MyTestClass
+
+@synthesize someObj;
+
+- (void)someMethod
+{
+ MySubclass *foo;
+ [self setSomeObj:foo]; // no warning here!
+}
+
+@end
diff --git a/test/SemaObjC/warn-write-strings.m b/test/SemaObjC/warn-write-strings.m
index 450d0a6fe62e..163c864257e9 100644
--- a/test/SemaObjC/warn-write-strings.m
+++ b/test/SemaObjC/warn-write-strings.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
+// RUN: %clang_cc1 -verify -fsyntax-only -fconst-strings %s
// PR4804
char* x = "foo"; // expected-warning {{initializing 'char *' with an expression of type 'const char [4]' discards qualifiers}}
diff --git a/test/SemaObjC/weak-attr-ivar.m b/test/SemaObjC/weak-attr-ivar.m
index d5bbb01902db..e3d96da13bb7 100644
--- a/test/SemaObjC/weak-attr-ivar.m
+++ b/test/SemaObjC/weak-attr-ivar.m
@@ -72,3 +72,13 @@ typedef enum { Foo_HUH_NONE } FooHUHCode;
}
@end
+// rdar://problem/9123040
+@interface Test1 {
+@public
+ id ivar __attribute__((objc_gc(weak)));
+}
+@property (assign) id prop __attribute((objc_gc(weak)));
+@end
+void test1(Test1 *t) {
+ id *(__attribute__((objc_gc(strong))) x) = &t->ivar; // expected-warning {{initializing '__strong id *' with an expression of type '__weak id *' discards qualifiers}}
+}
diff --git a/test/SemaObjCXX/argument-dependent-lookup.mm b/test/SemaObjCXX/argument-dependent-lookup.mm
new file mode 100644
index 000000000000..a25cc68888d7
--- /dev/null
+++ b/test/SemaObjCXX/argument-dependent-lookup.mm
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/9142559>: For the purposes of Argument-Dependent
+// Lookup, Objective-C classes are considered to be in the global
+// namespace.
+
+@interface NSFoo
+@end
+
+template<typename T>
+void f(T t) {
+ g(t);
+}
+
+void g(NSFoo*);
+
+void test(NSFoo *foo) {
+ f(foo);
+}
diff --git a/test/SemaObjCXX/exceptions-fragile.mm b/test/SemaObjCXX/exceptions-fragile.mm
index e345ebc70b18..d1e7077089e2 100644
--- a/test/SemaObjCXX/exceptions-fragile.mm
+++ b/test/SemaObjCXX/exceptions-fragile.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
@interface NSException @end
void opaque();
diff --git a/test/SemaObjCXX/goto.mm b/test/SemaObjCXX/goto.mm
new file mode 100644
index 000000000000..67df1f4c3240
--- /dev/null
+++ b/test/SemaObjCXX/goto.mm
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR9495
+struct NonPOD { NonPOD(); ~NonPOD(); };
+
+@interface A
+@end
+
+@implementation A
+- (void)method:(bool)b {
+ NonPOD np;
+ if (b) {
+ goto undeclared; // expected-error{{use of undeclared label 'undeclared'}}
+ }
+}
+@end
diff --git a/test/SemaObjCXX/objc-pointer-conv.mm b/test/SemaObjCXX/objc-pointer-conv.mm
index 209dcfdfd705..6f59de179472 100644
--- a/test/SemaObjCXX/objc-pointer-conv.mm
+++ b/test/SemaObjCXX/objc-pointer-conv.mm
@@ -43,6 +43,6 @@ void accept_derived(DerivedFromI*);
void test_base_to_derived(I* i) {
accept_derived(i); // expected-warning{{incompatible pointer types passing 'I *' to parameter of type 'DerivedFromI *'}}
- DerivedFromI *di = i; // expected-warning{{incompatible pointer types initializing 'I *' with an expression of type 'DerivedFromI *'}}
+ DerivedFromI *di = i; // expected-warning{{incompatible pointer types initializing 'DerivedFromI *' with an expression of type 'I *'}}
DerivedFromI *di2 = (DerivedFromI *)i;
}
diff --git a/test/SemaObjCXX/overload-gc.mm b/test/SemaObjCXX/overload-gc.mm
new file mode 100644
index 000000000000..d2ddd40efb4c
--- /dev/null
+++ b/test/SemaObjCXX/overload-gc.mm
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -triple i386-apple-darwin9 -fobjc-gc -verify %s
+
+void f0(__weak id *); // expected-note{{candidate function not viable: 1st argument ('id *') has no lifetime, but parameter has __weak lifetime}}
+
+void test_f0(id *x) {
+ f0(x); // expected-error{{no matching function for call to 'f0'}}
+}
+
+@interface A
+@end
+
+void f1(__weak id*);
+void test_f1(__weak A** a) {
+ f1(a);
+}
+
+@interface B : A
+@end
+
+void f2(__weak A**);
+void test_f2(__weak B** b) {
+ f2(b);
+}
+
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index 7e79a4249cb0..960a7b228ff3 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -51,12 +51,12 @@ void test0(A* a, B* b, id val) {
}
void test1(A* a) {
- B* b = a; // expected-warning{{incompatible pointer types initializing 'A *' with an expression of type 'B *'}}
+ B* b = a; // expected-warning{{incompatible pointer types initializing 'B *' with an expression of type 'A *'}}
B *c; c = a; // expected-warning{{incompatible pointer types assigning to 'A *' from 'B *'}}
}
void test2(A** ap) {
- B** bp = ap; // expected-warning{{incompatible pointer types initializing 'A **' with an expression of type 'B **'}}
+ B** bp = ap; // expected-warning{{incompatible pointer types initializing 'B **' with an expression of type 'A **'}}
bp = ap; // expected-warning{{incompatible pointer types assigning to 'A **' from 'B **'}}
}
@@ -149,3 +149,25 @@ namespace rdar8734046 {
f2(a);
}
}
+
+namespace PR9735 {
+ int &f3(const A*);
+ float &f3(const void*);
+
+ void test_f(B* b, const B* bc) {
+ int &ir1 = f3(b);
+ int &ir2 = f3(bc);
+ }
+}
+
+@interface D : B
+@end
+
+namespace rdar9327203 {
+ int &f(void* const&, int);
+ float &f(void* const&, long);
+
+ void g(id x) {
+ int &fr = (f)(x, 0);
+ }
+}
diff --git a/test/SemaObjCXX/parameters.mm b/test/SemaObjCXX/parameters.mm
index aab1fbda4dd8..1a7869dc7a7a 100644
--- a/test/SemaObjCXX/parameters.mm
+++ b/test/SemaObjCXX/parameters.mm
@@ -10,3 +10,8 @@ struct X0 {
X0<A> x0a; // expected-note{{instantiation}}
+
+struct test2 { virtual void foo() = 0; }; // expected-note {{unimplemented}}
+@interface Test2
+- (void) foo: (test2) foo; // expected-error {{parameter type 'test2' is an abstract class}}
+@end
diff --git a/test/SemaObjCXX/propert-dot-error.mm b/test/SemaObjCXX/propert-dot-error.mm
index 47b7dc64d5cc..7a5feb42e5b1 100644
--- a/test/SemaObjCXX/propert-dot-error.mm
+++ b/test/SemaObjCXX/propert-dot-error.mm
@@ -39,3 +39,14 @@ void g(B *b) {
b.value.staticData = 17;
b.value.method();
}
+
+@interface C
+@end
+
+@implementation C
+- (void)method:(B *)b {
+ // <rdar://problem/8985943>
+ b.operator+ = 17; // expected-error{{'operator+' is not a valid property name (accessing an object of type 'B *')}}
+ b->operator+ = 17; // expected-error{{'B' does not have a member named 'operator+'}}
+}
+@end
diff --git a/test/SemaObjCXX/property-reference.mm b/test/SemaObjCXX/property-reference.mm
new file mode 100644
index 000000000000..5dc8061de70b
--- /dev/null
+++ b/test/SemaObjCXX/property-reference.mm
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s
+// rdar://9070460
+
+class TCPPObject
+{
+public:
+ TCPPObject(const TCPPObject& inObj);
+ TCPPObject();
+ ~TCPPObject();
+
+ TCPPObject& operator=(const TCPPObject& inObj)const ;
+
+ void* Data();
+
+private:
+ void* fData;
+};
+
+
+typedef const TCPPObject& CREF_TCPPObject;
+
+@interface TNSObject
+@property (assign, readwrite, nonatomic) CREF_TCPPObject cppObjectNonAtomic;
+@property (assign, readwrite) CREF_TCPPObject cppObjectAtomic;
+@property (assign, readwrite, nonatomic) const TCPPObject& cppObjectDynamic;
+@end
+
+
+@implementation TNSObject
+
+@synthesize cppObjectNonAtomic;
+@synthesize cppObjectAtomic;
+@dynamic cppObjectDynamic;
+
+- (const TCPPObject&) cppObjectNonAtomic
+{
+ return cppObjectNonAtomic;
+}
+
+- (void) setCppObjectNonAtomic: (const TCPPObject&)cppObject
+{
+ cppObjectNonAtomic = cppObject;
+}
+@end
diff --git a/test/SemaObjCXX/references.mm b/test/SemaObjCXX/references.mm
index 15033f6bde8d..3a522005abee 100644
--- a/test/SemaObjCXX/references.mm
+++ b/test/SemaObjCXX/references.mm
@@ -9,7 +9,7 @@ typedef struct {
@interface A
@property (assign) T p0;
-@property (assign) T& p1; // expected-error {{property of reference type is not supported}}
+@property (assign) T& p1;
@end
int f0(const T& t) {
@@ -21,7 +21,7 @@ int f1(A *a) {
}
int f2(A *a) {
- return f0(a.p1); // expected-error {{property 'p1' not found on object of type 'A *'}}
+ return f0(a.p1);
}
// PR7740
@@ -37,7 +37,7 @@ void f4(NSString &tmpstr) {
@protocol P2 @end
@protocol P3 @end
@interface foo<P1> {} @end
-@interface bar : foo <P1, P2> {} @end
+@interface bar : foo <P1, P2, P3> {} @end
typedef bar baz;
struct ToBar {
diff --git a/test/SemaOpenCL/extension-fp64.cl b/test/SemaOpenCL/extension-fp64.cl
index eaf2509502f2..e0c2b1ea4b53 100644
--- a/test/SemaOpenCL/extension-fp64.cl
+++ b/test/SemaOpenCL/extension-fp64.cl
@@ -1,17 +1,19 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
-void f1(double da) { // expected-error {{requires cl_khr_fp64 extension}}
- double d; // expected-error {{requires cl_khr_fp64 extension}}
+void f1(double da) { // expected-error {{type 'double' requires cl_khr_fp64 extension}}
+ double d; // expected-error {{type 'double' requires cl_khr_fp64 extension}}
+ (void) 1.0; // expected-warning {{double precision constant requires cl_khr_fp64}}
}
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
void f2(void) {
double d;
+ (void) 1.0;
}
#pragma OPENCL EXTENSION cl_khr_fp64 : disable
void f3(void) {
- double d; // expected-error {{requires cl_khr_fp64 extension}}
+ double d; // expected-error {{type 'double' requires cl_khr_fp64 extension}}
}
diff --git a/test/SemaOpenCL/vec_step.cl b/test/SemaOpenCL/vec_step.cl
new file mode 100644
index 000000000000..d83ebf11fe03
--- /dev/null
+++ b/test/SemaOpenCL/vec_step.cl
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+
+typedef int int2 __attribute__((ext_vector_type(2)));
+typedef int int3 __attribute__((ext_vector_type(3)));
+typedef int int4 __attribute__((ext_vector_type(4)));
+typedef int int8 __attribute__((ext_vector_type(8)));
+typedef int int16 __attribute__((ext_vector_type(16)));
+
+void foo(int3 arg1, int8 arg2) {
+ int4 auto1;
+ int16 *auto2;
+ int auto3;
+ int2 auto4;
+ struct S *incomplete1;
+
+ int res1[vec_step(arg1) == 4 ? 1 : -1];
+ int res2[vec_step(arg2) == 8 ? 1 : -1];
+ int res3[vec_step(auto1) == 4 ? 1 : -1];
+ int res4[vec_step(*auto2) == 16 ? 1 : -1];
+ int res5[vec_step(auto3) == 1 ? 1 : -1];
+ int res6[vec_step(auto4) == 2 ? 1 : -1];
+ int res7[vec_step(int2) == 2 ? 1 : -1];
+ int res8[vec_step(int3) == 4 ? 1 : -1];
+ int res9[vec_step(int4) == 4 ? 1 : -1];
+ int res10[vec_step(int8) == 8 ? 1 : -1];
+ int res11[vec_step(int16) == 16 ? 1 : -1];
+ int res12[vec_step(void) == 1 ? 1 : -1];
+
+ int res13 = vec_step(*incomplete1); // expected-error {{'vec_step' requires built-in scalar or vector type, 'struct S' invalid}}
+ int res14 = vec_step(int16*); // expected-error {{'vec_step' requires built-in scalar or vector type, 'int16 *' invalid}}
+ int res15 = vec_step(void(void)); // expected-error {{'vec_step' requires built-in scalar or vector type, 'void (void)' invalid}}
+}
diff --git a/test/SemaTemplate/address-spaces.cpp b/test/SemaTemplate/address-spaces.cpp
new file mode 100644
index 000000000000..eda03dbac2bd
--- /dev/null
+++ b/test/SemaTemplate/address-spaces.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T, typename U>
+struct is_same {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+typedef int __attribute__((address_space(1))) int_1;;
+typedef int __attribute__((address_space(2))) int_2;;
+typedef int __attribute__((address_space(1))) *int_1_ptr;
+typedef int_2 *int_2_ptr;
+
+// Check that we maintain address spaces through template argument
+// deduction from a type.
+template<typename T>
+struct remove_pointer {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_pointer<T *> {
+ typedef T type;
+};
+
+int check_remove0[is_same<remove_pointer<int_1_ptr>::type, int_1>::value? 1 : -1];
+int check_remove1[is_same<remove_pointer<int_2_ptr>::type, int_2>::value? 1 : -1];
+int check_remove2[is_same<remove_pointer<int_2_ptr>::type, int>::value? -1 : 1];
+int check_remove3[is_same<remove_pointer<int_2_ptr>::type, int_1>::value? -1 : 1];
+
+template<typename T>
+struct is_pointer_in_address_space_1 {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_pointer_in_address_space_1<T __attribute__((address_space(1))) *> {
+ static const bool value = true;
+};
+
+int check_ptr_in_as1[is_pointer_in_address_space_1<int_1_ptr>::value? 1 : -1];
+int check_ptr_in_as2[is_pointer_in_address_space_1<int_2_ptr>::value? -1 : 1];
+int check_ptr_in_as3[is_pointer_in_address_space_1<int*>::value? -1 : 1];
+
+// Check that we maintain address spaces through template argument
+// deduction for a call.
+template<typename T>
+void accept_any_pointer(T*) {
+ T *x = 1; // expected-error{{cannot initialize a variable of type '__attribute__((address_space(1))) int *' with an rvalue of type 'int'}} \
+ // expected-error{{cannot initialize a variable of type '__attribute__((address_space(3))) int *' with an rvalue of type 'int'}}
+}
+
+void test_accept_any_pointer(int_1_ptr ip1, int_2_ptr ip2) {
+ static __attribute__((address_space(3))) int array[17];
+ accept_any_pointer(ip1); // expected-note{{in instantiation of}}
+ accept_any_pointer(array); // expected-note{{in instantiation of}}
+}
+
+template<typename T> struct identity {};
+
+template<typename T>
+identity<T> accept_arg_in_address_space_1(__attribute__((address_space(1))) T &ir1);
+
+template<typename T>
+identity<T> accept_any_arg(T &ir1);
+
+void test_arg_in_address_space_1() {
+ static int __attribute__((address_space(1))) int_1;
+ identity<int> ii = accept_arg_in_address_space_1(int_1);
+ identity<int __attribute__((address_space(1)))> ii2 = accept_any_arg(int_1);
+}
+
+// Partial ordering
+template<typename T> int &order1(__attribute__((address_space(1))) T&);
+template<typename T> float &order1(T&);
+
+void test_order1() {
+ static __attribute__((address_space(1))) int i1;
+ int i;
+ int &ir = order1(i1);
+ float &fr = order1(i);
+}
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index 8f4b7281818d..ec97311e5d72 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -4,7 +4,7 @@
// Note that the error count below doesn't matter. We just want to
// make sure that the parser doesn't crash.
-// CHECK: 15 errors
+// CHECK: 13 errors
template<a>
struct int_;
diff --git a/test/SemaTemplate/dependent-template-recover.cpp b/test/SemaTemplate/dependent-template-recover.cpp
index e91ffb52539c..3c01f6586b01 100644
--- a/test/SemaTemplate/dependent-template-recover.cpp
+++ b/test/SemaTemplate/dependent-template-recover.cpp
@@ -16,3 +16,45 @@ struct X {
(*t).f2<0>(); // expected-error{{expected expression}}
}
};
+
+namespace PR9401 {
+ // From GCC PR c++/45558
+ template <typename S, typename T>
+ struct C
+ {
+ template <typename U>
+ struct B
+ {
+ template <typename W>
+ struct E
+ {
+ explicit E(const W &x) : w(x) {}
+ const W &w;
+ };
+ };
+ };
+
+ struct F;
+ template <typename X>
+ struct D
+ {
+ D() {}
+ };
+
+ const D<F> g;
+ template <typename S, typename T>
+ struct A
+ {
+ template <typename U>
+ struct B : C<S, T>::template B<U>
+ {
+ typedef typename C<S, T>::template B<U> V;
+ static const D<typename V::template E<D<F> > > a;
+ };
+ };
+
+ template <typename S, typename T>
+ template <typename U>
+ const D<typename C<S, T>::template B<U>::template E<D<F> > >
+ A<S, T>::B<U>::a = typename C<S, T>::template B<U>::template E<D<F> >(g);
+}
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
index 6fe7f69cdd5f..07beda40aaa7 100644
--- a/test/SemaTemplate/destructor-template.cpp
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -50,3 +50,10 @@ namespace PR7239 {
}
};
}
+
+namespace PR7904 {
+ struct Foo {
+ template <int i> ~Foo() {} // expected-error{{destructor cannot be declared as a template}}
+ };
+ Foo f;
+}
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index ffec3c2b97f0..63016fd71568 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -88,15 +88,12 @@ template<typename> struct X3 { };
inline template struct X3<int>; // expected-warning{{ignoring 'inline' keyword on explicit template instantiation}}
static template struct X3<float>; // expected-warning{{ignoring 'static' keyword on explicit template instantiation}}
-namespace PR7622 { // expected-note{{to match this}}
+namespace PR7622 {
template<typename,typename=int>
struct basic_streambuf;
- // FIXME: Very poor recovery here.
template<typename,typename>
struct basic_streambuf{friend bob<>()}; // expected-error{{unknown type name 'bob'}} \
// expected-error{{ expected member name or ';' after declaration specifiers}}
- template struct basic_streambuf<int>; // expected-error{{explicit instantiation of 'basic_streambuf' in class scope}}
-} // expected-error{{expected ';' after struct}}
-
-//expected-error{{expected '}'}}
+ template struct basic_streambuf<int>;
+}
diff --git a/test/SemaTemplate/instantiate-cast.cpp b/test/SemaTemplate/instantiate-cast.cpp
index abf1b3c31d74..b3babf12981e 100644
--- a/test/SemaTemplate/instantiate-cast.cpp
+++ b/test/SemaTemplate/instantiate-cast.cpp
@@ -63,7 +63,7 @@ template struct DynamicCast0<Base*, A>; // expected-note{{instantiation}}
template<typename T, typename U>
struct ReinterpretCast0 {
void f(T t) {
- (void)reinterpret_cast<U>(t); // expected-error{{constness}}
+ (void)reinterpret_cast<U>(t); // expected-error{{qualifiers}}
}
};
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index 74eb5e5fff3d..521d2180d7ab 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
// ---------------------------------------------------------------------
// C++ Functional Casts
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index dbd1e6930382..688d0095267a 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
template<typename T, typename U>
struct X0 {
void f(T x, U y) {
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index f1bdf3e1e6d5..74c2609dcd0f 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -1,5 +1,28 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+namespace PR8965 {
+ template<typename T>
+ struct X {
+ typedef int type;
+
+ T field; // expected-note{{in instantiation of member class}}
+ };
+
+ template<typename T>
+ struct Y {
+ struct Inner;
+
+ typedef typename X<Inner>::type // expected-note{{in instantiation of template class}}
+ type; // expected-note{{not-yet-instantiated member is declared here}}
+
+ struct Inner {
+ typedef type field; // expected-error{{no member 'type' in 'PR8965::Y<int>'; it has not yet been instantiated}}
+ };
+ };
+
+ Y<int> y; // expected-note{{in instantiation of template class}}
+}
+
template<typename T>
class X {
public:
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
index e2f72756189c..4c74f5fb938b 100644
--- a/test/SemaTemplate/instantiate-member-template.cpp
+++ b/test/SemaTemplate/instantiate-member-template.cpp
@@ -215,3 +215,47 @@ namespace PR8489 {
c.F(); // expected-error{{no matching member function}}
}
}
+
+namespace rdar8986308 {
+ template <bool> struct __static_assert_test;
+ template <> struct __static_assert_test<true> {};
+ template <unsigned> struct __static_assert_check {};
+
+ namespace std {
+
+ template <class _Tp, class _Up>
+ struct __has_rebind
+ {
+ private:
+ struct __two {char _; char __;};
+ template <class _Xp> static __two __test(...);
+ template <class _Xp> static char __test(typename _Xp::template rebind<_Up>* = 0);
+ public:
+ static const bool value = sizeof(__test<_Tp>(0)) == 1;
+ };
+
+ }
+
+ template <class T> struct B1 {};
+
+ template <class T>
+ struct B
+ {
+ template <class U> struct rebind {typedef B1<U> other;};
+ };
+
+ template <class T, class U> struct D1 {};
+
+ template <class T, class U>
+ struct D
+ {
+ template <class V> struct rebind {typedef D1<V, U> other;};
+ };
+
+ int main()
+ {
+ typedef __static_assert_check<sizeof(__static_assert_test<((std::__has_rebind<B<int>, double>::value))>)> __t64;
+ typedef __static_assert_check<sizeof(__static_assert_test<((std::__has_rebind<D<char, int>, double>::value))>)> __t64;
+ }
+
+}
diff --git a/test/SemaTemplate/instantiate-try-catch.cpp b/test/SemaTemplate/instantiate-try-catch.cpp
index f1ffd06334c3..1c6c26f2586e 100644
--- a/test/SemaTemplate/instantiate-try-catch.cpp
+++ b/test/SemaTemplate/instantiate-try-catch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fexceptions -fsyntax-only -std=c++0x -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -std=c++0x -verify %s
template<typename T> struct TryCatch0 {
void f() {
diff --git a/test/SemaTemplate/issue150.cpp b/test/SemaTemplate/issue150.cpp
new file mode 100644
index 000000000000..af3b93c907c1
--- /dev/null
+++ b/test/SemaTemplate/issue150.cpp
@@ -0,0 +1,107 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Core issue 150: Template template parameters and default arguments
+
+template<typename T, typename U>
+struct is_same {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+namespace PR9353 {
+ template<class _T, class Traits> class IM;
+
+ template <class T, class Trt,
+ template<class _T, class Traits = int> class IntervalMap>
+ void foo(IntervalMap<T,Trt>* m) { typedef IntervalMap<int> type; }
+
+ void f(IM<int, int>* m) { foo(m); }
+}
+
+namespace PR9400 {
+ template<template <typename T, typename = T > class U> struct A
+ {
+ template<int> U<int> foo();
+ };
+
+ template <typename T, typename = T>
+ struct s {
+ };
+
+ void f() {
+ A<s> x;
+ x.foo<2>();
+ }
+}
+
+namespace MultiReplace {
+ template<typename Z,
+ template<typename T, typename U = T *, typename V = U const> class TT>
+ struct X {
+ typedef TT<Z> type;
+ };
+
+ template<typename T, typename = int, typename = float>
+ struct Y { };
+
+ int check0[is_same<X<int, Y>::type, Y<int, int*, int* const> >::value? 1 : -1];
+}
+
+namespace MultiReplacePartial {
+ template<typename First, typename Z,
+ template<typename T, typename U = T *, typename V = U const> class TT>
+ struct X {
+ typedef TT<Z> type;
+ };
+
+ template<typename Z,
+ template<typename T, typename U = T *, typename V = U const> class TT>
+ struct X<int, Z, TT> {
+ typedef TT<Z> type;
+ };
+
+ template<typename T, typename = int, typename = float>
+ struct Y { };
+
+ int check0[is_same<X<int, int, Y>::type, Y<int, int*, int* const> >::value? 1 : -1];
+}
+
+namespace PR9016 {
+ template<typename > struct allocator ;
+ template<typename > struct less ;
+
+ template<class T, template<class> class Compare, class Default,
+ template<class> class Alloc>
+ struct interval_set { };
+
+ template <class X, template<class> class = less> struct interval_type_default {
+ typedef X type;
+ };
+
+ template <class T,
+ template<class _T, template<class> class Compare = PR9016::less,
+ class = typename interval_type_default<_T,Compare>::type,
+ template<class> class = allocator> class IntervalSet>
+ struct ZZZ
+ {
+ IntervalSet<T> IntervalSetT;
+ };
+
+ template <class T,
+ template<class _T, template<class> class Compare = PR9016::less,
+ class = typename interval_type_default<_T,Compare>::type,
+ template<class> class = allocator> class IntervalSet>
+ void int40()
+ {
+ IntervalSet<T> IntervalSetT;
+ }
+
+ void test() {
+ ZZZ<int, interval_set> zzz;
+ int40<int, interval_set>();
+ }
+}
diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp
index 9c72845fb6a6..635687d4f6b7 100644
--- a/test/SemaTemplate/nested-name-spec-template.cpp
+++ b/test/SemaTemplate/nested-name-spec-template.cpp
@@ -99,3 +99,44 @@ namespace PR7725 {
}
};
}
+
+namespace PR9226 {
+ template<typename a>
+ void nt() // expected-note{{function template 'nt' declared here}}
+ { nt<>:: } // expected-error{{qualified name refers into a specialization of function template 'nt'}} \
+ // expected-error{{expected unqualified-id}}
+
+ template<typename T>
+ void f(T*); // expected-note{{function template 'f' declared here}}
+
+ template<typename T>
+ void f(T*, T*); // expected-note{{function template 'f' declared here}}
+
+ void g() {
+ f<int>:: // expected-error{{qualified name refers into a specialization of function template 'f'}}
+ } // expected-error{{expected unqualified-id}}
+
+ struct X {
+ template<typename T> void f(); // expected-note{{function template 'f' declared here}}
+ };
+
+ template<typename T, typename U>
+ struct Y {
+ typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::f'}}
+ };
+
+ Y<X, int> yxi; // expected-note{{in instantiation of template class 'PR9226::Y<PR9226::X, int>' requested here}}
+}
+
+namespace PR9449 {
+ template <typename T>
+ struct s; // expected-note{{template is declared here}}
+
+ template <typename T>
+ void f() {
+ int s<T>::template n<T>::* f; // expected-error{{implicit instantiation of undefined template 'PR9449::s<int>'}} \
+ // expected-error{{following the 'template' keyword}}
+ }
+
+ template void f<int>(); // expected-note{{in instantiation of}}
+}
diff --git a/test/SemaTemplate/resolve-single-template-id.cpp b/test/SemaTemplate/resolve-single-template-id.cpp
new file mode 100644
index 000000000000..ef0a76307670
--- /dev/null
+++ b/test/SemaTemplate/resolve-single-template-id.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+namespace std {
+ class type_info {};
+}
+
+void one() { }
+void two() { } // expected-note 3{{candidate}}
+void two(int) { } // expected-note 3{{candidate}}
+
+template<class T> void twoT() { } // expected-note 5{{candidate}}
+template<class T> void twoT(int) { } // expected-note 5{{candidate}}
+
+template<class T> void oneT() { }
+template<class T, class U> void oneT(U) { }
+/*
+The target can be
+ an object or reference being initialized (8.5, 8.5.3),
+ the left side of an assignment (5.17),
+ a parameter of a function (5.2.2),
+ a parameter of a user-defined operator (13.5),
+ the return value of a function, operator function, or conversion (6.6.3),
+ an explicit type conversion (5.2.3, 5.2.9, 5.4), or
+ a non-type template-parameter (14.3.2)
+*/
+//#include <typeinfo>
+template<void (*p)(int)> struct test { };
+
+int main()
+{
+ one; // expected-warning {{expression result unused}}
+ two; // expected-error {{cannot resolve overloaded function 'two' from context}}
+ oneT<int>; // expected-warning {{expression result unused}}
+ twoT<int>; // expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ typeid(oneT<int>); // expected-warning{{expression result unused}}
+ sizeof(oneT<int>); // expected-warning {{expression result unused}}
+ sizeof(twoT<int>); //expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ decltype(oneT<int>)* fun = 0;
+
+ *one; // expected-warning {{expression result unused}}
+ *oneT<int>; // expected-warning {{expression result unused}}
+ *two; //expected-error {{cannot resolve overloaded function 'two' from context}}
+ *twoT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ !oneT<int>; // expected-warning {{expression result unused}}
+ +oneT<int>; // expected-warning {{expression result unused}}
+ -oneT<int>; //expected-error {{invalid argument type}}
+ oneT<int> == 0; // expected-warning {{expression result unused}}
+ 0 == oneT<int>; // expected-warning {{expression result unused}}
+ 0 != oneT<int>; // expected-warning {{expression result unused}}
+ (false ? one : oneT<int>); // expected-warning {{expression result unused}}
+ void (*p1)(int); p1 = oneT<int>;
+
+ int i = (int) (false ? (void (*)(int))twoT<int> : oneT<int>); //expected-error {{incompatible operand}}
+ (twoT<int>) == oneT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ bool b = oneT<int>;
+ void (*p)() = oneT<int>;
+ test<oneT<int> > ti;
+ void (*u)(int) = oneT<int>;
+
+ b = (void (*)()) twoT<int>;
+
+ one < one; //expected-warning {{self-comparison always evaluates to false}} \
+ //expected-warning {{expression result unused}}
+
+ oneT<int> < oneT<int>; //expected-warning {{self-comparison always evaluates to false}} \
+ //expected-warning {{expression result unused}}
+
+ two < two; //expected-error {{cannot resolve overloaded function 'two' from context}}
+ twoT<int> < twoT<int>; //expected-error {{cannot resolve overloaded function 'twoT' from context}}
+ oneT<int> == 0; // expected-warning {{expression result unused}}
+
+}
+
+struct rdar9108698 {
+ template<typename> void f();
+};
+
+void test_rdar9108698(rdar9108698 x) {
+ x.f<int>; // expected-error{{a bound member function may only be called}}
+}
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
index 944acacd8441..9c34089e61f7 100644
--- a/test/SemaTemplate/temp_arg_template.cpp
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -30,9 +30,12 @@ template<typename T> void f(int);
A<f> *a9; // expected-error{{must be a class template}}
-// FIXME: The code below is ill-formed, because of the evil digraph '<:'.
-// We should provide a much better error message than we currently do.
-// A<::N::Z> *a10;
+// Evil digraph '<:' is parsed as '[', expect error.
+A<::N::Z> *a10; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}}
+
+// Do not do a digraph correction here.
+A<: :N::Z> *a11; // expected-error{{expected expression}} \
+ expected-error{{C++ requires a type specifier for all declarations}}
// PR7807
namespace N {
diff --git a/test/SemaTemplate/typename-specifier-4.cpp b/test/SemaTemplate/typename-specifier-4.cpp
index 38045e0a31bf..44cf966e33b5 100644
--- a/test/SemaTemplate/typename-specifier-4.cpp
+++ b/test/SemaTemplate/typename-specifier-4.cpp
@@ -154,3 +154,11 @@ namespace rdar8740998 {
xi.f();
}
}
+
+namespace rdar9068589 {
+ // From GCC PR c++/13950
+ template <class T> struct Base {};
+ template <class T> struct Derived: public Base<T> {
+ typename Derived::template Base<double>* p1;
+ };
+}
diff --git a/test/lit.cfg b/test/lit.cfg
index 6567c6d229cb..4b9d529b7d26 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -24,7 +24,8 @@ if platform.system() == 'Windows':
#
# For now we require '&&' between commands, until they get globally killed and
# the test runner updated.
-execute_external = platform.system() != 'Windows'
+execute_external = (platform.system() != 'Windows'
+ or lit.getBashPath() not in [None, ""])
config.test_format = lit.formats.ShTest(execute_external)
# suffixes: A list of file extensions to treat as test files.
@@ -137,7 +138,7 @@ def inferClang(PATH):
if lit.useValgrind:
config.target_triple += '-vg'
-config.clang = inferClang(config.environment['PATH'])
+config.clang = inferClang(config.environment['PATH']).replace('\\', '/')
if not lit.quiet:
lit.note('using clang: %r' % config.clang)
config.substitutions.append( ('%clang_cc1', config.clang + ' -cc1') )
@@ -166,3 +167,7 @@ config.substitutions.append(
# Set available features we allow tests to conditionalize on.
if platform.system() != 'Windows':
config.available_features.add('crash-recovery')
+
+# Shell execution
+if platform.system() not in ['Windows'] or lit.getBashPath() != '':
+ config.available_features.add('shell')
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 3d9849a3a401..68064041f435 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -13,6 +13,9 @@ TOOLNAME = c-index-test
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
+# Don't install this. It is used for tests.
+NO_INSTALL = 1
+
LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a clangAnalysis.a \
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index d4e567d9e26a..f7b7a367cfd6 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -370,6 +370,23 @@ void PrintDiagnostics(CXTranslationUnit TU) {
}
}
+void PrintMemoryUsage(CXTranslationUnit TU) {
+ unsigned long total = 0.0;
+ unsigned i = 0;
+ CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
+ fprintf(stderr, "Memory usage:\n");
+ for (i = 0 ; i != usage.numEntries; ++i) {
+ const char *name = clang_getTUResourceUsageName(usage.entries[i].kind);
+ unsigned long amount = usage.entries[i].amount;
+ total += amount;
+ fprintf(stderr, " %s : %ld bytes (%f MBytes)\n", name, amount,
+ ((double) amount)/(1024*1024));
+ }
+ fprintf(stderr, " TOTAL = %ld bytes (%f MBytes)\n", total,
+ ((double) total)/(1024*1024));
+ clang_disposeCXTUResourceUsage(usage);
+}
+
/******************************************************************************/
/* Logic for testing traversal. */
/******************************************************************************/
@@ -990,7 +1007,7 @@ void print_completion_result(CXCompletionResult *completion_result,
int my_stricmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
- int c1 = tolower(*s1), c2 = tolower(*s2);
+ int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2);
if (c1 < c2)
return -1;
else if (c1 > c2)
@@ -1503,6 +1520,8 @@ static CXCursorVisitor GetVisitor(const char *s) {
return FilteredPrintingVisitor;
if (strcmp(s, "-usrs") == 0)
return USRVisitor;
+ if (strncmp(s, "-memory-usage", 13) == 0)
+ return GetVisitor(s + 13);
return NULL;
}
@@ -1519,16 +1538,20 @@ static void print_usage(void) {
"[FileCheck prefix]\n"
" c-index-test -test-load-source <symbol filter> {<args>}*\n");
fprintf(stderr,
+ " c-index-test -test-load-source-memory-usage "
+ "<symbol filter> {<args>}*\n"
" c-index-test -test-load-source-reparse <trials> <symbol filter> "
" {<args>}*\n"
" c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
+ " c-index-test -test-load-source-usrs-memory-usage "
+ "<symbol filter> {<args>}*\n"
" c-index-test -test-annotate-tokens=<range> {<args>}*\n"
" c-index-test -test-inclusion-stack-source {<args>}*\n"
- " c-index-test -test-inclusion-stack-tu <AST file>\n"
+ " c-index-test -test-inclusion-stack-tu <AST file>\n");
+ fprintf(stderr,
" c-index-test -test-print-linkage-source {<args>}*\n"
" c-index-test -test-print-typekind {<args>}*\n"
- " c-index-test -print-usr [<CursorKind> {<args>}]*\n");
- fprintf(stderr,
+ " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n"
" c-index-test -write-pch <file> <compiler arguments>\n\n");
fprintf(stderr,
@@ -1569,8 +1592,14 @@ int cindextest_main(int argc, const char **argv) {
}
else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 17);
+
+ PostVisitTU postVisit = 0;
+ if (strstr(argv[1], "-memory-usage"))
+ postVisit = PrintMemoryUsage;
+
if (I)
- return perform_test_load_source(argc - 3, argv + 3, argv[2], I, NULL);
+ return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
+ postVisit);
}
else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
return perform_file_scan(argv[2], argv[3],
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 552e7a534427..0c41490175e9 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -23,6 +23,7 @@ set( LLVM_LINK_COMPONENTS
bitreader
bitwriter
codegen
+ instrumentation
ipo
selectiondag
)
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index d96f9505ffe5..abe70983df42 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -36,7 +36,7 @@ TOOL_INFO_PLIST := Info.plist
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
- ipo selectiondag
+ instrumentation ipo selectiondag
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 7fb394fa5b01..535eaa9c96f8 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -168,7 +168,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// When running with -disable-free, don't do any destruction or shutdown.
if (Clang->getFrontendOpts().DisableFree) {
- if (Clang->getFrontendOpts().ShowStats)
+ if (llvm::AreStatisticsEnabled() || Clang->getFrontendOpts().ShowStats)
llvm::PrintStatistics();
Clang.take();
return !Success;
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 1d544f3d3c9d..ec6ce65a9b8b 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -71,6 +71,7 @@ struct AssemblerInvocation {
std::vector<std::string> IncludePaths;
unsigned NoInitialTextSection : 1;
+ unsigned SaveTemporaryLabels : 1;
/// @}
/// @name Frontend Options
@@ -156,6 +157,7 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Language Options
Opts.IncludePaths = Args->getAllArgValues(OPT_I);
Opts.NoInitialTextSection = Args->hasArg(OPT_n);
+ Opts.SaveTemporaryLabels = Args->hasArg(OPT_L);
// Frontend Options
if (Args->hasArg(OPT_INPUT)) {
@@ -265,6 +267,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
const TargetAsmInfo *tai = new TargetAsmInfo(*TM);
MCContext Ctx(*MAI, tai);
+ if (Opts.SaveTemporaryLabels)
+ Ctx.setAllowTemporaryLabels(false);
OwningPtr<MCStreamer> Str;
@@ -275,7 +279,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI);
+ TheTarget->createMCInstPrinter(*TM, Opts.OutputAsmVariant, *MAI);
MCCodeEmitter *CE = 0;
TargetAsmBackend *TAB = 0;
if (Opts.ShowEncoding) {
@@ -283,7 +287,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) {
TAB = TheTarget->createAsmBackend(Opts.Triple);
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
- /*useLoc*/ true, IP, CE, TAB,
+ /*useLoc*/ true,
+ /*useCFI*/ true, IP, CE, TAB,
Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx));
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 0b5d2c97a4e7..db72da42ea34 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -18,6 +18,7 @@
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/OwningPtr.h"
@@ -35,6 +36,8 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Target/TargetSelect.h"
#include <cctype>
using namespace clang;
using namespace clang::driver;
@@ -252,6 +255,85 @@ static void ExpandArgv(int argc, const char **argv,
}
}
+static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector,
+ std::set<std::string> &SavedStrings,
+ Driver &TheDriver)
+{
+ // Try to infer frontend type and default target from the program name.
+
+ // suffixes[] contains the list of known driver suffixes.
+ // Suffixes are compared against the program name in order.
+ // If there is a match, the frontend type is updated as necessary (CPP/C++).
+ // If there is no match, a second round is done after stripping the last
+ // hyphen and everything following it. This allows using something like
+ // "clang++-2.9".
+
+ // If there is a match in either the first or second round,
+ // the function tries to identify a target as prefix. E.g.
+ // "x86_64-linux-clang" as interpreted as suffix "clang" with
+ // target prefix "x86_64-linux". If such a target prefix is found,
+ // is gets added via -ccc-host-triple as implicit first argument.
+ static const struct {
+ const char *Suffix;
+ bool IsCXX;
+ bool IsCPP;
+ } suffixes [] = {
+ { "clang", false, false },
+ { "clang++", true, false },
+ { "clang-c++", true, false },
+ { "clang-cc", false, false },
+ { "clang-cpp", false, true },
+ { "clang-g++", true, false },
+ { "clang-gcc", false, false },
+ { "cc", false, false },
+ { "cpp", false, true },
+ { "++", true, false },
+ };
+ std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+ llvm::StringRef ProgNameRef(ProgName);
+ llvm::StringRef Prefix;
+
+ for (int Components = 2; Components; --Components) {
+ bool FoundMatch = false;
+ size_t i;
+
+ for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
+ if (ProgNameRef.endswith(suffixes[i].Suffix)) {
+ FoundMatch = true;
+ if (suffixes[i].IsCXX)
+ TheDriver.CCCIsCXX = true;
+ if (suffixes[i].IsCPP)
+ TheDriver.CCCIsCPP = true;
+ break;
+ }
+ }
+
+ if (FoundMatch) {
+ llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-',
+ ProgNameRef.size() - strlen(suffixes[i].Suffix));
+ if (LastComponent != llvm::StringRef::npos)
+ Prefix = ProgNameRef.slice(0, LastComponent);
+ break;
+ }
+
+ llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-');
+ if (LastComponent == llvm::StringRef::npos)
+ break;
+ ProgNameRef = ProgNameRef.slice(0, LastComponent);
+ }
+
+ if (Prefix.empty())
+ return;
+
+ std::string IgnoredError;
+ if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
+ ArgVector.insert(&ArgVector[1],
+ SaveStringInSet(SavedStrings, Prefix));
+ ArgVector.insert(&ArgVector[1],
+ SaveStringInSet(SavedStrings, std::string("-ccc-host-triple")));
+ }
+}
+
int main(int argc_, const char **argv_) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc_, argv_);
@@ -328,19 +410,8 @@ int main(int argc_, const char **argv_) {
TheDriver.setInstalledDir(InstalledPath);
}
- // Check for ".*++" or ".*++-[^-]*" to determine if we are a C++
- // compiler. This matches things like "c++", "clang++", and "clang++-1.1".
- //
- // Note that we intentionally want to use argv[0] here, to support "clang++"
- // being a symlink.
- //
- // We use *argv instead of argv[0] to work around a bogus g++ warning.
- const char *progname = argv_[0];
- std::string ProgName(llvm::sys::path::stem(progname));
- if (llvm::StringRef(ProgName).endswith("++") ||
- llvm::StringRef(ProgName).rsplit('-').first.endswith("++")) {
- TheDriver.CCCIsCXX = true;
- }
+ llvm::InitializeAllTargets();
+ ParseProgName(argv, SavedStrings, TheDriver);
// Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
@@ -352,6 +423,11 @@ int main(int argc_, const char **argv_) {
if (TheDriver.CCPrintHeaders)
TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
+ // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
+ TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
+ if (TheDriver.CCLogDiagnostics)
+ TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
+
// Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a
// command line behind the scenes.
if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) {
@@ -378,8 +454,7 @@ int main(int argc_, const char **argv_) {
argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end());
}
- llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv.size(),
- &argv[0]));
+ llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 0;
if (C.get())
Res = TheDriver.ExecuteCompilation(*C);
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index cd1b8d66673a..28f1506988e1 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -34,6 +34,7 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -115,7 +116,7 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
// location accordingly.
SourceLocation EndLoc = R.getEnd();
if (EndLoc.isValid() && EndLoc.isMacroID())
- EndLoc = SM.getSpellingLoc(EndLoc);
+ EndLoc = SM.getInstantiationRange(EndLoc).second;
if (R.isTokenRange() && !EndLoc.isInvalid() && EndLoc.isFileID()) {
unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
EndLoc = EndLoc.getFileLocWithOffset(Length);
@@ -187,6 +188,10 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
// be suppressed.
unsigned MaxPCHLevel;
+ /// \brief Whether we should visit the preprocessing record entries last,
+ /// after visiting other declarations.
+ bool VisitPreprocessorLast;
+
/// \brief When valid, a source range to which the cursor should restrict
/// its search.
SourceRange RegionOfInterest;
@@ -234,11 +239,12 @@ public:
CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor,
CXClientData ClientData,
unsigned MaxPCHLevel,
+ bool VisitPreprocessorLast,
SourceRange RegionOfInterest = SourceRange())
: TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
Visitor(Visitor), ClientData(ClientData),
- MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest),
- DI_current(0)
+ MaxPCHLevel(MaxPCHLevel), VisitPreprocessorLast(VisitPreprocessorLast),
+ RegionOfInterest(RegionOfInterest), DI_current(0)
{
Parent.kind = CXCursor_NoDeclFound;
Parent.data[0] = 0;
@@ -266,6 +272,7 @@ public:
bool VisitChildren(CXCursor Parent);
// Declaration visitors
+ bool VisitTypeAliasDecl(TypeAliasDecl *D);
bool VisitAttributes(Decl *D);
bool VisitBlockDecl(BlockDecl *B);
bool VisitCXXRecordDecl(CXXRecordDecl *D);
@@ -342,7 +349,11 @@ public:
bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL);
bool VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL);
bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL);
-
+ bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL);
+ bool VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL);
+ bool VisitElaboratedTypeLoc(ElaboratedTypeLoc TL);
+
// Data-recursive visitor functions.
bool IsInRegionOfInterest(CXCursor C);
bool RunVisitorWorkList(VisitorWorkList &WL);
@@ -472,7 +483,8 @@ CursorVisitor::getPreprocessedEntities() {
/// \returns true if the visitation should be aborted, false if it
/// should continue.
bool CursorVisitor::VisitChildren(CXCursor Cursor) {
- if (clang_isReference(Cursor.kind)) {
+ if (clang_isReference(Cursor.kind) &&
+ Cursor.kind != CXCursor_CXXBaseSpecifier) {
// By definition, references have no children.
return false;
}
@@ -483,68 +495,96 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = getCursorDecl(Cursor);
- assert(D && "Invalid declaration cursor");
+ if (!D)
+ return false;
+
return VisitAttributes(D) || Visit(D);
}
- if (clang_isStatement(Cursor.kind))
- return Visit(getCursorStmt(Cursor));
- if (clang_isExpression(Cursor.kind))
- return Visit(getCursorExpr(Cursor));
+ if (clang_isStatement(Cursor.kind)) {
+ if (Stmt *S = getCursorStmt(Cursor))
+ return Visit(S);
+
+ return false;
+ }
+
+ if (clang_isExpression(Cursor.kind)) {
+ if (Expr *E = getCursorExpr(Cursor))
+ return Visit(E);
+
+ return false;
+ }
if (clang_isTranslationUnit(Cursor.kind)) {
CXTranslationUnit tu = getCursorTU(Cursor);
ASTUnit *CXXUnit = static_cast<ASTUnit*>(tu->TUData);
- if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
- RegionOfInterest.isInvalid()) {
- for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
- TLEnd = CXXUnit->top_level_end();
- TL != TLEnd; ++TL) {
- if (Visit(MakeCXCursor(*TL, tu), true))
+
+ int VisitOrder[2] = { VisitPreprocessorLast, !VisitPreprocessorLast };
+ for (unsigned I = 0; I != 2; ++I) {
+ if (VisitOrder[I]) {
+ if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
+ RegionOfInterest.isInvalid()) {
+ for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
+ TLEnd = CXXUnit->top_level_end();
+ TL != TLEnd; ++TL) {
+ if (Visit(MakeCXCursor(*TL, tu), true))
+ return true;
+ }
+ } else if (VisitDeclContext(
+ CXXUnit->getASTContext().getTranslationUnitDecl()))
return true;
+ continue;
}
- } else if (VisitDeclContext(
- CXXUnit->getASTContext().getTranslationUnitDecl()))
- return true;
- // Walk the preprocessing record.
- if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
- // FIXME: Once we have the ability to deserialize a preprocessing record,
- // do so.
- PreprocessingRecord::iterator E, EEnd;
- for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) {
- if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
- if (Visit(MakeMacroInstantiationCursor(MI, tu)))
- return true;
-
- continue;
- }
-
- if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
- if (Visit(MakeMacroDefinitionCursor(MD, tu)))
- return true;
+ // Walk the preprocessing record.
+ if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
+ // FIXME: Once we have the ability to deserialize a preprocessing record,
+ // do so.
+ PreprocessingRecord::iterator E, EEnd;
+ for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) {
+ if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
+ if (Visit(MakeMacroInstantiationCursor(MI, tu)))
+ return true;
+
+ continue;
+ }
- continue;
- }
-
- if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
- if (Visit(MakeInclusionDirectiveCursor(ID, tu)))
- return true;
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
+ if (Visit(MakeMacroDefinitionCursor(MD, tu)))
+ return true;
+
+ continue;
+ }
- continue;
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
+ if (Visit(MakeInclusionDirectiveCursor(ID, tu)))
+ return true;
+
+ continue;
+ }
}
}
}
+
return false;
}
+ if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
+ if (CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) {
+ if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) {
+ return Visit(BaseTSInfo->getTypeLoc());
+ }
+ }
+ }
+
// Nothing to visit at the moment.
return false;
}
bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
- if (Visit(B->getSignatureAsWritten()->getTypeLoc()))
- return true;
+ if (TypeSourceInfo *TSInfo = B->getSignatureAsWritten())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
if (Stmt *Body = B->getBody())
return Visit(MakeCXCursor(Body, StmtParent, TU));
@@ -604,6 +644,13 @@ bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
return false;
}
+bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) {
+ if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) {
if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
return Visit(TSInfo->getTypeLoc());
@@ -742,7 +789,7 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// FIXME: Attributes?
}
- if (ND->isThisDeclarationADefinition()) {
+ if (ND->isThisDeclarationADefinition() && !ND->isLateTemplateParsed()) {
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) {
// Find the initializers that were written in the source.
llvm::SmallVector<CXXCtorInitializer *, 4> WrittenInits;
@@ -1315,6 +1362,9 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
+ if (VisitNestedNameSpecifierLoc(TAL.getTemplateQualifierLoc()))
+ return true;
+
return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(),
TAL.getTemplateNameLoc());
}
@@ -1362,7 +1412,9 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
case BuiltinType::LongDouble:
case BuiltinType::NullPtr:
case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
break;
case BuiltinType::ObjCId:
@@ -1388,7 +1440,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
}
bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
- return Visit(MakeCursorTypeRef(TL.getTypedefDecl(), TL.getNameLoc(), TU));
+ return Visit(MakeCursorTypeRef(TL.getTypedefNameDecl(), TL.getNameLoc(), TU));
}
bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
@@ -1400,10 +1452,7 @@ bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) {
}
bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
- // FIXME: We can't visit the template type parameter, because there's
- // no context information with which we can match up the depth/index in the
- // type to the appropriate
- return false;
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
}
bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
@@ -1503,6 +1552,35 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
return false;
}
+bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc()))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitDependentTemplateSpecializationTypeLoc(
+ DependentTemplateSpecializationTypeLoc TL) {
+ // Visit the nested-name-specifier, if there is one.
+ if (TL.getQualifierLoc() &&
+ VisitNestedNameSpecifierLoc(TL.getQualifierLoc()))
+ return true;
+
+ // Visit the template arguments.
+ for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
+ if (VisitTemplateArgumentLoc(TL.getArgLoc(I)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
+ if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc()))
+ return true;
+
+ return Visit(TL.getNamedTypeLoc());
+}
+
bool CursorVisitor::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
return Visit(TL.getPatternLoc());
}
@@ -1703,12 +1781,14 @@ public:
void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
void VisitObjCMessageExpr(ObjCMessageExpr *M);
void VisitOverloadExpr(OverloadExpr *E);
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
void VisitStmt(Stmt *S);
void VisitSwitchStmt(SwitchStmt *S);
void VisitWhileStmt(WhileStmt *W);
void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+ void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
+ void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
void VisitVAArgExpr(VAArgExpr *E);
void VisitSizeOfPackExpr(SizeOfPackExpr *E);
@@ -1797,8 +1877,8 @@ void EnqueueVisitor::
VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
AddDeclarationNameInfo(E);
- if (NestedNameSpecifier *Qualifier = E->getQualifier())
- AddNestedNameSpecifier(Qualifier, E->getQualifierRange());
+ if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
+ AddNestedNameSpecifierLoc(QualifierLoc);
if (!E->isImplicitAccess())
AddStmt(E->getBase());
}
@@ -1934,12 +2014,8 @@ void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) {
// visit it.
// FIXME: If we ever want to show these implicit accesses, this will be
// unfortunate. However, clang_getCursor() relies on this behavior.
- if (CXXThisExpr *This
- = llvm::dyn_cast<CXXThisExpr>(M->getBase()->IgnoreParenImpCasts()))
- if (This->isImplicit())
- return;
-
- AddStmt(M->getBase());
+ if (!M->isImplicitAccess())
+ AddStmt(M->getBase());
}
void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
AddTypeLoc(E->getEncodedTypeSourceInfo());
@@ -1958,7 +2034,7 @@ void EnqueueVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) {
AddStmt(E->getIndexExpr(Node.getArrayExprIndex()));
break;
case OffsetOfNode::Field:
- AddMemberRef(Node.getField(), Node.getRange().getEnd());
+ AddMemberRef(Node.getField(), Node.getSourceRange().getEnd());
break;
case OffsetOfNode::Identifier:
case OffsetOfNode::Base:
@@ -1972,7 +2048,8 @@ void EnqueueVisitor::VisitOverloadExpr(OverloadExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
WL.push_back(OverloadExprParts(E, Parent));
}
-void EnqueueVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr(
+ UnaryExprOrTypeTraitExpr *E) {
EnqueueChildren(E);
if (E->isArgumentType())
AddTypeLoc(E->getArgumentTypeInfo());
@@ -1991,6 +2068,7 @@ void EnqueueVisitor::VisitWhileStmt(WhileStmt *W) {
AddStmt(W->getCond());
AddDecl(W->getConditionVariable());
}
+
void EnqueueVisitor::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
AddTypeLoc(E->getQueriedTypeSourceInfo());
}
@@ -2000,6 +2078,14 @@ void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
AddTypeLoc(E->getLhsTypeSourceInfo());
}
+void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+ AddTypeLoc(E->getQueriedTypeSourceInfo());
+}
+
+void EnqueueVisitor::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+ EnqueueChildren(E);
+}
+
void EnqueueVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U) {
VisitOverloadExpr(U);
if (!U->isImplicitAccess())
@@ -2124,8 +2210,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
MemberExpr *M = cast<MemberExprParts>(&LI)->get();
// Visit the nested-name-specifier
- if (NestedNameSpecifier *Qualifier = M->getQualifier())
- if (VisitNestedNameSpecifier(Qualifier, M->getQualifierRange()))
+ if (NestedNameSpecifierLoc QualifierLoc = M->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
return true;
// Visit the declaration name.
@@ -2146,8 +2232,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
case VisitorJob::DeclRefExprPartsKind: {
DeclRefExpr *DR = cast<DeclRefExprParts>(&LI)->get();
// Visit nested-name-specifier, if present.
- if (NestedNameSpecifier *Qualifier = DR->getQualifier())
- if (VisitNestedNameSpecifier(Qualifier, DR->getQualifierRange()))
+ if (NestedNameSpecifierLoc QualifierLoc = DR->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
return true;
// Visit declaration name.
if (VisitDeclarationNameInfo(DR->getNameInfo()))
@@ -2157,8 +2243,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
case VisitorJob::OverloadExprPartsKind: {
OverloadExpr *O = cast<OverloadExprParts>(&LI)->get();
// Visit the nested-name-specifier.
- if (NestedNameSpecifier *Qualifier = O->getQualifier())
- if (VisitNestedNameSpecifier(Qualifier, O->getQualifierRange()))
+ if (NestedNameSpecifierLoc QualifierLoc = O->getQualifierLoc())
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
return true;
// Visit the declaration name.
if (VisitDeclarationNameInfo(O->getNameInfo()))
@@ -2253,6 +2339,13 @@ void clang_disposeIndex(CXIndex CIdx) {
delete static_cast<CIndexer *>(CIdx);
}
+void clang_toggleCrashRecovery(unsigned isEnabled) {
+ if (isEnabled)
+ llvm::CrashRecoveryContext::Enable();
+ else
+ llvm::CrashRecoveryContext::Disable();
+}
+
CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
const char *ast_filename) {
if (!CIdx)
@@ -2327,27 +2420,37 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
// Configure the diagnostics.
DiagnosticOptions DiagOpts;
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
- Diags = CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
- command_line_args);
+ llvm::IntrusiveRefCntPtr<Diagnostic>
+ Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
+ command_line_args));
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
+ llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ DiagCleanup(Diags.getPtr());
+
+ llvm::OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<
+ std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
- llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
for (unsigned I = 0; I != num_unsaved_files; ++I) {
llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
const llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
- RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
- Buffer));
+ RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename,
+ Buffer));
}
- llvm::SmallVector<const char *, 16> Args;
+ llvm::OwningPtr<std::vector<const char *> >
+ Args(new std::vector<const char*>());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> >
+ ArgsCleanup(Args.get());
- // The 'source_filename' argument is optional. If the caller does not
- // specify it then it is assumed that the source file is specified
- // in the actual argument list.
- if (source_filename)
- Args.push_back(source_filename);
-
// Since the Clang C library is primarily used by batch tools dealing with
// (often very broken) source code, where spell-checking can have a
// significant negative impact on performance (particularly when
@@ -2362,26 +2465,37 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
}
}
if (!FoundSpellCheckingArgument)
- Args.push_back("-fno-spell-checking");
+ Args->push_back("-fno-spell-checking");
- Args.insert(Args.end(), command_line_args,
- command_line_args + num_command_line_args);
+ Args->insert(Args->end(), command_line_args,
+ command_line_args + num_command_line_args);
+
+ // The 'source_filename' argument is optional. If the caller does not
+ // specify it then it is assumed that the source file is specified
+ // in the actual argument list.
+ // Put the source file after command_line_args otherwise if '-x' flag is
+ // present it will be unused.
+ if (source_filename)
+ Args->push_back(source_filename);
// Do we need the detailed preprocessing record?
if (options & CXTranslationUnit_DetailedPreprocessingRecord) {
- Args.push_back("-Xclang");
- Args.push_back("-detailed-preprocessing-record");
+ Args->push_back("-Xclang");
+ Args->push_back("-detailed-preprocessing-record");
}
unsigned NumErrors = Diags->getClient()->getNumErrors();
llvm::OwningPtr<ASTUnit> Unit(
- ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
+ ASTUnit::LoadFromCommandLine(Args->size() ? &(*Args)[0] : 0
+ /* vector::data() not portable */,
+ Args->size() ? (&(*Args)[0] + Args->size()) :0,
Diags,
CXXIdx->getClangResourcesPath(),
CXXIdx->getOnlyLocalDecls(),
/*CaptureDiagnostics=*/true,
- RemappedFiles.data(),
- RemappedFiles.size(),
+ RemappedFiles->size() ? &(*RemappedFiles)[0]:0,
+ RemappedFiles->size(),
+ /*RemappedFilesKeepOriginalName=*/true,
PrecompilePreamble,
CompleteTranslationUnit,
CacheCodeCompetionResults,
@@ -2503,16 +2617,23 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
- llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
+ llvm::OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<
+ std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get());
+
for (unsigned I = 0; I != num_unsaved_files; ++I) {
llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
const llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
- RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
- Buffer));
+ RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename,
+ Buffer));
}
- if (!CXXUnit->Reparse(RemappedFiles.data(), RemappedFiles.size()))
+ if (!CXXUnit->Reparse(RemappedFiles->size() ? &(*RemappedFiles)[0] : 0,
+ RemappedFiles->size()))
RTUI->result = 0;
}
@@ -2627,7 +2748,22 @@ CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
begin.int_data, end.int_data };
return Result;
}
+} // end: extern "C"
+
+static void createNullLocation(CXFile *file, unsigned *line,
+ unsigned *column, unsigned *offset) {
+ if (file)
+ *file = 0;
+ if (line)
+ *line = 0;
+ if (column)
+ *column = 0;
+ if (offset)
+ *offset = 0;
+ return;
+}
+extern "C" {
void clang_getInstantiationLocation(CXSourceLocation location,
CXFile *file,
unsigned *line,
@@ -2636,14 +2772,7 @@ void clang_getInstantiationLocation(CXSourceLocation location,
SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
if (!location.ptr_data[0] || Loc.isInvalid()) {
- if (file)
- *file = 0;
- if (line)
- *line = 0;
- if (column)
- *column = 0;
- if (offset)
- *offset = 0;
+ createNullLocation(file, line, column, offset);
return;
}
@@ -2651,8 +2780,18 @@ void clang_getInstantiationLocation(CXSourceLocation location,
*static_cast<const SourceManager*>(location.ptr_data[0]);
SourceLocation InstLoc = SM.getInstantiationLoc(Loc);
+ // Check that the FileID is invalid on the instantiation location.
+ // This can manifest in invalid code.
+ FileID fileID = SM.getFileID(InstLoc);
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
+ if (!sloc.isFile() || Invalid) {
+ createNullLocation(file, line, column, offset);
+ return;
+ }
+
if (file)
- *file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc));
+ *file = (void *)SM.getFileEntryForSLocEntry(sloc);
if (line)
*line = SM.getInstantiationLineNumber(InstLoc);
if (column)
@@ -2816,7 +2955,8 @@ unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data) {
CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
- getCursorASTUnit(parent)->getMaxPCHLevel());
+ getCursorASTUnit(parent)->getMaxPCHLevel(),
+ false);
return CursorVis.VisitChildren(parent);
}
@@ -3216,6 +3356,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("UsingDirective");
case CXCursor_UsingDeclaration:
return createCXString("UsingDeclaration");
+ case CXCursor_TypeAliasDecl:
+ return createCXString("TypeAliasDecl");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -3272,7 +3414,7 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
// the region of interest, rather than starting from the translation unit.
CXCursor Parent = clang_getTranslationUnitCursor(TU);
CursorVisitor CursorVis(TU, GetCursorVisitor, &Result,
- Decl::MaxPCHLevel, SourceLocation(SLoc));
+ Decl::MaxPCHLevel, true, SourceLocation(SLoc));
CursorVis.VisitChildren(Parent);
}
@@ -3587,25 +3729,30 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
Decl *D = cxcursor::getCursorDecl(C);
SourceRange R = D->getSourceRange();
-
+
+ // Adjust the start of the location for declarations preceded by
+ // declaration specifiers.
+ SourceLocation StartLoc;
if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
- if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) {
- TypeLoc TL = TI->getTypeLoc();
- SourceLocation TLoc = TL.getSourceRange().getBegin();
- if (TLoc.isValid() && R.getBegin().isValid() &&
- SrcMgr.isBeforeInTranslationUnit(TLoc, R.getBegin()))
- R.setBegin(TLoc);
- }
+ if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
+ if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ }
- // FIXME: Multiple variables declared in a single declaration
- // currently lack the information needed to correctly determine their
- // ranges when accounting for the type-specifier. We use context
- // stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
- // and if so, whether it is the first decl.
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (!cxcursor::isFirstInDeclGroup(C))
- R.setBegin(VD->getLocation());
- }
+ if (StartLoc.isValid() && R.getBegin().isValid() &&
+ SrcMgr.isBeforeInTranslationUnit(StartLoc, R.getBegin()))
+ R.setBegin(StartLoc);
+
+ // FIXME: Multiple variables declared in a single declaration
+ // currently lack the information needed to correctly determine their
+ // ranges when accounting for the type-specifier. We use context
+ // stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
+ // and if so, whether it is the first decl.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (!cxcursor::isFirstInDeclGroup(C))
+ R.setBegin(VD->getLocation());
}
return R;
@@ -3660,7 +3807,9 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
if (clang_isStatement(C.kind)) {
Stmt *S = getCursorStmt(C);
if (GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S))
- return MakeCXCursor(Goto->getLabel()->getStmt(), getCursorDecl(C), tu);
+ if (LabelDecl *label = Goto->getLabel())
+ if (LabelStmt *labelS = label->getStmt())
+ return MakeCXCursor(labelS, getCursorDecl(C), tu);
return clang_getNullCursor();
}
@@ -3749,6 +3898,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
// declaration and definition.
case Decl::Namespace:
case Decl::Typedef:
+ case Decl::TypeAlias:
case Decl::TemplateTypeParm:
case Decl::EnumConstant:
case Decl::Field:
@@ -4215,7 +4365,8 @@ class AnnotateTokensWorker {
unsigned PreprocessingTokIdx;
CursorVisitor AnnotateVis;
SourceManager &SrcMgr;
-
+ bool HasContextSensitiveKeywords;
+
bool MoreTokens() const { return TokIdx < NumTokens; }
unsigned NextToken() const { return TokIdx; }
void AdvanceToken() { ++TokIdx; }
@@ -4231,8 +4382,9 @@ public:
NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
AnnotateVis(tu,
AnnotateTokensVisitor, this,
- Decl::MaxPCHLevel, RegionOfInterest),
- SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()) {}
+ Decl::MaxPCHLevel, true, RegionOfInterest),
+ SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
+ HasContextSensitiveKeywords(false) { }
void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
@@ -4240,6 +4392,12 @@ public:
void AnnotateTokens() {
AnnotateTokens(clang_getTranslationUnitCursor(AnnotateVis.getTU()));
}
+
+ /// \brief Determine whether the annotator saw any cursors that have
+ /// context-sensitive keywords.
+ bool hasContextSensitiveKeywords() const {
+ return HasContextSensitiveKeywords;
+ }
};
}
@@ -4273,7 +4431,52 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
SourceRange cursorRange = getRawCursorExtent(cursor);
if (cursorRange.isInvalid())
return CXChildVisit_Recurse;
-
+
+ if (!HasContextSensitiveKeywords) {
+ // Objective-C properties can have context-sensitive keywords.
+ if (cursor.kind == CXCursor_ObjCPropertyDecl) {
+ if (ObjCPropertyDecl *Property
+ = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(cursor)))
+ HasContextSensitiveKeywords = Property->getPropertyAttributesAsWritten() != 0;
+ }
+ // Objective-C methods can have context-sensitive keywords.
+ else if (cursor.kind == CXCursor_ObjCInstanceMethodDecl ||
+ cursor.kind == CXCursor_ObjCClassMethodDecl) {
+ if (ObjCMethodDecl *Method
+ = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) {
+ if (Method->getObjCDeclQualifier())
+ HasContextSensitiveKeywords = true;
+ else {
+ for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; ++P) {
+ if ((*P)->getObjCDeclQualifier()) {
+ HasContextSensitiveKeywords = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ // C++ methods can have context-sensitive keywords.
+ else if (cursor.kind == CXCursor_CXXMethod) {
+ if (CXXMethodDecl *Method
+ = dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(cursor))) {
+ if (Method->hasAttr<FinalAttr>() || Method->hasAttr<OverrideAttr>())
+ HasContextSensitiveKeywords = true;
+ }
+ }
+ // C++ classes can have context-sensitive keywords.
+ else if (cursor.kind == CXCursor_StructDecl ||
+ cursor.kind == CXCursor_ClassDecl ||
+ cursor.kind == CXCursor_ClassTemplate ||
+ cursor.kind == CXCursor_ClassTemplatePartialSpecialization) {
+ if (Decl *D = getCursorDecl(cursor))
+ if (D->hasAttr<FinalAttr>())
+ HasContextSensitiveKeywords = true;
+ }
+ }
+
if (clang_isPreprocessing(cursor.kind)) {
// For macro instantiations, just note where the beginning of the macro
// instantiation occurs.
@@ -4342,15 +4545,19 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
if (MD->isSynthesized())
return CXChildVisit_Continue;
}
+
+ SourceLocation StartLoc;
if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
- if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) {
- TypeLoc TL = TI->getTypeLoc();
- SourceLocation TLoc = TL.getSourceRange().getBegin();
- if (TLoc.isValid() && L.isValid() &&
- SrcMgr.isBeforeInTranslationUnit(TLoc, L))
- cursorRange.setBegin(TLoc);
- }
+ if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
+ if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
+ StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
}
+
+ if (StartLoc.isValid() && L.isValid() &&
+ SrcMgr.isBeforeInTranslationUnit(StartLoc, L))
+ cursorRange.setBegin(StartLoc);
}
// If the location of the cursor occurs within a macro instantiation, record
@@ -4444,43 +4651,36 @@ static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
}
-// This gets run a separate thread to avoid stack blowout.
-static void runAnnotateTokensWorker(void *UserData) {
- ((AnnotateTokensWorker*)UserData)->AnnotateTokens();
+namespace {
+ struct clang_annotateTokens_Data {
+ CXTranslationUnit TU;
+ ASTUnit *CXXUnit;
+ CXToken *Tokens;
+ unsigned NumTokens;
+ CXCursor *Cursors;
+ };
}
-extern "C" {
-
-void clang_annotateTokens(CXTranslationUnit TU,
- CXToken *Tokens, unsigned NumTokens,
- CXCursor *Cursors) {
-
- if (NumTokens == 0 || !Tokens || !Cursors)
- return;
-
- // Any token we don't specifically annotate will have a NULL cursor.
- CXCursor C = clang_getNullCursor();
- for (unsigned I = 0; I != NumTokens; ++I)
- Cursors[I] = C;
-
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
- if (!CXXUnit)
- return;
-
- ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+// This gets run a separate thread to avoid stack blowout.
+static void clang_annotateTokensImpl(void *UserData) {
+ CXTranslationUnit TU = ((clang_annotateTokens_Data*)UserData)->TU;
+ ASTUnit *CXXUnit = ((clang_annotateTokens_Data*)UserData)->CXXUnit;
+ CXToken *Tokens = ((clang_annotateTokens_Data*)UserData)->Tokens;
+ const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens;
+ CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors;
// Determine the region of interest, which contains all of the tokens.
SourceRange RegionOfInterest;
- RegionOfInterest.setBegin(cxloc::translateSourceLocation(
- clang_getTokenLocation(TU, Tokens[0])));
- RegionOfInterest.setEnd(cxloc::translateSourceLocation(
- clang_getTokenLocation(TU,
- Tokens[NumTokens - 1])));
+ RegionOfInterest.setBegin(
+ cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
+ RegionOfInterest.setEnd(
+ cxloc::translateSourceLocation(clang_getTokenLocation(TU,
+ Tokens[NumTokens-1])));
// A mapping from the source locations found when re-lexing or traversing the
// region of interest to the corresponding cursors.
AnnotateTokensData Annotated;
-
+
// Relex the tokens within the source range to look for preprocessing
// directives.
SourceManager &SourceMgr = CXXUnit->getSourceManager();
@@ -4488,7 +4688,7 @@ void clang_annotateTokens(CXTranslationUnit TU,
= SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
std::pair<FileID, unsigned> EndLocInfo
= SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
-
+
llvm::StringRef Buffer;
bool Invalid = false;
if (BeginLocInfo.first == EndLocInfo.first &&
@@ -4499,13 +4699,13 @@ void clang_annotateTokens(CXTranslationUnit TU,
Buffer.begin(), Buffer.data() + BeginLocInfo.second,
Buffer.end());
Lex.SetCommentRetentionState(true);
-
+
// Lex tokens in raw mode until we hit the end of the range, to avoid
// entering #includes or expanding macros.
while (true) {
Token Tok;
Lex.LexFromRawLexer(Tok);
-
+
reprocess:
if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
// We have found a preprocessing directive. Gobble it up so that we
@@ -4515,49 +4715,158 @@ void clang_annotateTokens(CXTranslationUnit TU,
//
// FIXME: Some simple tests here could identify macro definitions and
// #undefs, to provide specific cursor kinds for those.
- std::vector<SourceLocation> Locations;
+ llvm::SmallVector<SourceLocation, 32> Locations;
do {
Locations.push_back(Tok.getLocation());
Lex.LexFromRawLexer(Tok);
} while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
-
+
using namespace cxcursor;
CXCursor Cursor
- = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
- Locations.back()),
+ = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
+ Locations.back()),
TU);
for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
Annotated[Locations[I].getRawEncoding()] = Cursor;
}
-
+
if (Tok.isAtStartOfLine())
goto reprocess;
-
+
continue;
}
-
+
if (Tok.is(tok::eof))
break;
}
}
-
+
// Annotate all of the source locations in the region of interest that map to
// a specific cursor.
AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens,
TU, RegionOfInterest);
-
- // Run the worker within a CrashRecoveryContext.
+
// FIXME: We use a ridiculous stack size here because the data-recursion
// algorithm uses a large stack frame than the non-data recursive version,
// and AnnotationTokensWorker currently transforms the data-recursion
// algorithm back into a traditional recursion by explicitly calling
// VisitChildren(). We will need to remove this explicit recursive call.
+ W.AnnotateTokens();
+
+ // If we ran into any entities that involve context-sensitive keywords,
+ // take another pass through the tokens to mark them as such.
+ if (W.hasContextSensitiveKeywords()) {
+ for (unsigned I = 0; I != NumTokens; ++I) {
+ if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier)
+ continue;
+
+ if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) {
+ IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
+ if (ObjCPropertyDecl *Property
+ = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) {
+ if (Property->getPropertyAttributesAsWritten() != 0 &&
+ llvm::StringSwitch<bool>(II->getName())
+ .Case("readonly", true)
+ .Case("assign", true)
+ .Case("readwrite", true)
+ .Case("retain", true)
+ .Case("copy", true)
+ .Case("nonatomic", true)
+ .Case("atomic", true)
+ .Case("getter", true)
+ .Case("setter", true)
+ .Default(false))
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ }
+ continue;
+ }
+
+ if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl ||
+ Cursors[I].kind == CXCursor_ObjCClassMethodDecl) {
+ IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
+ if (llvm::StringSwitch<bool>(II->getName())
+ .Case("in", true)
+ .Case("out", true)
+ .Case("inout", true)
+ .Case("oneway", true)
+ .Case("bycopy", true)
+ .Case("byref", true)
+ .Default(false))
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ continue;
+ }
+
+ if (Cursors[I].kind == CXCursor_CXXMethod) {
+ IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
+ if (CXXMethodDecl *Method
+ = dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(Cursors[I]))) {
+ if ((Method->hasAttr<FinalAttr>() ||
+ Method->hasAttr<OverrideAttr>()) &&
+ Method->getLocation().getRawEncoding() != Tokens[I].int_data[1] &&
+ llvm::StringSwitch<bool>(II->getName())
+ .Case("final", true)
+ .Case("override", true)
+ .Default(false))
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ }
+ continue;
+ }
+
+ if (Cursors[I].kind == CXCursor_ClassDecl ||
+ Cursors[I].kind == CXCursor_StructDecl ||
+ Cursors[I].kind == CXCursor_ClassTemplate) {
+ IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
+ if (II->getName() == "final") {
+ // We have to be careful with 'final', since it could be the name
+ // of a member class rather than the context-sensitive keyword.
+ // So, check whether the cursor associated with this
+ Decl *D = getCursorDecl(Cursors[I]);
+ if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(D)) {
+ if ((Record->hasAttr<FinalAttr>()) &&
+ Record->getIdentifier() != II)
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ } else if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast_or_null<ClassTemplateDecl>(D)) {
+ CXXRecordDecl *Record = ClassTemplate->getTemplatedDecl();
+ if ((Record->hasAttr<FinalAttr>()) &&
+ Record->getIdentifier() != II)
+ Tokens[I].int_data[0] = CXToken_Keyword;
+ }
+ }
+ continue;
+ }
+ }
+ }
+}
+
+extern "C" {
+
+void clang_annotateTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens,
+ CXCursor *Cursors) {
+
+ if (NumTokens == 0 || !Tokens || !Cursors)
+ return;
+
+ // Any token we don't specifically annotate will have a NULL cursor.
+ CXCursor C = clang_getNullCursor();
+ for (unsigned I = 0; I != NumTokens; ++I)
+ Cursors[I] = C;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!CXXUnit)
+ return;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ clang_annotateTokens_Data data = { TU, CXXUnit, Tokens, NumTokens, Cursors };
llvm::CrashRecoveryContext CRC;
- if (!RunSafely(CRC, runAnnotateTokensWorker, &W,
+ if (!RunSafely(CRC, clang_annotateTokensImpl, &data,
GetSafetyThreadStackSize() * 2)) {
fprintf(stderr, "libclang: crash detected while annotating tokens\n");
}
}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -4639,14 +4948,22 @@ extern "C" {
enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind))
if (Decl *D = cxcursor::getCursorDecl(cursor)) {
- if (D->hasAttr<UnavailableAttr>() ||
- (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted()))
+ if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
return CXAvailability_Available;
- if (D->hasAttr<DeprecatedAttr>())
+ switch (D->getAvailability()) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ return CXAvailability_Available;
+
+ case AR_Deprecated:
return CXAvailability_Deprecated;
+
+ case AR_Unavailable:
+ return CXAvailability_NotAvailable;
+ }
}
-
+
return CXAvailability_Available;
}
@@ -4866,11 +5183,142 @@ CXType clang_getIBOutletCollectionType(CXCursor C) {
IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C));
- return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C));
+ return cxtype::MakeCXType(A->getInterFace(), cxcursor::getCursorTU(C));
}
} // end: extern "C"
//===----------------------------------------------------------------------===//
+// Inspecting memory usage.
+//===----------------------------------------------------------------------===//
+
+typedef std::vector<CXTUResourceUsageEntry> MemUsageEntries;
+
+static inline void createCXTUResourceUsageEntry(MemUsageEntries &entries,
+ enum CXTUResourceUsageKind k,
+ unsigned long amount) {
+ CXTUResourceUsageEntry entry = { k, amount };
+ entries.push_back(entry);
+}
+
+extern "C" {
+
+const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) {
+ const char *str = "";
+ switch (kind) {
+ case CXTUResourceUsage_AST:
+ str = "ASTContext: expressions, declarations, and types";
+ break;
+ case CXTUResourceUsage_Identifiers:
+ str = "ASTContext: identifiers";
+ break;
+ case CXTUResourceUsage_Selectors:
+ str = "ASTContext: selectors";
+ break;
+ case CXTUResourceUsage_GlobalCompletionResults:
+ str = "Code completion: cached global results";
+ break;
+ case CXTUResourceUsage_SourceManagerContentCache:
+ str = "SourceManager: content cache allocator";
+ break;
+ case CXTUResourceUsage_AST_SideTables:
+ str = "ASTContext: side tables";
+ break;
+ case CXTUResourceUsage_SourceManager_Membuffer_Malloc:
+ str = "SourceManager: malloc'ed memory buffers";
+ break;
+ case CXTUResourceUsage_SourceManager_Membuffer_MMap:
+ str = "SourceManager: mmap'ed memory buffers";
+ break;
+ case CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc:
+ str = "ExternalASTSource: malloc'ed memory buffers";
+ break;
+ case CXTUResourceUsage_ExternalASTSource_Membuffer_MMap:
+ str = "ExternalASTSource: mmap'ed memory buffers";
+ break;
+ }
+ return str;
+}
+
+CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
+ if (!TU) {
+ CXTUResourceUsage usage = { (void*) 0, 0, 0 };
+ return usage;
+ }
+
+ ASTUnit *astUnit = static_cast<ASTUnit*>(TU->TUData);
+ llvm::OwningPtr<MemUsageEntries> entries(new MemUsageEntries());
+ ASTContext &astContext = astUnit->getASTContext();
+
+ // How much memory is used by AST nodes and types?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST,
+ (unsigned long) astContext.getASTAllocatedMemory());
+
+ // How much memory is used by identifiers?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Identifiers,
+ (unsigned long) astContext.Idents.getAllocator().getTotalMemory());
+
+ // How much memory is used for selectors?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Selectors,
+ (unsigned long) astContext.Selectors.getTotalMemory());
+
+ // How much memory is used by ASTContext's side tables?
+ createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST_SideTables,
+ (unsigned long) astContext.getSideTableAllocatedMemory());
+
+ // How much memory is used for caching global code completion results?
+ unsigned long completionBytes = 0;
+ if (GlobalCodeCompletionAllocator *completionAllocator =
+ astUnit->getCachedCompletionAllocator().getPtr()) {
+ completionBytes = completionAllocator-> getTotalMemory();
+ }
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_GlobalCompletionResults,
+ completionBytes);
+
+ // How much memory is being used by SourceManager's content cache?
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManagerContentCache,
+ (unsigned long) astContext.getSourceManager().getContentCacheSize());
+
+ // How much memory is being used by the MemoryBuffer's in SourceManager?
+ const SourceManager::MemoryBufferSizes &srcBufs =
+ astUnit->getSourceManager().getMemoryBufferSizes();
+
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManager_Membuffer_Malloc,
+ (unsigned long) srcBufs.malloc_bytes);
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_SourceManager_Membuffer_MMap,
+ (unsigned long) srcBufs.mmap_bytes);
+
+ // How much memory is being used by the ExternalASTSource?
+ if (ExternalASTSource *esrc = astContext.getExternalSource()) {
+ const ExternalASTSource::MemoryBufferSizes &sizes =
+ esrc->getMemoryBufferSizes();
+
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc,
+ (unsigned long) sizes.malloc_bytes);
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_ExternalASTSource_Membuffer_MMap,
+ (unsigned long) sizes.mmap_bytes);
+ }
+
+ CXTUResourceUsage usage = { (void*) entries.get(),
+ (unsigned) entries->size(),
+ entries->size() ? &(*entries)[0] : 0 };
+ entries.take();
+ return usage;
+}
+
+void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage) {
+ if (usage.data)
+ delete (MemUsageEntries*) usage.data;
+}
+
+} // end extern "C"
+
+//===----------------------------------------------------------------------===//
// Misc. utility functions.
//===----------------------------------------------------------------------===//
@@ -4906,3 +5354,4 @@ CXString clang_getClangVersion() {
}
} // end: extern "C"
+
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 292719bebdae..e85e80246f9e 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -201,7 +201,7 @@ clang_getCompletionAvailability(CXCompletionString completion_string) {
/// \brief The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
- AllocatedCXCodeCompleteResults();
+ AllocatedCXCodeCompleteResults(const FileSystemOptions& FileSystemOpts);
~AllocatedCXCodeCompleteResults();
/// \brief Diagnostics produced while performing code completion.
@@ -216,10 +216,10 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
FileSystemOptions FileSystemOpts;
/// \brief File manager, used for diagnostics.
- FileManager FileMgr;
+ llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
/// \brief Source manager, used for diagnostics.
- SourceManager SourceMgr;
+ llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
/// \brief Temporary files that should be removed once we have finished
/// with the code-completion results.
@@ -243,12 +243,14 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// Used for debugging purposes only.
static llvm::sys::cas_flag CodeCompletionResultObjects;
-AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
+AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
+ const FileSystemOptions& FileSystemOpts)
: CXCodeCompleteResults(),
Diag(new Diagnostic(
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
- FileMgr(FileSystemOpts),
- SourceMgr(*Diag, FileMgr) {
+ FileSystemOpts(FileSystemOpts),
+ FileMgr(new FileManager(FileSystemOpts)),
+ SourceMgr(new SourceManager(*Diag, *FileMgr)) {
if (getenv("LIBCLANG_OBJTRACKING")) {
llvm::sys::AtomicIncrement(&CodeCompletionResultObjects);
fprintf(stderr, "+++ %d completion results\n", CodeCompletionResultObjects);
@@ -380,7 +382,8 @@ void clang_codeCompleteAt_Impl(void *UserData) {
}
// Parse the resulting source file to find code-completion results.
- AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
+ AllocatedCXCodeCompleteResults *Results =
+ new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts());
Results->Results = 0;
Results->NumResults = 0;
@@ -393,8 +396,8 @@ void clang_codeCompleteAt_Impl(void *UserData) {
(options & CXCodeComplete_IncludeMacros),
(options & CXCodeComplete_IncludeCodePatterns),
Capture,
- *Results->Diag, Results->LangOpts, Results->SourceMgr,
- Results->FileMgr, Results->Diagnostics,
+ *Results->Diag, Results->LangOpts, *Results->SourceMgr,
+ *Results->FileMgr, Results->Diagnostics,
Results->TemporaryBuffers);
// Keep a reference to the allocator used for cached global completions, so
diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp
index e0f4d42defdb..6bc4f2e776a3 100644
--- a/tools/libclang/CIndexInclusionStack.cpp
+++ b/tools/libclang/CIndexInclusionStack.cpp
@@ -40,14 +40,14 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
i = 0;
for ( ; i < n ; ++i) {
-
- const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i);
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i, &Invalid);
- if (!SL.isFile())
+ if (!SL.isFile() || Invalid)
continue;
const SrcMgr::FileInfo &FI = SL.getFile();
- if (!FI.getContentCache()->Entry)
+ if (!FI.getContentCache()->OrigEntry)
continue;
// Build the inclusion stack.
@@ -61,7 +61,7 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
// Callback to the client.
// FIXME: We should have a function to construct CXFiles.
- CB((CXFile) FI.getContentCache()->Entry,
+ CB((CXFile) FI.getContentCache()->OrigEntry,
InclusionStack.data(), InclusionStack.size(), clientData);
}
}
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index e74d1d4deb3f..9917d2ad2104 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -431,7 +431,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
const unsigned off = Buf.size() - 1;
if (EmitDeclName(D)) {
- if (const TypedefDecl *TD = D->getTypedefForAnonDecl()) {
+ if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) {
Buf[off] = 'A';
Out << '@' << TD;
}
@@ -470,6 +470,12 @@ bool USRGenerator::GenLoc(const Decl *D) {
if (generatedLoc)
return IgnoreResults;
generatedLoc = true;
+
+ // Guard against null declarations in invalid code.
+ if (!D) {
+ IgnoreResults = true;
+ return true;
+ }
const SourceManager &SM = AU->getSourceManager();
SourceLocation L = D->getLocStart();
@@ -570,7 +576,9 @@ void USRGenerator::VisitType(QualType T) {
case BuiltinType::NullPtr:
c = 'n'; break;
case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
case BuiltinType::Dependent:
+ case BuiltinType::UnknownAny:
IgnoreResults = true;
return;
case BuiltinType::ObjCId:
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index 992d76a2efe9..56974b9e999b 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -32,6 +32,7 @@
#include <sstream>
#ifdef __CYGWIN__
+#include <cygwin/version.h>
#include <sys/cygwin.h>
#define LLVM_ON_WIN32 1
#endif
@@ -60,8 +61,12 @@ std::string CIndexer::getClangResourcesPath() {
#ifdef __CYGWIN__
char w32path[MAX_PATH];
strcpy(w32path, path);
+#if CYGWIN_VERSION_API_MAJOR > 0 || CYGWIN_VERSION_API_MINOR >= 181
+ cygwin_conv_path(CCP_WIN_A_TO_POSIX, w32path, path, MAX_PATH);
+#else
cygwin_conv_to_full_posix_path(w32path, path);
#endif
+#endif
llvm::sys::Path LibClangPath(path);
LibClangPath.eraseComponent();
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 11759eefb6d3..7a6270d17647 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -1,5 +1,3 @@
-set(SHARED_LIBRARY TRUE)
-
set(LLVM_USED_LIBS
clangFrontend
clangDriver
@@ -15,7 +13,7 @@ set( LLVM_LINK_COMPONENTS
mc
)
-add_clang_library(libclang
+set(SOURCES
CIndex.cpp
CIndexCXX.cpp
CIndexCodeCompletion.cpp
@@ -27,34 +25,44 @@ add_clang_library(libclang
CXString.cpp
CXType.cpp
../../include/clang-c/Index.h
-)
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- # Darwin-specific linker flags
+ )
- set(LIBCLANG_LINK_FLAGS "-Wl,-compatibility_version -Wl,1")
-
- set(LIBCLANG_LINK_FLAGS
- "${LIBCLANG_LINK_FLAGS} -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000")
+if( LLVM_ENABLE_PIC )
+ set(SHARED_LIBRARY TRUE)
+ add_clang_library(libclang ${SOURCES})
set_target_properties(libclang
PROPERTIES
- LINK_FLAGS "${LIBCLANG_LINK_FLAGS}"
- INSTALL_NAME_DIR "@executable_path/../lib")
+ OUTPUT_NAME "libclang"
+ VERSION ${LIBCLANG_LIBRARY_VERSION}
+ DEFINE_SYMBOL _CINDEX_LIB_)
+
+ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(LIBCLANG_LINK_FLAGS
+ "-Wl,-compatibility_version -Wl,1 -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000")
+ set_target_properties(libclang
+ PROPERTIES
+ LINK_FLAGS "${LIBCLANG_LINK_FLAGS}"
+ INSTALL_NAME_DIR "@executable_path/../lib")
+ endif()
+
+ if(MSVC)
+ # windows.h doesn't compile with /Za
+ get_target_property(NON_ANSI_COMPILE_FLAGS libclang COMPILE_FLAGS)
+ string(REPLACE "/Za" "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
+ set_target_properties(libclang PROPERTIES
+ COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
+ endif()
+
+ set(LIBCLANG_STATIC_TARGET_NAME libclang_static)
+else()
+ set(LIBCLANG_STATIC_TARGET_NAME libclang)
endif()
-# Versioning information
-set_target_properties(libclang PROPERTIES VERSION ${LIBCLANG_LIBRARY_VERSION})
-
-if(MSVC)
- # windows.h doesn't compile with /Za
- get_target_property(NON_ANSI_COMPILE_FLAGS libclang COMPILE_FLAGS)
- string(REPLACE /Za "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
- set_target_properties(libclang PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
-endif(MSVC)
-
-set_target_properties(libclang
- PROPERTIES
- PREFIX "" # Otherwise we get liblibclang.so
- LINKER_LANGUAGE CXX
- DEFINE_SYMBOL _CINDEX_LIB_)
+if( NOT BUILD_SHARED_LIBS AND NOT WIN32 )
+ add_clang_library(${LIBCLANG_STATIC_TARGET_NAME} STATIC ${SOURCES})
+
+ set_target_properties(${LIBCLANG_STATIC_TARGET_NAME}
+ PROPERTIES
+ OUTPUT_NAME "libclang")
+endif()
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index dd22a97ab19b..2a78012d8917 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -95,6 +95,10 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::ObjCForCollectionStmtClass:
case Stmt::CXXCatchStmtClass:
case Stmt::CXXTryStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::SEHTryStmtClass:
+ case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHFinallyStmtClass:
K = CXCursor_UnexposedStmt;
break;
@@ -111,7 +115,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::ParenExprClass:
case Stmt::UnaryOperatorClass:
case Stmt::OffsetOfExprClass:
- case Stmt::SizeOfAlignOfExprClass:
+ case Stmt::UnaryExprOrTypeTraitExprClass:
case Stmt::ArraySubscriptExprClass:
case Stmt::BinaryOperatorClass:
case Stmt::CompoundAssignOperatorClass:
@@ -129,6 +133,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::AddrLabelExprClass:
case Stmt::StmtExprClass:
case Stmt::ChooseExprClass:
+ case Stmt::GenericSelectionExprClass:
case Stmt::GNUNullExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::CXXDynamicCastExprClass:
@@ -149,6 +154,8 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::UnresolvedLookupExprClass:
case Stmt::UnaryTypeTraitExprClass:
case Stmt::BinaryTypeTraitExprClass:
+ case Stmt::ArrayTypeTraitExprClass:
+ case Stmt::ExpressionTraitExprClass:
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::CXXBindTemporaryExprClass:
case Stmt::ExprWithCleanupsClass:
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index 7614544ca3bc..30c3fd1ac30a 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -21,6 +21,7 @@ _clang_defaultEditingTranslationUnitOptions
_clang_defaultReparseOptions
_clang_defaultSaveOptions
_clang_disposeCXCursorSet
+_clang_disposeCXTUResourceUsage
_clang_disposeCodeCompleteResults
_clang_disposeDiagnostic
_clang_disposeIndex
@@ -35,6 +36,7 @@ _clang_equalTypes
_clang_executeOnThread
_clang_formatDiagnostic
_clang_getCString
+_clang_getCXTUResourceUsage
_clang_getCXXAccessSpecifier
_clang_getCanonicalCursor
_clang_getCanonicalType
@@ -98,6 +100,7 @@ _clang_getRangeStart
_clang_getResultType
_clang_getSpecializedCursorTemplate
_clang_getSpellingLocation
+_clang_getTUResourceUsageName
_clang_getTemplateCursorKind
_clang_getTokenExtent
_clang_getTokenKind
@@ -108,8 +111,8 @@ _clang_getTranslationUnitSpelling
_clang_getTypeDeclaration
_clang_getTypeKindSpelling
_clang_hashCursor
-_clang_isCursorDefinition
_clang_isConstQualifiedType
+_clang_isCursorDefinition
_clang_isDeclaration
_clang_isExpression
_clang_isInvalid
@@ -126,6 +129,7 @@ _clang_parseTranslationUnit
_clang_reparseTranslationUnit
_clang_saveTranslationUnit
_clang_sortCodeCompletionResults
+_clang_toggleCrashRecovery
_clang_tokenize
_clang_visitChildren
_clang_visitChildrenWithBlock
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index c2f0587b9ae8..4e96e8a0d6d7 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -21,6 +21,7 @@ clang_defaultEditingTranslationUnitOptions
clang_defaultReparseOptions
clang_defaultSaveOptions
clang_disposeCXCursorSet
+clang_disposeCXTUResourceUsage
clang_disposeCodeCompleteResults
clang_disposeDiagnostic
clang_disposeIndex
@@ -35,6 +36,7 @@ clang_equalTypes
clang_executeOnThread
clang_formatDiagnostic
clang_getCString
+clang_getCXTUResourceUsage
clang_getCXXAccessSpecifier
clang_getCanonicalCursor
clang_getCanonicalType
@@ -98,6 +100,7 @@ clang_getRangeStart
clang_getResultType
clang_getSpecializedCursorTemplate
clang_getSpellingLocation
+clang_getTUResourceUsageName
clang_getTemplateCursorKind
clang_getTokenExtent
clang_getTokenKind
@@ -126,6 +129,7 @@ clang_parseTranslationUnit
clang_reparseTranslationUnit
clang_saveTranslationUnit
clang_sortCodeCompletionResults
+clang_toggleCrashRecovery
clang_tokenize
clang_visitChildren
clang_visitChildrenWithBlock
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 5601387d794c..7793a8db49b1 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -147,9 +147,10 @@ sub GetCCArgs {
}
sub Analyze {
- my ($Clang, $Args, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir,
+ my ($Clang, $OriginalArgs, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir,
$file) = @_;
+ my @Args = @$OriginalArgs;
my $Cmd;
my @CmdArgs;
my @CmdArgsSansAnalyses;
@@ -166,41 +167,37 @@ sub Analyze {
else {
$Cmd = $Clang;
if ($Lang eq "objective-c" || $Lang eq "objective-c++") {
- push @$Args,'-DIBOutlet=__attribute__((iboutlet))';
- push @$Args,'-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection)))';
- push @$Args,'-DIBAction=void)__attribute__((ibaction)';
+ push @Args,'-DIBOutlet=__attribute__((iboutlet))';
+ push @Args,'-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection)))';
+ push @Args,'-DIBAction=void)__attribute__((ibaction)';
}
# Create arguments for doing regular parsing.
- my $SyntaxArgs = GetCCArgs("-fsyntax-only", $Args);
- @CmdArgsSansAnalyses = @CmdArgs;
- push @CmdArgsSansAnalyses, @$SyntaxArgs;
-
+ my $SyntaxArgs = GetCCArgs("-fsyntax-only", \@Args);
+ @CmdArgsSansAnalyses = @$SyntaxArgs;
+
# Create arguments for doing static analysis.
if (defined $ResultFile) {
- push @$Args,'-o';
- push @$Args, $ResultFile;
+ push @Args, '-o', $ResultFile;
}
elsif (defined $HtmlDir) {
- push @$Args,'-o';
- push @$Args, $HtmlDir;
+ push @Args, '-o', $HtmlDir;
+ }
+ if ($Verbose) {
+ push @Args, "-Xclang", "-analyzer-display-progress";
}
- push @$Args,"-Xclang";
- push @$Args,"-analyzer-display-progress";
foreach my $arg (@$AnalyzeArgs) {
- push @$Args, "-Xclang";
- push @$Args, $arg;
+ push @Args, "-Xclang", $arg;
}
-
+
# Display Ubiviz graph?
if (defined $ENV{'CCC_UBI'}) {
- push @$Args, "-Xclang";
- push @$Args,"-analyzer-viz-egraph-ubigraph";
+ push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph";
}
- my $AnalysisArgs = GetCCArgs("--analyze", $Args);
- push @CmdArgs, @$AnalysisArgs;
+ my $AnalysisArgs = GetCCArgs("--analyze", \@Args);
+ @CmdArgs = @$AnalysisArgs;
}
my @PrintArgs;
@@ -217,7 +214,7 @@ sub Analyze {
if ($Verbose == 1) {
# We MUST print to stderr. Some clients use the stdout output of
# gcc for various purposes.
- print STDERR join(' ',@PrintArgs);
+ print STDERR join(' ', @PrintArgs);
print STDERR "\n";
}
elsif ($Verbose == 2) {
@@ -368,9 +365,11 @@ my %LangMap = (
'cp' => 'c++',
'cpp' => 'c++',
'cc' => 'c++',
+ 'ii' => 'c++',
'i' => 'c-cpp-output',
'm' => 'objective-c',
- 'mi' => 'objective-c-cpp-output'
+ 'mi' => 'objective-c-cpp-output',
+ 'mm' => 'objective-c++'
);
my %UniqueOptions = (
@@ -383,14 +382,11 @@ my %UniqueOptions = (
my %LangsAccepted = (
"objective-c" => 1,
- "c" => 1
+ "c" => 1,
+ "c++" => 1,
+ "objective-c++" => 1
);
-if (defined $ENV{'CCC_ANALYZER_CPLUSPLUS'}) {
- $LangsAccepted{"c++"} = 1;
- $LangsAccepted{"objective-c++"} = 1;
-}
-
##----------------------------------------------------------------------------##
# Main Logic.
##----------------------------------------------------------------------------##
@@ -613,8 +609,7 @@ if ($Action eq 'compile' or $Action eq 'link') {
my @AnalyzeArgs;
if ($FileLang ne 'unknown') {
- push @CmdArgs,'-x';
- push @CmdArgs,$FileLang;
+ push @CmdArgs, '-x', $FileLang;
}
if (defined $StoreModel) {
@@ -625,9 +620,9 @@ if ($Action eq 'compile' or $Action eq 'link') {
push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
}
-# if (defined $Analyses) {
-# push @AnalyzeArgs, split '\s+', $Analyses;
-# }
+ if (defined $Analyses) {
+ push @AnalyzeArgs, split '\s+', $Analyses;
+ }
if (defined $OutputFormat) {
push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
@@ -646,8 +641,7 @@ if ($Action eq 'compile' or $Action eq 'link') {
if (scalar @Archs) {
foreach my $arch (@Archs) {
my @NewArgs;
- push @NewArgs, '-arch';
- push @NewArgs, $arch;
+ push @NewArgs, '-arch', $arch;
push @NewArgs, @CmdArgs;
Analyze($Clang, \@NewArgs, \@AnalyzeArgs, $FileLang, $Output,
$Verbose, $HtmlDir, $file);
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index f7e521f49ecb..f835ca3520c4 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -201,8 +201,8 @@ sub SetHtmlEnv {
die "No build command." if (scalar(@$Args) == 0);
my $Cmd = $$Args[0];
-
- if ($Cmd =~ /configure/) {
+
+ if ($Cmd =~ /configure/ || $Cmd =~ /autogen/) {
return;
}
@@ -290,7 +290,7 @@ sub AddStatLine {
print $Line . "\n";
my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
- \ CFGBlocks:\ (\d+)\ \|\ Aborted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
+ \ CFGBlocks:\ (\d+)\ \|\ Exhausted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
\ (yes|no)/x;
if ($Line !~ $Regex) {
@@ -1001,8 +1001,16 @@ ADVANCED OPTIONS:
-stats - Generates visitation statistics for the project being analyzed.
-maxloop N - specifiy the number of times a block can be visited before giving
- up. Default is 3. Increase for more comprehensive coverage at a
+ up. Default is 4. Increase for more comprehensive coverage at a
cost of speed.
+
+CONTROLLING CHECKERS:
+
+ A default group of checkers are always run unless explicitly disabled.
+ Checkers may be enabled/disabled using the following options:
+
+ -enable-checker [checker name]
+ -disable-checker [checker name]
ENDTEXT
# Query clang for list of checkers that are enabled.
@@ -1053,7 +1061,7 @@ else {
print("\nAVAILABLE CHECKERS:\n\n");
my $skip = 0;
while(<FROM_CHILD>) {
- if (/core\.experimental/ or /debug\./ or /unix.experimental/ or /cocoa.experimental/) {
+ if (/experimental/) {
$skip = 1;
next;
}
@@ -1305,6 +1313,16 @@ while (@ARGV) {
$MaxLoop = shift @ARGV;
next;
}
+ if ($arg eq "-enable-checker") {
+ shift @ARGV;
+ push @AnalysesToRun, "-analyzer-checker", shift @ARGV;
+ next;
+ }
+ if ($arg eq "-disable-checker") {
+ shift @ARGV;
+ push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV;
+ next;
+ }
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
@@ -1365,7 +1383,7 @@ if ($AnalyzeHeaders) {
push @AnalysesToRun,"-analyzer-opt-analyze-headers";
}
if ($AnalyzerStats) {
- push @AnalysesToRun, '-analyzer-stats';
+ push @AnalysesToRun, '-analyzer-checker', 'debug.Stats';
}
if ($MaxLoop > 0) {
push @AnalysesToRun, '-analyzer-max-loop ' . $MaxLoop;
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 112d6a0e509c..f7f495ee9dd7 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -59,3 +59,13 @@ add_clang_unittest(Frontend
Frontend/FrontendActionTest.cpp
USED_LIBS gtest gtest_main clangFrontend
)
+
+add_clang_unittest(Tooling
+ Tooling/ToolingTest.cpp
+ USED_LIBS gtest gtest_main clangTooling
+ )
+
+add_clang_unittest(JsonCompileCommandLineDatabase
+ Tooling/JsonCompileCommandLineDatabaseTest.cpp
+ USED_LIBS gtest gtest_main clangTooling
+ )
diff --git a/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp b/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp
new file mode 100644
index 000000000000..d875293e5d85
--- /dev/null
+++ b/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp
@@ -0,0 +1,232 @@
+//===- unittest/Tooling/JsonCompileCommandLineDatabaseTest ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../../lib/Tooling/JsonCompileCommandLineDatabase.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+TEST(UnescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine("");
+ EXPECT_TRUE(Result.empty());
+}
+
+TEST(UnescapeJsonCommandLine, SplitsOnSpaces) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine("a b c");
+ ASSERT_EQ(3ul, Result.size());
+ EXPECT_EQ("a", Result[0]);
+ EXPECT_EQ("b", Result[1]);
+ EXPECT_EQ("c", Result[2]);
+}
+
+TEST(UnescapeJsonCommandLine, MungesMultipleSpaces) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine(" a b ");
+ ASSERT_EQ(2ul, Result.size());
+ EXPECT_EQ("a", Result[0]);
+ EXPECT_EQ("b", Result[1]);
+}
+
+TEST(UnescapeJsonCommandLine, UnescapesBackslashCharacters) {
+ std::vector<std::string> Backslash = UnescapeJsonCommandLine("a\\\\\\\\");
+ ASSERT_EQ(1ul, Backslash.size());
+ EXPECT_EQ("a\\", Backslash[0]);
+ std::vector<std::string> Quote = UnescapeJsonCommandLine("a\\\\\\\"");
+ ASSERT_EQ(1ul, Quote.size());
+ EXPECT_EQ("a\"", Quote[0]);
+}
+
+TEST(UnescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine("\\\" a b \\\"");
+ ASSERT_EQ(1ul, Result.size());
+ EXPECT_EQ(" a b ", Result[0]);
+}
+
+TEST(UnescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine(
+ " \\\" a \\\" \\\" b \\\" ");
+ ASSERT_EQ(2ul, Result.size());
+ EXPECT_EQ(" a ", Result[0]);
+ EXPECT_EQ(" b ", Result[1]);
+}
+
+TEST(UnescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine(
+ "\\\"\\\"\\\"\\\"");
+ ASSERT_EQ(1ul, Result.size());
+ EXPECT_TRUE(Result[0].empty()) << Result[0];
+}
+
+TEST(UnescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine(
+ "\\\"\\\\\\\"\\\"");
+ ASSERT_EQ(1ul, Result.size());
+ EXPECT_EQ("\"", Result[0]);
+}
+
+TEST(UnescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
+ std::vector<std::string> Result = UnescapeJsonCommandLine(
+ " \\\\\\\" \\\"a \\\\\\\" b \\\" \\\"and\\\\\\\\c\\\" \\\\\\\"");
+ ASSERT_EQ(4ul, Result.size());
+ EXPECT_EQ("\"", Result[0]);
+ EXPECT_EQ("a \" b ", Result[1]);
+ EXPECT_EQ("and\\c", Result[2]);
+ EXPECT_EQ("\"", Result[3]);
+}
+
+TEST(UnescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
+ std::vector<std::string> QuotedNoSpaces = UnescapeJsonCommandLine(
+ "\\\"a\\\"\\\"b\\\"");
+ ASSERT_EQ(1ul, QuotedNoSpaces.size());
+ EXPECT_EQ("ab", QuotedNoSpaces[0]);
+
+ std::vector<std::string> MixedNoSpaces = UnescapeJsonCommandLine(
+ "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
+ ASSERT_EQ(1ul, MixedNoSpaces.size());
+ EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnEmptyString) {
+ JsonCompileCommandLineParser Parser("", NULL);
+ EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, DoesNotReadAfterInput) {
+ JsonCompileCommandLineParser Parser(llvm::StringRef(NULL, 0), NULL);
+ EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyArray) {
+ JsonCompileCommandLineParser Parser("[]", NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfNotClosingArray) {
+ JsonCompileCommandLineParser JustOpening("[", NULL);
+ EXPECT_FALSE(JustOpening.Parse()) << JustOpening.GetErrorMessage();
+ JsonCompileCommandLineParser WithSpaces(" [ ", NULL);
+ EXPECT_FALSE(WithSpaces.Parse()) << WithSpaces.GetErrorMessage();
+ JsonCompileCommandLineParser WithGarbage(" [x", NULL);
+ EXPECT_FALSE(WithGarbage.Parse()) << WithGarbage.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyArrayWithWhitespace) {
+ JsonCompileCommandLineParser Spaces(" [ ] ", NULL);
+ EXPECT_TRUE(Spaces.Parse()) << Spaces.GetErrorMessage();
+ JsonCompileCommandLineParser AllWhites("\t\r\n[\t\n \t\r ]\t\r \n\n", NULL);
+ EXPECT_TRUE(AllWhites.Parse()) << AllWhites.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfNotStartingArray) {
+ JsonCompileCommandLineParser ObjectStart("{", NULL);
+ EXPECT_FALSE(ObjectStart.Parse()) << ObjectStart.GetErrorMessage();
+ // We don't implement a full JSON parser, and thus parse only a subset
+ // of valid JSON.
+ JsonCompileCommandLineParser Object("{}", NULL);
+ EXPECT_FALSE(Object.Parse()) << Object.GetErrorMessage();
+ JsonCompileCommandLineParser Character("x", NULL);
+ EXPECT_FALSE(Character.Parse()) << Character.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyObject) {
+ JsonCompileCommandLineParser Parser("[{}]", NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesObject) {
+ JsonCompileCommandLineParser Parser("[{\"a\":\"/b\"}]", NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesMultipleKeyValuePairsInObject) {
+ JsonCompileCommandLineParser Parser(
+ "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]", NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfNotClosingObject) {
+ JsonCompileCommandLineParser MissingCloseOnEmpty("[{]", NULL);
+ EXPECT_FALSE(MissingCloseOnEmpty.Parse())
+ << MissingCloseOnEmpty.GetErrorMessage();
+ JsonCompileCommandLineParser MissingCloseAfterPair("[{\"a\":\"b\"]", NULL);
+ EXPECT_FALSE(MissingCloseAfterPair.Parse())
+ << MissingCloseAfterPair.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfMissingColon) {
+ JsonCompileCommandLineParser StringString("[{\"a\"\"/b\"}]", NULL);
+ EXPECT_FALSE(StringString.Parse()) << StringString.GetErrorMessage();
+ JsonCompileCommandLineParser StringSpaceString("[{\"a\" \"b\"}]", NULL);
+ EXPECT_FALSE(StringSpaceString.Parse())
+ << StringSpaceString.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnMissingQuote) {
+ JsonCompileCommandLineParser OpenQuote("[{a\":\"b\"}]", NULL);
+ EXPECT_FALSE(OpenQuote.Parse()) << OpenQuote.GetErrorMessage();
+ JsonCompileCommandLineParser CloseQuote("[{\"a\":\"b}]", NULL);
+ EXPECT_FALSE(CloseQuote.Parse()) << CloseQuote.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEscapedQuotes) {
+ JsonCompileCommandLineParser Parser(
+ "[{\"a\":\"\\\"b\\\" \\\" \\\"\"}]", NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyString) {
+ JsonCompileCommandLineParser Parser("[{\"a\":\"\"}]", NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnMissingString) {
+ JsonCompileCommandLineParser MissingValue("[{\"a\":}]", NULL);
+ EXPECT_FALSE(MissingValue.Parse()) << MissingValue.GetErrorMessage();
+ JsonCompileCommandLineParser MissingKey("[{:\"b\"}]", NULL);
+ EXPECT_FALSE(MissingKey.Parse()) << MissingKey.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesMultipleObjects) {
+ JsonCompileCommandLineParser Parser(
+ "["
+ " { \"a\" : \"b\" },"
+ " { \"a\" : \"b\" },"
+ " { \"a\" : \"b\" }"
+ "]", NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnMissingComma) {
+ JsonCompileCommandLineParser Parser(
+ "["
+ " { \"a\" : \"b\" }"
+ " { \"a\" : \"b\" }"
+ "]", NULL);
+ EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnSuperfluousComma) {
+ JsonCompileCommandLineParser Parser(
+ "[ { \"a\" : \"b\" }, ]", NULL);
+ EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesSpacesInBetweenTokens) {
+ JsonCompileCommandLineParser Parser(
+ " \t \n\n \r [ \t \n\n \r"
+ " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
+ " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r"
+ " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
+ " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r",
+ NULL);
+ EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
new file mode 100644
index 000000000000..6e5bc6b613e0
--- /dev/null
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -0,0 +1,175 @@
+//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Twine.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+/// Takes an ast consumer and returns it from CreateASTConsumer. This only
+/// works with single translation unit compilations.
+class TestAction : public clang::ASTFrontendAction {
+ public:
+ /// Takes ownership of TestConsumer.
+ explicit TestAction(clang::ASTConsumer *TestConsumer)
+ : TestConsumer(TestConsumer) {}
+
+ protected:
+ virtual clang::ASTConsumer* CreateASTConsumer(
+ clang::CompilerInstance& compiler, llvm::StringRef dummy) {
+ /// TestConsumer will be deleted by the framework calling us.
+ return TestConsumer;
+ }
+
+ private:
+ clang::ASTConsumer * const TestConsumer;
+};
+
+class FindTopLevelDeclConsumer : public clang::ASTConsumer {
+ public:
+ explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
+ : FoundTopLevelDecl(FoundTopLevelDecl) {}
+ virtual void HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) {
+ *FoundTopLevelDecl = true;
+ }
+ private:
+ bool * const FoundTopLevelDecl;
+};
+} // end namespace
+
+TEST(RunSyntaxOnlyToolOnCode, FindsTopLevelDeclOnEmptyCode) {
+ bool FoundTopLevelDecl = false;
+ EXPECT_TRUE(RunSyntaxOnlyToolOnCode(
+ new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
+ EXPECT_TRUE(FoundTopLevelDecl);
+}
+
+namespace {
+class FindClassDeclXConsumer : public clang::ASTConsumer {
+ public:
+ FindClassDeclXConsumer(bool *FoundClassDeclX)
+ : FoundClassDeclX(FoundClassDeclX) {}
+ virtual void HandleTopLevelDecl(clang::DeclGroupRef GroupRef) {
+ if (CXXRecordDecl* Record = llvm::dyn_cast<clang::CXXRecordDecl>(
+ *GroupRef.begin())) {
+ if (Record->getName() == "X") {
+ *FoundClassDeclX = true;
+ }
+ }
+ }
+ private:
+ bool *FoundClassDeclX;
+};
+} // end namespace
+
+TEST(RunSyntaxOnlyToolOnCode, FindsClassDecl) {
+ bool FoundClassDeclX = false;
+ EXPECT_TRUE(RunSyntaxOnlyToolOnCode(new TestAction(
+ new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;"));
+ EXPECT_TRUE(FoundClassDeclX);
+
+ FoundClassDeclX = false;
+ EXPECT_TRUE(RunSyntaxOnlyToolOnCode(new TestAction(
+ new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;"));
+ EXPECT_FALSE(FoundClassDeclX);
+}
+
+TEST(FindCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
+ std::string ErrorMessage;
+ CompileCommand NotFound = FindCompileArgsInJsonDatabase(
+ "a-file.cpp", "", ErrorMessage);
+ EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
+ EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, ReadsSingleEntry) {
+ llvm::StringRef Directory("/some/directory");
+ llvm::StringRef FileName("/path/to/a-file.cpp");
+ llvm::StringRef Command("/path/to/compiler and some arguments");
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+ FileName,
+ (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+ EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
+ ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
+ EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
+ EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
+ EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
+
+ CompileCommand NotFound = FindCompileArgsInJsonDatabase(
+ "a-file.cpp",
+ (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+ EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
+ EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
+ llvm::StringRef Directory("/some/directory");
+ llvm::StringRef FileName("/path/to/a-file.cpp");
+ llvm::StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+ FileName,
+ (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+ ASSERT_EQ(2u, FoundCommand.CommandLine.size());
+ EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
+ llvm::StringRef Directory("/some directory / with spaces");
+ llvm::StringRef FileName("/path/to/a-file.cpp");
+ llvm::StringRef Command("a command");
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+ FileName,
+ (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+ EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, FindsEntry) {
+ llvm::StringRef Directory("directory");
+ llvm::StringRef FileName("file");
+ llvm::StringRef Command("command");
+ std::string JsonDatabase = "[";
+ for (int I = 0; I < 10; ++I) {
+ if (I > 0) JsonDatabase += ",";
+ JsonDatabase += (llvm::Twine(
+ "{\"directory\":\"") + Directory + llvm::Twine(I) + "\"," +
+ "\"command\":\"" + Command + llvm::Twine(I) + "\","
+ "\"file\":\"" + FileName + llvm::Twine(I) + "\"}").str();
+ }
+ JsonDatabase += "]";
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+ "file4", JsonDatabase, ErrorMessage);
+ EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
+ ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
+ EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
+}
+
+} // end namespace tooling
+} // end namespace clang
+
diff --git a/utils/CmpDriver b/utils/CmpDriver
index 16b108117d3e..2533f547e973 100755
--- a/utils/CmpDriver
+++ b/utils/CmpDriver
@@ -55,7 +55,7 @@ def insertMinimumPadding(a, b, dist):
return a,b
class ZipperDiff(object):
- """ZipperDiff - Simple (slow) diff only accomodating inserts."""
+ """ZipperDiff - Simple (slow) diff only accommodating inserts."""
def __init__(self, a, b):
self.a = a
diff --git a/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c b/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c
index d22c0bd0bca0..e527789d4f01 100644
--- a/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c
+++ b/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c
@@ -1,4 +1,4 @@
-/* This file tests that we can succesfully call each compiler-rt function. It is
+/* This file tests that we can successfully call each compiler-rt function. It is
designed to check that the runtime libraries are available for linking and
that they contain the expected contents. It is not designed to test the
correctness of the individual functions in compiler-rt.
diff --git a/www/OpenProjects.html b/www/OpenProjects.html
index 52fcabebbaa4..b3e0841a73a1 100644
--- a/www/OpenProjects.html
+++ b/www/OpenProjects.html
@@ -100,6 +100,13 @@ experience -- it should be easy to cross compile applications, install support
for new architectures, access different compilers and tools, and be consistent
across different platforms. See the <a href="UniversalDriver.html">Universal
Driver</a> web page for more information.</li>
+
+<li><b>XML Representation of ASTs</b>: Clang maintains a rich Abstract Syntax Tree that describes the program. Clang could emit an XML document that describes the program, which others tools could consume rather than being tied directly to the Clang binary.The XML representation needs to meet several requirements:
+ <ul>
+ <li><i>General</i>, so that it's able to represent C/C++/Objective-C abstractly, and isn't tied to the specific internal ASTs that Clang uses.</li>
+ <li><i>Documented</i>, with appropriate Schema against which the output of Clang's XML formatter can be verified.</li>
+ <li><i>Stable</i> across Clang versions.</li>
+ </ul></li>
</ul>
</div>
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 7cd6b2bff5de..99151a899191 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="/checker/checker-255.tar.bz2">checker-255.tar.bz2</a></b> (built February 11, 2011)
+<b><a href="/checker/checker-256.tar.bz2">checker-256.tar.bz2</a></b> (built April 13, 2011)
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index 7b6924fa344d..163e84f372b2 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -15,6 +15,56 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<h4 id="checker_256">checker-256</h4>
+
+<p><b>built:</b> April 13, 2011<br>
+<b>download:</b> <a href="/checker/checker-256.tar.bz2">checker-256.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<ul>
+ <li>Lots of bug fixes and improvements to analyzer precision (fewer false positives, possibly more bugs found).
+ <li>Introductory analysis support for C++ and Objective-C++.
+</ul>
+
+<p>This build contains basic support for C++ and Objective-C++ that is ready to be tried out
+ by general users. It is still in its infancy, but establishes a baseline for things to come. The main hope is that it can find some
+ issues and have a reasonable false positive rate.</p>
+
+<p><b>Please</b> <a href="/filing_bugs.html">file bugs</a> when you see issues of any kind so we can assess
+ where development on C++ analysis support needs to be focused.</p>
+
+<p>To try out C++ analysis support, it should work out of the box using <tt>scan-build</tt>. If you are using this checker build
+ as a replacement to the analyzer bundled with Xcode, first use the <tt>set-xcode-analyzer</tt> script to <a href="/xcode.html">change Xcode to use
+ your version of the analyzer</a>. You will then need to modify one configuration file in Xcode to enable C++ analysis support. This can
+ be done with the following steps:</p>
+
+<ol>
+ <li>Find the clang .xcspec file:
+<pre>$ cd /Developer/Library
+$ find . | grep xcspec | grep Clang
+./Xcode/<b>&lt;SNIP&gt;</b>/Clang LLVM 1.0.xcplugin/Contents/Resources/Clang LLVM 1.0.xcspec
+</pre></li>
+ <li>The exact location of the file may vary depending on your installation of Xcode. Edit that file, and look for the string &quot;--analyze&quot;:
+<pre>
+ SourceFileOption = "--analyze";
+ FileTypes = (
+ "sourcecode.c.c",
+ "sourcecode.c.objc",
+ );
+ ...
+</pre>
+ Change the &quot;FileTypes&quot; entry to:
+<pre>
+ FileTypes = (
+ "sourcecode.c.c",
+ "sourcecode.c.objc",
+ "sourcecode.cpp.cpp",
+ "sourcecode.cpp.objcpp",
+ );
+</pre></li>
+<li>Restart Xcode.</li>
+</ol>
+
<h4 id="checker_255">checker-255</h4>
<p><b>built:</b> February 11, 2011<br>
diff --git a/www/analyzer/scan-build.html b/www/analyzer/scan-build.html
index 1db15fec99eb..6c2833e7991f 100644
--- a/www/analyzer/scan-build.html
+++ b/www/analyzer/scan-build.html
@@ -293,7 +293,7 @@ following things in mind:</p>
this as your configuration with Xcode or by passing <tt>-configuration
Debug</tt> to <tt>xcodebuild</tt>.</li>
<li>Analyze your project using the <tt>Simulator</tt> as your base SDK. It is
-possible to analyze your code when targetting the device, but this is much
+possible to analyze your code when targeting the device, but this is much
easier to do when using Xcode's <i>Build and Analyze</i> feature.</li>
<li>Check that your code signing SDK is set to the simulator SDK as well, and make sure this option is set to <tt>Don't Code Sign</tt>.</li>
</ul>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index e4a915a4b298..5545a813d392 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -25,7 +25,7 @@
<!--*************************************************************************-->
<h1>C++ and C++'0x Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2011-02-23 01:41:16 +0100 (Wed, 23 Feb 2011) $</p>
+<p>Last updated: $Date: 2011-05-01 09:04:31 +0200 (Sun, 01 May 2011) $</p>
<ul>
<li><a href="#projects">Projects Building with Clang</a></li>
@@ -85,6 +85,11 @@
ISO C++ standard (1998/2003). This section tracks the status of various C++0x
features.</p>
+<p>You can use clang in C++0x mode either
+with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++.
+libstdc++-4.4 requires <a href="libstdc++4.4-clang0x.patch">a patch</a> to work
+with clang; other versions have not been tested.</p>
+
<h2 id="specification">Implementation Status by Feature</h2>
@@ -168,7 +173,7 @@ components are:</p>
welcome!</p>
<table width="689" border="1" cellspacing="0">
-<tr><td colspan="7" align="center" bgcolor="#ffddaa">C++0x Features (current draft report <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf">here</a>) </td>
+<tr><td colspan="7" align="center" bgcolor="#ffddaa">C++0x Features (current draft report <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3291.pdf">here</a>)</td>
</tr>
<tr>
<th>Feature</th>
@@ -182,12 +187,13 @@ welcome!</p>
<tr><td colspan="7" class="category">Control Flow Modifications</td></tr>
<tr>
<td>Range-based for loop</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
<td>6.5.4</td>
- <td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2243.html">N2243</a></td>
+ <td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2243.html">N2243</a>
+ <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3271.htm">N3271</a></td>
</tr>
<tr><td colspan="7" class="category">Type System Modifications</td></tr>
@@ -216,10 +222,10 @@ welcome!</p>
</tr>
<tr>
<td>auto type deduction</td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
- <td class="complete" align="center"></td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
<td>7.1.6.2, 7.1.6.4</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">N1984</a></td>
</tr>
@@ -310,7 +316,7 @@ welcome!</p>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2378.pdf">N2378</a></td>
</tr>
<tr>
- <td>POD defintion changes</td>
+ <td>POD definition changes</td>
<td></td>
<td></td>
<td></td>
@@ -342,10 +348,10 @@ welcome!</p>
<tr><td colspan="7" class="category">Class Modifications</td></tr>
<tr>
<td>delegating constructors</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
+ <td class="complete"></td>
+ <td class="complete"></td>
+ <td class="complete"></td>
+ <td class="complete"></td>
<td>12.6.2</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986">N1986</a></td>
</tr>
@@ -454,14 +460,14 @@ welcome!</p>
</tr>
<tr>
<td>template aliases</td>
- <td></td>
- <td></td>
- <td></td>
+ <td class="basic"></td>
+ <td class="basic"></td>
+ <td class="basic"></td>
<td></td>
<td>7.1.3, 14.6.7</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf">N1489</a>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a>
- Includes non-template type aliasing
+ Only non-template type aliases implemented
</td>
</tr>
<tr>
@@ -515,7 +521,7 @@ welcome!</p>
<tr><td colspan="7" class="category">Preprocessor Modifications</td></tr>
<tr>
<td>__STDC_HOSTED__</td>
- <td></td>
+ <td class="complete"></td>
<td class="na">N/A</td>
<td class="na">N/A</td>
<td class="na">N/A</td>
@@ -580,10 +586,10 @@ welcome!</p>
<tr><td colspan="7" class="category">Things Completely New</td></tr>
<tr>
<td>Late-specified return type</td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="basic"></td>
<td>8.3.5</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2445.html">N2445</a></td>
</tr>
diff --git a/www/get_started.html b/www/get_started.html
index 54f7442b88bb..f8745f96bcbc 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -129,15 +129,15 @@ Visual Studio:</p>
<li><b>Python</b>. This is needed only if you will be running the tests
(which is essential, if you will be developing for clang).
Get it from:
- <a href="http://www.python.org/download">
- http://www.python.org/download</a></li>
+ <a href="http://www.python.org/download/">
+ http://www.python.org/download/</a></li>
<li><b>GnuWin32 tools</b>
These are also necessary for running the tests.
(Note that the grep from MSYS or Cygwin doesn't work with the tests
because of embedded double-quotes in the search strings. The GNU
grep does work in this case.)
- Get them from <a href="http://getgnuwin32.sourceforge.net">
- http://getgnuwin32.sourceforge.net</a>.</li>
+ Get them from <a href="http://getgnuwin32.sourceforge.net/">
+ http://getgnuwin32.sourceforge.net/</a>.</li>
</ul>
<li>Checkout LLVM:</li>
@@ -157,6 +157,13 @@ Visual Studio:</p>
<li>If you are using Visual Studio 2005: <tt>cmake -G "Visual Studio 8 2005" ..\llvm</tt></li>
<li>Or if you are using Visual Studio 2008: <tt>cmake -G "Visual Studio 9 2008" ..\llvm</tt></li>
<li>Or if you are using Visual Studio 2010: <tt>cmake -G "Visual Studio 10" ..\llvm</tt></li>
+ <li>By default, cmake will target LLVM to X86. If you want all targets
+ (needed if you want to run the LLVM tests), add the <tt>-DLLVM_TARGETS_TO_BUILD=all</tt> option to the
+ cmake command line. Or specify a target from the LLVM_TARGETS_TO_BUILD
+ definition in CMakeLists.txt.</li>
+ <li>See the <a href="http://www.llvm.org/docs/CMake.html">LLVM CMake guide</a> for
+ more information on other configuration options for cmake.</li>
+</li>
<li>The above, if successful, will have created an LLVM.sln file in the
llvm directory.
</ul>
diff --git a/www/hacking.html b/www/hacking.html
index 978c99f14139..969a39c55998 100644
--- a/www/hacking.html
+++ b/www/hacking.html
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
@@ -14,7 +14,7 @@
<!--*********************************************************************-->
<h1>Hacking on Clang</h1>
<!--*********************************************************************-->
-
+
<p>This document provides some hints for how to get started hacking
on Clang for developers who are new to the Clang and/or LLVM
codebases.</p>
@@ -24,18 +24,18 @@
<li><a href="#debugging">Debugging</a></li>
<li><a href="#testing">Testing</a></li>
<ul>
- <li><a href="#testingNonWindows">Testing on Unix-like Systems</a></li>
- <li><a href="#testingWindows">Testing using Visual Studio on Windows</a></li>
- <li><a href="#testingCommands">Testing on the Command Line</a></li>
- </ul>
+ <li><a href="#testingNonWindows">Testing on Unix-like Systems</a></li>
+ <li><a href="#testingWindows">Testing using Visual Studio on Windows</a></li>
+ <li><a href="#testingCommands">Testing on the Command Line</a></li>
+ </ul>
<li><a href="#patches">Creating Patch Files</a></li>
<li><a href="#irgen">LLVM IR Generation</a></li>
</ul>
-
+
<!--=====================================================================-->
<h2 id="docs">Coding Standards</h2>
<!--=====================================================================-->
-
+
<p>Clang follows the
LLVM <a href="http://llvm.org/docs/CodingStandards.html">Coding
Standards</a>. When submitting patches, please take care to follow these standards
@@ -56,14 +56,14 @@
<!--=====================================================================-->
<h2 id="docs">Developer Documentation</h2>
<!--=====================================================================-->
-
+
<p>Both Clang and LLVM use doxygen to provide API documentation. Their
respective web pages (generated nightly) are here:</p>
<ul>
<li><a href="http://clang.llvm.org/doxygen">Clang</a></li>
<li><a href="http://llvm.org/doxygen">LLVM</a></li>
</ul>
-
+
<p>For work on the LLVM IR generation, the LLVM assembly language
<a href="http://llvm.org/docs/LangRef.html">reference manual</a> is
also useful.</p>
@@ -71,7 +71,7 @@
<!--=====================================================================-->
<h2 id="debugging">Debugging</h2>
<!--=====================================================================-->
-
+
<p>Inspecting data structures in a debugger:</p>
<ul>
<li>Many LLVM and Clang data structures provide
@@ -84,18 +84,18 @@
qualifiers, and the <tt>getTypePtr()</tt> method to get the
wrapped <tt>Type*</tt> which you can then dump.</li>
</ul>
-
+
<!--=====================================================================-->
<h2 id="testing">Testing</h2>
<!--=====================================================================-->
-
+
<p><i>[Note: The test running mechanism is currently under revision, so the
following might change shortly.]</i></p>
-
+
<!--=====================================================================-->
<h3 id="testingNonWindows">Testing on Unix-like Systems</h3>
<!--=====================================================================-->
-
+
<p>Clang includes a basic regression suite in the tree which can be
run with <tt>make test</tt> from the top-level clang directory, or
just <tt>make</tt> in the <em>test</em> sub-directory.
@@ -113,15 +113,15 @@
the test runner that an error is expected at the current line.
Any output files produced by the test will be placed under
a created Output directory.</p>
-
+
<p>During the run of <tt>make test</tt>, the terminal output will
display a line similar to the following:</p>
-
+
<ul><tt>--- Running clang tests for i686-pc-linux-gnu ---</tt></ul>
-
+
<p>followed by a line continually overwritten with the current test
file being compiled, and an overall completion percentage.</p>
-
+
<p>After the <tt>make test</tt> run completes, the absence of any
<tt>Failing Tests (count):</tt> message indicates that no tests
failed unexpectedly. If any tests did fail, the
@@ -148,38 +148,46 @@
override LLVMGCC, as in: <tt>make LLVMGCC="clang -std=gnu89"
TEST=nightly report</tt> (make sure <tt>clang</tt> is in your PATH or use the
full path).</p>
-
+
<!--=====================================================================-->
<h3 id="testingWindows">Testing using Visual Studio on Windows</h3>
<!--=====================================================================-->
<p>The Clang test suite can be run from either Visual Studio or
the command line.</p>
-
+
<p>Note that the test runner is based on
Python, which must be installed. Find Python at:
- <a href="http://www.python.org/download">http://www.python.org/download</a>.
+ <a href="http://www.python.org/download/">http://www.python.org/download/</a>.
Download the latest stable version (2.6.2 at the time of this writing).</p>
-
+
<p>The GnuWin32 tools are also necessary for running the tests.
- (Note that the grep from MSYS or Cygwin doesn't work with the tests
- because of embedded double-quotes in the search strings. The GNU
- grep does work in this case.)
- Get them from <a href="http://getgnuwin32.sourceforge.net">
- http://getgnuwin32.sourceforge.net</a>.</p>
-
+ Get them from <a href="http://getgnuwin32.sourceforge.net/">
+ http://getgnuwin32.sourceforge.net/</a>.
+ If the environment variable <tt>%PATH%</tt> does not have GnuWin32,
+ or if other grep(s) supercedes GnuWin32 on <tt>%PATH%,</tt>
+ you should specify <tt>LLVM_LIT_TOOLS_DIR</tt>
+ to CMake explicitly.</p>
+
<p>The cmake build tool is set up to create Visual Studio project files
for running the tests, "clang-test" being the root. Therefore, to
run the test from Visual Studio, right-click the clang-test project
and select "Build".</p>
-
+
+ <p>
+ Please see also
+ <a href="http://llvm.org/docs/GettingStartedVS.html">Getting Started
+ with the LLVM System using Microsoft Visual Studio</a> and
+ <a href="http://llvm.org/docs/CMake.html">Building LLVM with CMake</a>.
+ </p>
+
<!--=====================================================================-->
<h3 id="testingCommands">Testing on the Command Line</h3>
<!--=====================================================================-->
<p>To run all the tests from the command line, execute a command like
the following:</p>
-
+
<tt>
python (path to llvm)/llvm/utils/lit/lit.py -sv --no-progress-bar
(path to llvm)/llvm/tools/clang/test
@@ -190,14 +198,14 @@
<tt>--param=build_config=(build config)</tt>.</p>
<p>To run a single test:</p>
-
+
<tt>
python (path to llvm)/llvm/utils/lit/lit.py -sv --no-progress-bar
(path to llvm)/llvm/tools/clang/test/(dir)/(test)
</tt>
<p>For example:</p>
-
+
<tt>
python C:/Tools/llvm/utils/lit/lit.py -sv --no-progress-bar
C:/Tools/llvm/tools/clang/test/Sema/wchar.c
@@ -215,7 +223,7 @@ Testing Time: 81.52s
Expected Passes : 2503
Expected Failures : 28
Unsupported Tests : 3
-</pre></tt>
+</pre></tt>
<p>The statistic, "Unexpected Failures" (not shown if all tests pass), is the important one.</p>
@@ -224,24 +232,24 @@ Testing Time: 81.52s
<!--=====================================================================-->
<p>To return changes to the Clang team, unless you have checkin
- privileges, the prefered way is to send patch files to the
+ privileges, the preferred way is to send patch files to the
cfe-commits mailing list, with an explanation of what the patch is for.
Or, if you have questions, or want to have a wider discussion of what
you are doing, such as if you are new to Clang development, you can use
the cfe-dev mailing list also.
</p>
-
+
<p>To create these patch files, change directory
to the llvm/tools/clang root and run:</p>
-
+
<ul><tt>svn diff (relative path) >(patch file name)</tt></ul>
<p>For example, for getting the diffs of all of clang:</p>
-
+
<ul><tt>svn diff . >~/mypatchfile.patch</tt></ul>
<p>For example, for getting the diffs of a single file:</p>
-
+
<ul><tt>svn diff lib/Parse/ParseDeclCXX.cpp >~/ParseDeclCXX.patch</tt></ul>
<p>Note that the paths embedded in the patch depend on where you run it,
@@ -256,7 +264,7 @@ Testing Time: 81.52s
Representation (IR). Historically, this was referred to as
"codegen", and the Clang code for this lives
in <tt>lib/CodeGen</tt>.</p>
-
+
<p>The output is most easily inspected using the <tt>-emit-llvm</tt>
option to clang (possibly in conjunction with <tt>-o -</tt>). You
can also use <tt>-emit-llvm-bc</tt> to write an LLVM bitcode file
diff --git a/www/libstdc++4.4-clang0x.patch b/www/libstdc++4.4-clang0x.patch
new file mode 100644
index 000000000000..8b9916dd69f1
--- /dev/null
+++ b/www/libstdc++4.4-clang0x.patch
@@ -0,0 +1,369 @@
+This patch was generated from the headers installed by MacPorts
+gcc-4.4 on OS X 10.6. You can apply it there with
+`cd /opt/local/include/gcc44/c++ ; sudo patch -p1 <this_patch`, or similar
+on other operating systems. Mail cfe-dev if you find other problems in the
+standard headers.
+
+This patch is offered under the same modified GPLv3 as libstdc++-4.4.
+
+diff -ur a/bits/move.h b/bits/move.h
+--- a/bits/move.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/move.h 2011-03-29 10:33:39.000000000 -0700
+@@ -48,13 +48,35 @@
+
+ template<typename _Tp>
+ inline _Tp&&
+- forward(typename std::identity<_Tp>::type&& __t)
++ forward(typename std::remove_reference<_Tp>::type& __t)
++#ifdef __clang__
++ { return static_cast<_Tp&&>(__t); }
++#else
+ { return __t; }
++#endif
++
++ template<typename _Tp>
++ inline _Tp&&
++ forward(typename std::remove_reference<_Tp>::type&& __t)
++ {
++#ifdef __clang__
++ static_assert(!std::is_lvalue_reference<_Tp>::value,
++ "Can't instantiate this forward() with an"
++ " lvalue reference type.");
++ return static_cast<_Tp&&>(__t);
++#else
++ return __t;
++#endif
++ }
+
+ template<typename _Tp>
+ inline typename std::remove_reference<_Tp>::type&&
+ move(_Tp&& __t)
++#ifdef __clang__
++ { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
++#else
+ { return __t; }
++#endif
+
+ _GLIBCXX_END_NAMESPACE
+
+diff -ur a/bits/stl_deque.h b/bits/stl_deque.h
+--- a/bits/stl_deque.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_deque.h 2011-03-29 10:33:39.000000000 -0700
+@@ -1395,11 +1395,7 @@
+ * std::swap(d1,d2) will feed to this function.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(deque&& __x)
+-#else
+ swap(deque& __x)
+-#endif
+ {
+ std::swap(this->_M_impl._M_start, __x._M_impl._M_start);
+ std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish);
+diff -ur a/bits/stl_iterator.h b/bits/stl_iterator.h
+--- a/bits/stl_iterator.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_iterator.h 2011-03-29 10:33:39.000000000 -0700
+@@ -913,7 +913,7 @@
+
+ reference
+ operator*() const
+- { return *_M_current; }
++ { return std::move(*_M_current); }
+
+ pointer
+ operator->() const
+diff -ur a/bits/stl_list.h b/bits/stl_list.h
+--- a/bits/stl_list.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_list.h 2011-03-29 10:33:39.000000000 -0700
+@@ -1106,11 +1106,7 @@
+ * function.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(list&& __x)
+-#else
+ swap(list& __x)
+-#endif
+ {
+ _List_node_base::swap(this->_M_impl._M_node, __x._M_impl._M_node);
+
+@@ -1160,6 +1156,12 @@
+ }
+ }
+
++#ifdef __GXX_EXPERIMENTAL_CXX0X__
++ void
++ splice(iterator __position, list& __x)
++ { splice(__position, std::move(__x)); }
++#endif
++
+ /**
+ * @brief Insert element from another %list.
+ * @param position Iterator referencing the element to insert before.
+@@ -1187,6 +1189,12 @@
+ this->_M_transfer(__position, __i, __j);
+ }
+
++#ifdef __GXX_EXPERIMENTAL_CXX0X__
++ void
++ splice(iterator __position, list& __x, iterator __i)
++ { splice(__position, std::move(__x), __i); }
++#endif
++
+ /**
+ * @brief Insert range from another %list.
+ * @param position Iterator referencing the element to insert before.
+@@ -1217,6 +1225,13 @@
+ }
+ }
+
++#ifdef __GXX_EXPERIMENTAL_CXX0X__
++ void
++ splice(iterator __position, list& __x, iterator __first,
++ iterator __last)
++ { splice(__position, std::move(__x), __first, __last); }
++#endif
++
+ /**
+ * @brief Remove all elements equal to value.
+ * @param value The value to remove.
+@@ -1287,6 +1302,10 @@
+ void
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
+ merge(list&& __x);
++
++ void
++ merge(list& __x)
++ { merge(std::move(__x)); }
+ #else
+ merge(list& __x);
+ #endif
+@@ -1307,6 +1326,11 @@
+ void
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
+ merge(list&&, _StrictWeakOrdering);
++
++ template<typename _StrictWeakOrdering>
++ void
++ merge(list& __l, _StrictWeakOrdering __comp)
++ { merge(std::move(__l), __comp); }
+ #else
+ merge(list&, _StrictWeakOrdering);
+ #endif
+diff -ur a/bits/stl_map.h b/bits/stl_map.h
+--- a/bits/stl_map.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_map.h 2011-03-29 10:33:39.000000000 -0700
+@@ -608,11 +608,7 @@
+ * that std::swap(m1,m2) will feed to this function.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(map&& __x)
+-#else
+ swap(map& __x)
+-#endif
+ { _M_t.swap(__x._M_t); }
+
+ /**
+diff -ur a/bits/stl_multimap.h b/bits/stl_multimap.h
+--- a/bits/stl_multimap.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_multimap.h 2011-03-29 10:33:39.000000000 -0700
+@@ -544,11 +544,7 @@
+ * std::swap(m1,m2) will feed to this function.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(multimap&& __x)
+-#else
+ swap(multimap& __x)
+-#endif
+ { _M_t.swap(__x._M_t); }
+
+ /**
+diff -ur a/bits/stl_multiset.h b/bits/stl_multiset.h
+--- a/bits/stl_multiset.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_multiset.h 2011-03-29 10:33:39.000000000 -0700
+@@ -376,11 +376,7 @@
+ * std::swap(s1,s2) will feed to this function.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(multiset&& __x)
+-#else
+ swap(multiset& __x)
+-#endif
+ { _M_t.swap(__x._M_t); }
+
+ // insert/erase
+diff -ur a/bits/stl_pair.h b/bits/stl_pair.h
+--- a/bits/stl_pair.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_pair.h 2011-03-29 10:33:39.000000000 -0700
+@@ -84,10 +84,21 @@
+ : first(__a), second(__b) { }
+
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
+- template<class _U1, class _U2>
++ template<class _U1, class = typename
++ std::enable_if<std::is_convertible<_U1, _T1>::value>::type>
++ pair(_U1&& __x, const _T2& __y)
++ : first(std::forward<_U1>(__x)), second(__y) { }
++
++ template<class _U2, class = typename
++ std::enable_if<std::is_convertible<_U2, _T2>::value>::type>
++ pair(const _T1& __x, _U2&& __y)
++ : first(__x), second(std::forward<_U2>(__y)) { }
++
++ template<class _U1, class _U2, class = typename
++ std::enable_if<std::is_convertible<_U1, _T1>::value
++ && std::is_convertible<_U2, _T2>::value>::type>
+ pair(_U1&& __x, _U2&& __y)
+- : first(std::forward<_U1>(__x)),
+- second(std::forward<_U2>(__y)) { }
++ : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
+
+ pair(pair&& __p)
+ : first(std::move(__p.first)),
+@@ -107,11 +118,19 @@
+ second(std::move(__p.second)) { }
+
+ // http://gcc.gnu.org/ml/libstdc++/2007-08/msg00052.html
++
++#if 0
++ // This constructor is incompatible with libstdc++-4.6, and it
++ // interferes with passing NULL pointers to the 2-argument
++ // constructors, so we disable it. map::emplace isn't
++ // implemented in libstdc++-4.4 anyway, and that's what this
++ // constructor was here for.
+ template<class _U1, class _Arg0, class... _Args>
+ pair(_U1&& __x, _Arg0&& __arg0, _Args&&... __args)
+ : first(std::forward<_U1>(__x)),
+ second(std::forward<_Arg0>(__arg0),
+ std::forward<_Args>(__args)...) { }
++#endif
+
+ pair&
+ operator=(pair&& __p)
+@@ -131,7 +150,7 @@
+ }
+
+ void
+- swap(pair&& __p)
++ swap(pair& __p)
+ {
+ using std::swap;
+ swap(first, __p.first);
+diff -ur a/bits/stl_set.h b/bits/stl_set.h
+--- a/bits/stl_set.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_set.h 2011-03-29 10:33:39.000000000 -0700
+@@ -383,11 +383,7 @@
+ * std::swap(s1,s2) will feed to this function.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(set&& __x)
+-#else
+ swap(set& __x)
+-#endif
+ { _M_t.swap(__x._M_t); }
+
+ // insert/erase
+diff -ur a/bits/stl_tree.h b/bits/stl_tree.h
+--- a/bits/stl_tree.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_tree.h 2011-03-29 10:33:39.000000000 -0700
+@@ -675,11 +675,7 @@
+ { return _M_get_Node_allocator().max_size(); }
+
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(_Rb_tree&& __t);
+-#else
+ swap(_Rb_tree& __t);
+-#endif
+
+ // Insert/erase.
+ pair<iterator, bool>
+@@ -1104,11 +1100,7 @@
+ typename _Compare, typename _Alloc>
+ void
+ _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&& __t)
+-#else
+ swap(_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __t)
+-#endif
+ {
+ if (_M_root() == 0)
+ {
+diff -ur a/bits/stl_vector.h b/bits/stl_vector.h
+--- a/bits/stl_vector.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_vector.h 2011-03-29 10:33:39.000000000 -0700
+@@ -923,11 +923,7 @@
+ * std::swap(v1,v2) will feed to this function.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(vector&& __x)
+-#else
+ swap(vector& __x)
+-#endif
+ {
+ std::swap(this->_M_impl._M_start, __x._M_impl._M_start);
+ std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish);
+diff -ur a/exception_ptr.h b/exception_ptr.h
+--- a/exception_ptr.h 2011-03-15 14:49:08.000000000 -0700
++++ b/exception_ptr.h 2011-03-29 10:33:39.000000000 -0700
+@@ -140,7 +140,7 @@
+ friend bool
+ operator==(const exception_ptr&, const exception_ptr&) throw();
+
+- const type_info*
++ const class type_info*
+ __cxa_exception_type() const throw();
+ };
+
+diff -ur a/ext/algorithm b/ext/algorithm
+--- a/ext/algorithm 2011-03-15 14:49:05.000000000 -0700
++++ b/ext/algorithm 2011-03-29 10:33:39.000000000 -0700
+@@ -423,6 +423,9 @@
+ __out_last - __out_first);
+ }
+
++#ifdef __GXX_EXPERIMENTAL_CXX0X__
++ using std::is_heap;
++#else
+ /**
+ * This is an SGI extension.
+ * @ingroup SGIextensions
+@@ -462,6 +465,7 @@
+
+ return std::__is_heap(__first, __comp, __last - __first);
+ }
++#endif
+
+ // is_sorted, a predicated testing whether a range is sorted in
+ // nondescending order. This is an extension, not part of the C++
+diff -ur a/ext/vstring.h b/ext/vstring.h
+--- a/ext/vstring.h 2011-03-15 14:49:05.000000000 -0700
++++ b/ext/vstring.h 2011-03-29 10:33:39.000000000 -0700
+@@ -152,7 +152,7 @@
+ * string.
+ */
+ __versa_string(__versa_string&& __str)
+- : __vstring_base(std::forward<__vstring_base>(__str)) { }
++ : __vstring_base(std::move(__str)) { }
+
+ /**
+ * @brief Construct string from an initializer list.
+@@ -1439,11 +1439,7 @@
+ * constant time.
+ */
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(__versa_string&& __s)
+-#else
+ swap(__versa_string& __s)
+-#endif
+ { this->_M_swap(__s); }
+
+ // String operations: