aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-02-16 09:31:36 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-02-16 09:31:36 +0000
commitecb7e5c8afe929ee38155db94de6b084ec32a645 (patch)
tree53010172e19c77ea447bcd89e117cda052ab52e0
parent5044f5c816adfd5cba17f1adee1a10127296d0bf (diff)
downloadsrc-ecb7e5c8afe929ee38155db94de6b084ec32a645.tar.gz
src-ecb7e5c8afe929ee38155db94de6b084ec32a645.zip
Update clang to r96341.
Notes
Notes: svn path=/vendor/clang/dist/; revision=203955
-rw-r--r--bindings/python/README.txt18
-rw-r--r--bindings/python/clang/__init__.py24
-rw-r--r--bindings/python/clang/cindex.py933
-rw-r--r--bindings/python/examples/cindex/cindex-dump.py87
-rw-r--r--bindings/python/examples/cindex/cindex-includes.py58
-rw-r--r--bindings/python/tests/__init__.py0
-rw-r--r--bindings/python/tests/cindex/INPUTS/header1.h6
-rw-r--r--bindings/python/tests/cindex/INPUTS/header2.h6
-rw-r--r--bindings/python/tests/cindex/INPUTS/header3.h3
-rw-r--r--bindings/python/tests/cindex/INPUTS/hello.cpp6
-rw-r--r--bindings/python/tests/cindex/INPUTS/include.cpp5
-rw-r--r--bindings/python/tests/cindex/INPUTS/parse_arguments.c2
-rw-r--r--bindings/python/tests/cindex/__init__.py0
-rw-r--r--bindings/python/tests/cindex/test_cursor.py59
-rw-r--r--bindings/python/tests/cindex/test_cursor_kind.py27
-rw-r--r--bindings/python/tests/cindex/test_diagnostics.py48
-rw-r--r--bindings/python/tests/cindex/test_index.py15
-rw-r--r--bindings/python/tests/cindex/test_translation_unit.py73
-rw-r--r--clang.xcodeproj/project.pbxproj42
-rw-r--r--docs/LanguageExtensions.html22
-rw-r--r--docs/UsersManual.html6
-rw-r--r--examples/PrintFunctionNames/Makefile1
-rw-r--r--examples/wpa/Makefile1
-rw-r--r--include/clang-c/Index.h827
-rw-r--r--include/clang/AST/ASTContext.h46
-rw-r--r--include/clang/AST/ASTDiagnostic.h22
-rw-r--r--include/clang/AST/ASTImporter.h234
-rw-r--r--include/clang/AST/Attr.h78
-rw-r--r--include/clang/AST/CXXInheritance.h11
-rw-r--r--include/clang/AST/Decl.h377
-rw-r--r--include/clang/AST/DeclBase.h86
-rw-r--r--include/clang/AST/DeclCXX.h512
-rw-r--r--include/clang/AST/DeclObjC.h70
-rw-r--r--include/clang/AST/DeclTemplate.h53
-rw-r--r--include/clang/AST/DeclarationName.h12
-rw-r--r--include/clang/AST/Expr.h19
-rw-r--r--include/clang/AST/ExprCXX.h418
-rw-r--r--include/clang/AST/ExprObjC.h10
-rw-r--r--include/clang/AST/Stmt.h93
-rw-r--r--include/clang/AST/StmtCXX.h27
-rw-r--r--include/clang/AST/StmtNodes.def9
-rw-r--r--include/clang/AST/StmtVisitor.h1
-rw-r--r--include/clang/AST/Type.h170
-rw-r--r--include/clang/AST/TypeNodes.def5
-rw-r--r--include/clang/AST/UnresolvedSet.h116
-rw-r--r--include/clang/Analysis/Analyses/PrintfFormatString.h279
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h3
-rw-r--r--include/clang/Analysis/AnalysisContext.h (renamed from include/clang/Analysis/PathSensitive/AnalysisContext.h)33
-rw-r--r--include/clang/Analysis/Support/Optional.h12
-rw-r--r--include/clang/Basic/Builtins.def39
-rw-r--r--include/clang/Basic/Diagnostic.h27
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td29
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td11
-rw-r--r--include/clang/Basic/DiagnosticGroups.td6
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td15
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td152
-rw-r--r--include/clang/Basic/LangOptions.h14
-rw-r--r--include/clang/Basic/Linkage.h57
-rw-r--r--include/clang/Basic/PartialDiagnostic.h2
-rw-r--r--include/clang/Basic/SourceManager.h8
-rw-r--r--include/clang/Basic/Specifiers.h3
-rw-r--r--include/clang/Basic/TargetInfo.h19
-rw-r--r--include/clang/Basic/TokenKinds.def10
-rw-r--r--include/clang/Basic/Version.h6
-rw-r--r--include/clang/Checker/BugReporter/BugReporter.h (renamed from include/clang/Analysis/PathSensitive/BugReporter.h)12
-rw-r--r--include/clang/Checker/BugReporter/BugType.h (renamed from include/clang/Analysis/PathSensitive/BugType.h)1
-rw-r--r--include/clang/Checker/BugReporter/PathDiagnostic.h (renamed from include/clang/Analysis/PathDiagnostic.h)0
-rw-r--r--include/clang/Checker/Checkers/DereferenceChecker.h (renamed from include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h)0
-rw-r--r--include/clang/Checker/Checkers/LocalCheckers.h (renamed from include/clang/Analysis/LocalCheckers.h)6
-rw-r--r--include/clang/Checker/DomainSpecific/CocoaConventions.h40
-rw-r--r--include/clang/Checker/ManagerRegistry.h (renamed from include/clang/Analysis/ManagerRegistry.h)2
-rw-r--r--include/clang/Checker/PathSensitive/AnalysisManager.h (renamed from include/clang/Analysis/PathSensitive/AnalysisManager.h)6
-rw-r--r--include/clang/Checker/PathSensitive/BasicValueFactory.h (renamed from include/clang/Analysis/PathSensitive/BasicValueFactory.h)18
-rw-r--r--include/clang/Checker/PathSensitive/Checker.h (renamed from include/clang/Analysis/PathSensitive/Checker.h)6
-rw-r--r--include/clang/Checker/PathSensitive/CheckerVisitor.def (renamed from include/clang/Analysis/PathSensitive/CheckerVisitor.def)1
-rw-r--r--include/clang/Checker/PathSensitive/CheckerVisitor.h (renamed from include/clang/Analysis/PathSensitive/CheckerVisitor.h)19
-rw-r--r--include/clang/Checker/PathSensitive/ConstraintManager.h (renamed from include/clang/Analysis/PathSensitive/ConstraintManager.h)2
-rw-r--r--include/clang/Checker/PathSensitive/Environment.h (renamed from include/clang/Analysis/PathSensitive/Environment.h)4
-rw-r--r--include/clang/Checker/PathSensitive/ExplodedGraph.h (renamed from include/clang/Analysis/PathSensitive/ExplodedGraph.h)2
-rw-r--r--include/clang/Checker/PathSensitive/GRAuditor.h (renamed from include/clang/Analysis/PathSensitive/GRAuditor.h)0
-rw-r--r--include/clang/Checker/PathSensitive/GRBlockCounter.h (renamed from include/clang/Analysis/PathSensitive/GRBlockCounter.h)0
-rw-r--r--include/clang/Checker/PathSensitive/GRCoreEngine.h (renamed from include/clang/Analysis/PathSensitive/GRCoreEngine.h)10
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h (renamed from include/clang/Analysis/PathSensitive/GRExprEngine.h)25
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngineBuilders.h (renamed from include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h)2
-rw-r--r--include/clang/Checker/PathSensitive/GRSimpleAPICheck.h (renamed from include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h)4
-rw-r--r--include/clang/Checker/PathSensitive/GRState.h (renamed from include/clang/Analysis/PathSensitive/GRState.h)29
-rw-r--r--include/clang/Checker/PathSensitive/GRStateTrait.h (renamed from include/clang/Analysis/PathSensitive/GRStateTrait.h)0
-rw-r--r--include/clang/Checker/PathSensitive/GRSubEngine.h (renamed from include/clang/Analysis/PathSensitive/GRSubEngine.h)2
-rw-r--r--include/clang/Checker/PathSensitive/GRTransferFuncs.h (renamed from include/clang/Analysis/PathSensitive/GRTransferFuncs.h)6
-rw-r--r--include/clang/Checker/PathSensitive/GRWorkList.h (renamed from include/clang/Analysis/PathSensitive/GRWorkList.h)2
-rw-r--r--include/clang/Checker/PathSensitive/MemRegion.h (renamed from include/clang/Analysis/PathSensitive/MemRegion.h)15
-rw-r--r--include/clang/Checker/PathSensitive/SVals.h (renamed from include/clang/Analysis/PathSensitive/SVals.h)4
-rw-r--r--include/clang/Checker/PathSensitive/SValuator.h (renamed from include/clang/Analysis/PathSensitive/SValuator.h)29
-rw-r--r--include/clang/Checker/PathSensitive/Store.h (renamed from include/clang/Analysis/PathSensitive/Store.h)80
-rw-r--r--include/clang/Checker/PathSensitive/SummaryManager.h57
-rw-r--r--include/clang/Checker/PathSensitive/SymbolManager.h (renamed from include/clang/Analysis/PathSensitive/SymbolManager.h)0
-rw-r--r--include/clang/Checker/PathSensitive/ValueManager.h (renamed from include/clang/Analysis/PathSensitive/ValueManager.h)14
-rw-r--r--include/clang/CodeGen/CodeGenOptions.h5
-rw-r--r--include/clang/Driver/CC1Options.td32
-rw-r--r--include/clang/Driver/Driver.h28
-rw-r--r--include/clang/Driver/Options.td17
-rw-r--r--include/clang/Driver/Tool.h1
-rw-r--r--include/clang/Driver/ToolChain.h18
-rw-r--r--include/clang/Driver/Types.def1
-rw-r--r--include/clang/Frontend/ASTConsumers.h7
-rw-r--r--include/clang/Frontend/ASTUnit.h10
-rw-r--r--include/clang/Frontend/Analyses.def17
-rw-r--r--include/clang/Frontend/CompilerInstance.h74
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h6
-rw-r--r--include/clang/Frontend/FrontendAction.h8
-rw-r--r--include/clang/Frontend/FrontendActions.h44
-rw-r--r--include/clang/Frontend/FrontendOptions.h4
-rw-r--r--include/clang/Frontend/PCHBitCodes.h12
-rw-r--r--include/clang/Frontend/PCHReader.h4
-rw-r--r--include/clang/Lex/Lexer.h3
-rw-r--r--include/clang/Lex/Token.h4
-rw-r--r--include/clang/Parse/Action.h17
-rw-r--r--include/clang/Parse/DeclSpec.h13
-rw-r--r--include/clang/Parse/Parser.h92
-rw-r--r--lib/AST/ASTContext.cpp247
-rw-r--r--lib/AST/ASTDiagnostic.cpp266
-rw-r--r--lib/AST/ASTImporter.cpp2394
-rw-r--r--lib/AST/AttrImpl.cpp65
-rw-r--r--lib/AST/CMakeLists.txt2
-rw-r--r--lib/AST/CXXInheritance.cpp14
-rw-r--r--lib/AST/Decl.cpp734
-rw-r--r--lib/AST/DeclBase.cpp35
-rw-r--r--lib/AST/DeclCXX.cpp123
-rw-r--r--lib/AST/DeclObjC.cpp14
-rw-r--r--lib/AST/DeclPrinter.cpp62
-rw-r--r--lib/AST/DeclTemplate.cpp3
-rw-r--r--lib/AST/DeclarationName.cpp47
-rw-r--r--lib/AST/Expr.cpp134
-rw-r--r--lib/AST/ExprCXX.cpp100
-rw-r--r--lib/AST/ExprConstant.cpp39
-rw-r--r--lib/AST/Makefile1
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp9
-rw-r--r--lib/AST/Stmt.cpp148
-rw-r--r--lib/AST/StmtDumper.cpp2
-rw-r--r--lib/AST/StmtPrinter.cpp4
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/Type.cpp154
-rw-r--r--lib/AST/TypePrinter.cpp40
-rw-r--r--lib/Analysis/AnalysisContext.cpp48
-rw-r--r--lib/Analysis/CMakeLists.txt59
-rw-r--r--lib/Analysis/LiveVariables.cpp2
-rw-r--r--lib/Analysis/Makefile1
-rw-r--r--lib/Analysis/PrintfFormatString.cpp436
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp114
-rw-r--r--lib/Analysis/UninitializedValues.cpp1
-rw-r--r--lib/Basic/Diagnostic.cpp219
-rw-r--r--lib/Basic/IdentifierTable.cpp4
-rw-r--r--lib/Basic/Makefile1
-rw-r--r--lib/Basic/SourceManager.cpp10
-rw-r--r--lib/Basic/TargetInfo.cpp39
-rw-r--r--lib/Basic/Targets.cpp157
-rw-r--r--lib/Basic/Version.cpp78
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/Checker/AdjustedReturnValueChecker.cpp98
-rw-r--r--lib/Checker/ArrayBoundChecker.cpp (renamed from lib/Analysis/ArrayBoundChecker.cpp)6
-rw-r--r--lib/Checker/AttrNonNullChecker.cpp (renamed from lib/Analysis/AttrNonNullChecker.cpp)4
-rw-r--r--lib/Checker/BasicConstraintManager.cpp (renamed from lib/Analysis/BasicConstraintManager.cpp)6
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp (renamed from lib/Analysis/BasicObjCFoundationChecks.cpp)89
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.h (renamed from lib/Analysis/BasicObjCFoundationChecks.h)0
-rw-r--r--lib/Checker/BasicStore.cpp (renamed from lib/Analysis/BasicStore.cpp)215
-rw-r--r--lib/Checker/BasicValueFactory.cpp (renamed from lib/Analysis/BasicValueFactory.cpp)13
-rw-r--r--lib/Checker/BugReporter.cpp (renamed from lib/Analysis/BugReporter.cpp)6
-rw-r--r--lib/Checker/BugReporterVisitors.cpp (renamed from lib/Analysis/BugReporterVisitors.cpp)26
-rw-r--r--lib/Checker/BuiltinFunctionChecker.cpp (renamed from lib/Analysis/BuiltinFunctionChecker.cpp)2
-rw-r--r--lib/Checker/CFRefCount.cpp (renamed from lib/Analysis/CFRefCount.cpp)463
-rw-r--r--lib/Checker/CMakeLists.txt67
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp (renamed from lib/Analysis/CallAndMessageChecker.cpp)4
-rw-r--r--lib/Checker/CallInliner.cpp (renamed from lib/Analysis/CallInliner.cpp)6
-rw-r--r--lib/Checker/CastToStructChecker.cpp (renamed from lib/Analysis/CastToStructChecker.cpp)2
-rw-r--r--lib/Checker/CheckDeadStores.cpp (renamed from lib/Analysis/CheckDeadStores.cpp)6
-rw-r--r--lib/Checker/CheckObjCDealloc.cpp (renamed from lib/Analysis/CheckObjCDealloc.cpp)6
-rw-r--r--lib/Checker/CheckObjCInstMethSignature.cpp (renamed from lib/Analysis/CheckObjCInstMethSignature.cpp)6
-rw-r--r--lib/Checker/CheckObjCUnusedIVars.cpp (renamed from lib/Analysis/CheckObjCUnusedIVars.cpp)6
-rw-r--r--lib/Checker/CheckSecuritySyntaxOnly.cpp (renamed from lib/Analysis/CheckSecuritySyntaxOnly.cpp)4
-rw-r--r--lib/Checker/CheckSizeofPointer.cpp (renamed from lib/Analysis/CheckSizeofPointer.cpp)4
-rw-r--r--lib/Checker/Checker.cpp (renamed from lib/Analysis/Checker.cpp)2
-rw-r--r--lib/Checker/CocoaConventions.cpp195
-rw-r--r--lib/Checker/DereferenceChecker.cpp (renamed from lib/Analysis/DereferenceChecker.cpp)8
-rw-r--r--lib/Checker/DivZeroChecker.cpp (renamed from lib/Analysis/DivZeroChecker.cpp)2
-rw-r--r--lib/Checker/Environment.cpp (renamed from lib/Analysis/Environment.cpp)2
-rw-r--r--lib/Checker/ExplodedGraph.cpp (renamed from lib/Analysis/ExplodedGraph.cpp)4
-rw-r--r--lib/Checker/FixedAddressChecker.cpp (renamed from lib/Analysis/FixedAddressChecker.cpp)2
-rw-r--r--lib/Checker/FlatStore.cpp166
-rw-r--r--lib/Checker/GRBlockCounter.cpp (renamed from lib/Analysis/GRBlockCounter.cpp)2
-rw-r--r--lib/Checker/GRCoreEngine.cpp (renamed from lib/Analysis/GRCoreEngine.cpp)4
-rw-r--r--lib/Checker/GRExprEngine.cpp (renamed from lib/Analysis/GRExprEngine.cpp)439
-rw-r--r--lib/Checker/GRExprEngineExperimentalChecks.cpp (renamed from lib/Analysis/GRExprEngineExperimentalChecks.cpp)2
-rw-r--r--lib/Checker/GRExprEngineExperimentalChecks.h (renamed from lib/Analysis/GRExprEngineExperimentalChecks.h)0
-rw-r--r--lib/Checker/GRExprEngineInternalChecks.h (renamed from lib/Analysis/GRExprEngineInternalChecks.h)3
-rw-r--r--lib/Checker/GRState.cpp (renamed from lib/Analysis/GRState.cpp)12
-rw-r--r--lib/Checker/LLVMConventionsChecker.cpp335
-rw-r--r--lib/Checker/Makefile21
-rw-r--r--lib/Checker/MallocChecker.cpp (renamed from lib/Analysis/MallocChecker.cpp)13
-rw-r--r--lib/Checker/ManagerRegistry.cpp (renamed from lib/Analysis/ManagerRegistry.cpp)2
-rw-r--r--lib/Checker/MemRegion.cpp (renamed from lib/Analysis/MemRegion.cpp)11
-rw-r--r--lib/Checker/NSAutoreleasePoolChecker.cpp (renamed from lib/Analysis/NSAutoreleasePoolChecker.cpp)6
-rw-r--r--lib/Checker/NSErrorChecker.cpp (renamed from lib/Analysis/NSErrorChecker.cpp)8
-rw-r--r--lib/Checker/NoReturnFunctionChecker.cpp (renamed from lib/Analysis/NoReturnFunctionChecker.cpp)2
-rw-r--r--lib/Checker/OSAtomicChecker.cpp (renamed from lib/Analysis/OSAtomicChecker.cpp)5
-rw-r--r--lib/Checker/PathDiagnostic.cpp (renamed from lib/Analysis/PathDiagnostic.cpp)2
-rw-r--r--lib/Checker/PointerArithChecker.cpp (renamed from lib/Analysis/PointerArithChecker.cpp)2
-rw-r--r--lib/Checker/PointerSubChecker.cpp (renamed from lib/Analysis/PointerSubChecker.cpp)2
-rw-r--r--lib/Checker/PthreadLockChecker.cpp (renamed from lib/Analysis/PthreadLockChecker.cpp)6
-rw-r--r--lib/Checker/RangeConstraintManager.cpp (renamed from lib/Analysis/RangeConstraintManager.cpp)8
-rw-r--r--lib/Checker/RegionStore.cpp (renamed from lib/Analysis/RegionStore.cpp)1052
-rw-r--r--lib/Checker/ReturnPointerRangeChecker.cpp (renamed from lib/Analysis/ReturnPointerRangeChecker.cpp)6
-rw-r--r--lib/Checker/ReturnStackAddressChecker.cpp125
-rw-r--r--lib/Checker/ReturnUndefChecker.cpp (renamed from lib/Analysis/ReturnUndefChecker.cpp)6
-rw-r--r--lib/Checker/SVals.cpp (renamed from lib/Analysis/SVals.cpp)8
-rw-r--r--lib/Checker/SValuator.cpp (renamed from lib/Analysis/SValuator.cpp)49
-rw-r--r--lib/Checker/SimpleConstraintManager.cpp (renamed from lib/Analysis/SimpleConstraintManager.cpp)6
-rw-r--r--lib/Checker/SimpleConstraintManager.h (renamed from lib/Analysis/SimpleConstraintManager.h)4
-rw-r--r--lib/Checker/SimpleSValuator.cpp (renamed from lib/Analysis/SimpleSValuator.cpp)6
-rw-r--r--lib/Checker/Store.cpp (renamed from lib/Analysis/Store.cpp)121
-rw-r--r--lib/Checker/SymbolManager.cpp (renamed from lib/Analysis/SymbolManager.cpp)4
-rw-r--r--lib/Checker/UndefBranchChecker.cpp (renamed from lib/Analysis/UndefBranchChecker.cpp)2
-rw-r--r--lib/Checker/UndefCapturedBlockVarChecker.cpp101
-rw-r--r--lib/Checker/UndefResultChecker.cpp (renamed from lib/Analysis/UndefResultChecker.cpp)6
-rw-r--r--lib/Checker/UndefinedArraySubscriptChecker.cpp (renamed from lib/Analysis/UndefinedArraySubscriptChecker.cpp)4
-rw-r--r--lib/Checker/UndefinedAssignmentChecker.cpp (renamed from lib/Analysis/UndefinedAssignmentChecker.cpp)4
-rw-r--r--lib/Checker/VLASizeChecker.cpp (renamed from lib/Analysis/VLASizeChecker.cpp)6
-rw-r--r--lib/Checker/ValueManager.cpp (renamed from lib/Analysis/ValueManager.cpp)4
-rw-r--r--lib/CodeGen/CGBlocks.cpp74
-rw-r--r--lib/CodeGen/CGBlocks.h5
-rw-r--r--lib/CodeGen/CGBuiltin.cpp3
-rw-r--r--lib/CodeGen/CGCXX.cpp8
-rw-r--r--lib/CodeGen/CGCall.cpp116
-rw-r--r--lib/CodeGen/CGCall.h9
-rw-r--r--lib/CodeGen/CGClass.cpp445
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp918
-rw-r--r--lib/CodeGen/CGDebugInfo.h45
-rw-r--r--lib/CodeGen/CGDecl.cpp91
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp118
-rw-r--r--lib/CodeGen/CGException.cpp26
-rw-r--r--lib/CodeGen/CGExpr.cpp149
-rw-r--r--lib/CodeGen/CGExprAgg.cpp86
-rw-r--r--lib/CodeGen/CGExprCXX.cpp125
-rw-r--r--lib/CodeGen/CGExprComplex.cpp12
-rw-r--r--lib/CodeGen/CGExprConstant.cpp175
-rw-r--r--lib/CodeGen/CGExprScalar.cpp57
-rw-r--r--lib/CodeGen/CGObjC.cpp26
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp135
-rw-r--r--lib/CodeGen/CGObjCMac.cpp29
-rw-r--r--lib/CodeGen/CGRTTI.cpp7
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp41
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.h15
-rw-r--r--lib/CodeGen/CGStmt.cpp22
-rw-r--r--lib/CodeGen/CGVtable.cpp1683
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp24
-rw-r--r--lib/CodeGen/CodeGenFunction.h61
-rw-r--r--lib/CodeGen/CodeGenModule.cpp149
-rw-r--r--lib/CodeGen/CodeGenModule.h18
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp32
-rw-r--r--lib/CodeGen/CodeGenTypes.h36
-rw-r--r--lib/CodeGen/GlobalDecl.h4
-rw-r--r--lib/CodeGen/Makefile1
-rw-r--r--lib/CodeGen/Mangle.cpp320
-rw-r--r--lib/CodeGen/TargetInfo.cpp126
-rw-r--r--lib/Driver/Driver.cpp81
-rw-r--r--lib/Driver/HostInfo.cpp11
-rw-r--r--lib/Driver/Makefile1
-rw-r--r--lib/Driver/ToolChains.cpp158
-rw-r--r--lib/Driver/ToolChains.h115
-rw-r--r--lib/Driver/Tools.cpp228
-rw-r--r--lib/Driver/Tools.h19
-rw-r--r--lib/Frontend/ASTConsumers.cpp2
-rw-r--r--lib/Frontend/ASTMerge.cpp103
-rw-r--r--lib/Frontend/ASTUnit.cpp30
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp161
-rw-r--r--lib/Frontend/Backend.cpp38
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CompilerInstance.cpp54
-rw-r--r--lib/Frontend/CompilerInvocation.cpp41
-rw-r--r--lib/Frontend/FrontendActions.cpp5
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp2
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp10
-rw-r--r--lib/Frontend/InitPreprocessor.cpp2
-rw-r--r--lib/Frontend/Makefile1
-rw-r--r--lib/Frontend/PCHReader.cpp44
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp13
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp33
-rw-r--r--lib/Frontend/PCHWriter.cpp35
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp1
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp21
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp2
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp5
-rw-r--r--lib/Frontend/RewriteObjC.cpp448
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp26
-rw-r--r--lib/Headers/xmmintrin.h16
-rw-r--r--lib/Index/Makefile1
-rw-r--r--lib/Lex/Lexer.cpp16
-rw-r--r--lib/Lex/Makefile1
-rw-r--r--lib/Lex/PPCaching.cpp2
-rw-r--r--lib/Lex/PPDirectives.cpp17
-rw-r--r--lib/Lex/PPMacroExpansion.cpp38
-rw-r--r--lib/Lex/Preprocessor.cpp2
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Parse/DeclSpec.cpp37
-rw-r--r--lib/Parse/Makefile1
-rw-r--r--lib/Parse/ParseDecl.cpp94
-rw-r--r--lib/Parse/ParseDeclCXX.cpp122
-rw-r--r--lib/Parse/ParseExpr.cpp41
-rw-r--r--lib/Parse/ParseExprCXX.cpp7
-rw-r--r--lib/Parse/ParseObjc.cpp24
-rw-r--r--lib/Parse/ParseStmt.cpp90
-rw-r--r--lib/Parse/ParseTemplate.cpp2
-rw-r--r--lib/Parse/ParseTentative.cpp9
-rw-r--r--lib/Parse/Parser.cpp23
-rw-r--r--lib/Rewrite/Makefile1
-rw-r--r--lib/Sema/IdentifierResolver.cpp38
-rw-r--r--lib/Sema/Lookup.h44
-rw-r--r--lib/Sema/Makefile1
-rw-r--r--lib/Sema/Sema.cpp280
-rw-r--r--lib/Sema/Sema.h327
-rw-r--r--lib/Sema/SemaAccess.cpp592
-rw-r--r--lib/Sema/SemaCXXCast.cpp59
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp4
-rw-r--r--lib/Sema/SemaChecking.cpp554
-rw-r--r--lib/Sema/SemaCodeComplete.cpp16
-rw-r--r--lib/Sema/SemaDecl.cpp682
-rw-r--r--lib/Sema/SemaDeclAttr.cpp211
-rw-r--r--lib/Sema/SemaDeclCXX.cpp730
-rw-r--r--lib/Sema/SemaDeclObjC.cpp219
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp83
-rw-r--r--lib/Sema/SemaExpr.cpp148
-rw-r--r--lib/Sema/SemaExprCXX.cpp127
-rw-r--r--lib/Sema/SemaExprObjC.cpp31
-rw-r--r--lib/Sema/SemaInit.cpp692
-rw-r--r--lib/Sema/SemaInit.h35
-rw-r--r--lib/Sema/SemaLookup.cpp318
-rw-r--r--lib/Sema/SemaOverload.cpp646
-rw-r--r--lib/Sema/SemaOverload.h62
-rw-r--r--lib/Sema/SemaStmt.cpp178
-rw-r--r--lib/Sema/SemaTemplate.cpp199
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp361
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp242
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp182
-rw-r--r--lib/Sema/SemaType.cpp188
-rw-r--r--lib/Sema/TargetAttributesSema.cpp44
-rw-r--r--lib/Sema/TreeTransform.h160
-rw-r--r--test/ASTMerge/Inputs/enum1.c42
-rw-r--r--test/ASTMerge/Inputs/enum2.c42
-rw-r--r--test/ASTMerge/Inputs/function1.c6
-rw-r--r--test/ASTMerge/Inputs/function2.c7
-rw-r--r--test/ASTMerge/Inputs/interface1.m7
-rw-r--r--test/ASTMerge/Inputs/interface2.m7
-rw-r--r--test/ASTMerge/Inputs/lit.local.cfg1
-rw-r--r--test/ASTMerge/Inputs/struct1.c63
-rw-r--r--test/ASTMerge/Inputs/struct2.c60
-rw-r--r--test/ASTMerge/Inputs/typedef1.c4
-rw-r--r--test/ASTMerge/Inputs/typedef2.c4
-rw-r--r--test/ASTMerge/Inputs/var1.c7
-rw-r--r--test/ASTMerge/Inputs/var1.h1
-rw-r--r--test/ASTMerge/Inputs/var2.c7
-rw-r--r--test/ASTMerge/enum.c25
-rw-r--r--test/ASTMerge/function.c9
-rw-r--r--test/ASTMerge/interface.m6
-rw-r--r--test/ASTMerge/struct.c42
-rw-r--r--test/ASTMerge/typedef.c7
-rw-r--r--test/ASTMerge/var.c12
-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.m16
-rw-r--r--test/Analysis/NSWindow.m8
-rw-r--r--test/Analysis/NoReturn.m8
-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/array-struct.c8
-rw-r--r--test/Analysis/blocks.m18
-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/complex.c8
-rw-r--r--test/Analysis/concrete-address.c4
-rw-r--r--test/Analysis/conditional-op-missing-lhs.c2
-rw-r--r--test/Analysis/dead-stores.c10
-rw-r--r--test/Analysis/dead-stores.cpp10
-rw-r--r--test/Analysis/dead-stores.m2
-rw-r--r--test/Analysis/delegates.m4
-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/func.c4
-rw-r--r--test/Analysis/malloc.c6
-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.m2
-rw-r--r--test/Analysis/misc-ps-flat-store.c10
-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.cpp4
-rw-r--r--test/Analysis/misc-ps-region-store.m141
-rw-r--r--test/Analysis/misc-ps-region-store.mm4
-rw-r--r--test/Analysis/misc-ps.m112
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m8
-rw-r--r--test/Analysis/no-exit-cfg.c4
-rw-r--r--test/Analysis/no-outofbounds.c4
-rw-r--r--test/Analysis/null-deref-ps-region.c2
-rw-r--r--test/Analysis/null-deref-ps.c8
-rw-r--r--test/Analysis/outofbound.c2
-rw-r--r--test/Analysis/override-werror.c4
-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/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.m4
-rw-r--r--test/Analysis/security-syntax-checks-no-emit.c2
-rw-r--r--test/Analysis/security-syntax-checks.m2
-rw-r--r--test/Analysis/stack-addr-ps.c4
-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.c2
-rw-r--r--test/Analysis/uninit-vals-ps.c4
-rw-r--r--test/Analysis/uninit-vals.m4
-rw-r--r--test/Analysis/unions-region.m2
-rw-r--r--test/Analysis/unused-ivars.m2
-rw-r--r--test/CMakeLists.txt6
-rw-r--r--test/CXX/basic/basic.def.odr/p1-var.cpp21
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp2
-rw-r--r--test/CXX/class.access/class.access.base/p1.cpp45
-rw-r--r--test/CXX/class.access/p4.cpp114
-rw-r--r--test/CXX/class.access/p6.cpp54
-rw-r--r--test/CXX/class/class.local/p2.cpp4
-rw-r--r--test/CXX/conv/conv.mem/p4.cpp65
-rw-r--r--test/CXX/conv/conv.qual/pr6089.cpp18
-rw-r--r--test/CXX/dcl.dcl/dcl.enum/p5.cpp56
-rw-r--r--test/CXX/dcl.dcl/dcl.link/p7.cpp30
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp9
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp6
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp12
-rw-r--r--test/CXX/dcl.decl/dcl.init/p6.cpp15
-rw-r--r--test/CXX/dcl.decl/dcl.name/p1.cpp16
-rw-r--r--test/CXX/expr/p8.cpp2
-rw-r--r--test/CXX/lex/lex.literal/lex.ccon/p1.cpp9
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp57
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp129
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p5.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp3
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp95
-rw-r--r--test/CXX/temp/temp.names/p4.cpp15
-rw-r--r--test/CXX/temp/temp.res/temp.local/p1.cpp33
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp15
-rw-r--r--test/CodeGen/2010-02-09-DbgSelf.m14
-rw-r--r--test/CodeGen/2010-02-15-Dbg-MethodStart.m15
-rw-r--r--test/CodeGen/address-space-field1.c4
-rw-r--r--test/CodeGen/arm-arguments.c61
-rw-r--r--test/CodeGen/attributes.c7
-rw-r--r--test/CodeGen/darwin-string-literals.c4
-rw-r--r--test/CodeGen/debug-info-crash.c21
-rw-r--r--test/CodeGen/enum.c1
-rw-r--r--test/CodeGen/function-attributes.c8
-rw-r--r--test/CodeGen/stdcall-fastcall.c20
-rw-r--r--test/CodeGen/union.c3
-rw-r--r--test/CodeGenCXX/PR4890-debug-info-dtor.cpp6
-rw-r--r--test/CodeGenCXX/alloca-align.cpp12
-rw-r--r--test/CodeGenCXX/anonymous-namespaces.cpp16
-rw-r--r--test/CodeGenCXX/attr.cpp29
-rw-r--r--test/CodeGenCXX/condition.cpp22
-rw-r--r--test/CodeGenCXX/conditional-temporaries.cpp65
-rw-r--r--test/CodeGenCXX/const-global-linkage.cpp4
-rw-r--r--test/CodeGenCXX/const-init.cpp4
-rw-r--r--test/CodeGenCXX/conversion-function.cpp2
-rw-r--r--test/CodeGenCXX/debug-info.cpp28
-rw-r--r--test/CodeGenCXX/default-destructor-synthesis.cpp72
-rw-r--r--test/CodeGenCXX/deferred-global-init.cpp2
-rw-r--r--test/CodeGenCXX/derived-to-base.cpp22
-rw-r--r--test/CodeGenCXX/dyncast.cpp29
-rw-r--r--test/CodeGenCXX/extern-c.cpp3
-rw-r--r--test/CodeGenCXX/global-init.cpp15
-rw-r--r--test/CodeGenCXX/global-llvm-constant.cpp2
-rw-r--r--test/CodeGenCXX/internal-linkage.cpp19
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp44
-rw-r--r--test/CodeGenCXX/mangle.cpp72
-rw-r--r--test/CodeGenCXX/member-function-pointer-calls.cpp26
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp37
-rw-r--r--test/CodeGenCXX/member-initializers.cpp34
-rw-r--r--test/CodeGenCXX/member-pointer-cast.cpp21
-rw-r--r--test/CodeGenCXX/member-pointers-zero-init.cpp34
-rw-r--r--test/CodeGenCXX/no-exceptions.cpp12
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp87
-rw-r--r--test/CodeGenCXX/reference-init.cpp8
-rw-r--r--test/CodeGenCXX/references.cpp8
-rw-r--r--test/CodeGenCXX/static-data-member.cpp10
-rw-r--r--test/CodeGenCXX/static-init.cpp19
-rw-r--r--test/CodeGenCXX/temp-order.cpp32
-rw-r--r--test/CodeGenCXX/temporaries.cpp39
-rw-r--r--test/CodeGenCXX/threadsafe-statics.cpp17
-rw-r--r--test/CodeGenCXX/throw-expressions.cpp2
-rw-r--r--test/CodeGenCXX/virt.cpp58
-rw-r--r--test/CodeGenCXX/virtual-bases.cpp8
-rw-r--r--test/CodeGenCXX/virtual-function-calls.cpp21
-rw-r--r--test/CodeGenCXX/visibility.cpp66
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp367
-rw-r--r--test/CodeGenCXX/vtable-pointer-initialization.cpp54
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp24
-rw-r--r--test/CodeGenObjC/PR4894-recursive-debug-crash.m40
-rw-r--r--test/CodeGenObjC/blocks-4.m21
-rw-r--r--test/CodeGenObjC/debug-info-crash.m (renamed from test/CodeGenObjC/PR4541.m)27
-rw-r--r--test/CodeGenObjC/id-isa-codegen.m14
-rw-r--r--test/CodeGenObjC/image-info.m2
-rw-r--r--test/CodeGenObjC/objc2-legacy-dispatch.m26
-rw-r--r--test/CodeGenObjC/objc2-weak-block-call.m29
-rw-r--r--test/CodeGenObjC/unwind-fn.m14
-rw-r--r--test/Coverage/html-diagnostics.c2
-rw-r--r--test/Driver/darwin-iphone-defaults.m30
-rw-r--r--test/Driver/darwin-ld.c33
-rw-r--r--test/Driver/darwin-version.c21
-rw-r--r--test/Driver/rewrite-objc.m11
-rw-r--r--test/FixIt/fixit.cpp17
-rw-r--r--test/FixIt/typo-crash.m6
-rw-r--r--test/FixIt/typo.m2
-rw-r--r--test/Index/TestClassDecl.m28
-rw-r--r--test/Index/TestClassForwardDecl.m18
-rw-r--r--test/Index/annotate-tokens.c64
-rw-r--r--test/Index/c-index-api-loadTU-test.m122
-rw-r--r--test/Index/c-index-getCursor-test.m198
-rw-r--r--test/Index/cindex-from-source.m2
-rw-r--r--test/Index/cindex-test-inclusions.c13
-rw-r--r--test/Index/code-complete-errors.c16
-rw-r--r--test/Index/include_test.h1
-rw-r--r--test/Index/include_test_2.h0
-rw-r--r--test/Index/load-exprs.c11
-rw-r--r--test/Index/load-stmts.cpp51
-rw-r--r--test/Index/remap-cursor-at.c2
-rw-r--r--test/Index/remap-load.c23
-rw-r--r--test/Misc/caret-diags-macros.c9
-rw-r--r--test/PCH/cxx_exprs.cpp15
-rw-r--r--test/PCH/cxx_exprs.h18
-rw-r--r--test/Parser/altivec.c91
-rw-r--r--test/Parser/cxx-altivec.cpp108
-rw-r--r--test/Parser/cxx-decl.cpp6
-rw-r--r--test/Parser/cxx-template-decl.cpp10
-rw-r--r--test/Parser/declarators.c23
-rw-r--r--test/Parser/objc-property-syntax.m2
-rw-r--r--test/Parser/statements.c2
-rw-r--r--test/Preprocessor/init.c11
-rw-r--r--test/Preprocessor/mi_opt2.c15
-rw-r--r--test/Preprocessor/mi_opt2.h5
-rw-r--r--test/Rewriter/blockcast3.mm23
-rw-r--r--test/Rewriter/rewrite-block-pointer.mm16
-rw-r--r--test/Rewriter/rewrite-byref-vars.mm10
-rw-r--r--test/Rewriter/rewrite-cast-ivar-access.mm53
-rw-r--r--test/Rewriter/rewrite-category-property.mm15
-rw-r--r--test/Rewriter/rewrite-implementation.mm13
-rw-r--r--test/Rewriter/rewrite-message-expr.mm25
-rw-r--r--test/Rewriter/rewrite-nested-ivar.mm33
-rw-r--r--test/Rewriter/rewrite-protocol-qualified.mm41
-rw-r--r--test/Rewriter/rewrite-typeof.mm21
-rw-r--r--test/Rewriter/rewrite-unique-block-api.mm31
-rw-r--r--test/Sema/Inputs/conversion.h3
-rw-r--r--test/Sema/arm-layout.c20
-rw-r--r--test/Sema/asm.c3
-rw-r--r--test/Sema/attr-mode.c39
-rw-r--r--test/Sema/attr-noreturn.c2
-rw-r--r--test/Sema/block-args.c6
-rw-r--r--test/Sema/block-printf-attribute-1.c5
-rw-r--r--test/Sema/block-return.c7
-rw-r--r--test/Sema/builtin-unary-fp.c4
-rw-r--r--test/Sema/callingconv.c19
-rw-r--r--test/Sema/compare.c2
-rw-r--r--test/Sema/const-eval.c1
-rw-r--r--test/Sema/conversion.c10
-rw-r--r--test/Sema/declspec.c19
-rw-r--r--test/Sema/enum.c4
-rw-r--r--test/Sema/format-string-percentm.c1
-rw-r--r--test/Sema/format-strings.c81
-rw-r--r--test/Sema/function-redecl.c4
-rw-r--r--test/Sema/incomplete-decl.c2
-rw-r--r--test/Sema/indirect-goto.c3
-rw-r--r--test/Sema/return-noreturn.c2
-rw-r--r--test/Sema/return.c2
-rw-r--r--test/Sema/scope-check.c2
-rw-r--r--test/Sema/statements.c8
-rw-r--r--test/Sema/stdcall-fastcall.c8
-rw-r--r--test/Sema/switch.c138
-rw-r--r--test/Sema/ucn-cstring.c4
-rw-r--r--test/Sema/unused-expr.c2
-rw-r--r--test/Sema/vla.c6
-rw-r--r--test/Sema/warn-unused-function.c16
-rw-r--r--test/Sema/x86-attr-force-align-arg-pointer.c18
-rw-r--r--test/SemaCXX/Inputs/lit.local.cfg1
-rw-r--r--test/SemaCXX/Inputs/malloc.h3
-rw-r--r--test/SemaCXX/access-base-class.cpp23
-rw-r--r--test/SemaCXX/access-control-check.cpp2
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp39
-rw-r--r--test/SemaCXX/builtin-exception-spec.cpp6
-rw-r--r--test/SemaCXX/builtins.cpp2
-rw-r--r--test/SemaCXX/cast-conversion.cpp2
-rw-r--r--test/SemaCXX/comma.cpp8
-rw-r--r--test/SemaCXX/conditional-expr.cpp10
-rw-r--r--test/SemaCXX/constructor-initializer.cpp8
-rw-r--r--test/SemaCXX/copy-assignment.cpp8
-rw-r--r--test/SemaCXX/dcl_ambig_res.cpp4
-rw-r--r--test/SemaCXX/dcl_init_aggr.cpp2
-rw-r--r--test/SemaCXX/decl-init-ref.cpp3
-rw-r--r--test/SemaCXX/enum.cpp4
-rw-r--r--test/SemaCXX/explicit.cpp39
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp16
-rw-r--r--test/SemaCXX/illegal-member-initialization.cpp7
-rw-r--r--test/SemaCXX/namespace-alias.cpp21
-rw-r--r--test/SemaCXX/nested-name-spec.cpp11
-rw-r--r--test/SemaCXX/new-delete-predefined-decl.cpp19
-rw-r--r--test/SemaCXX/new-delete.cpp15
-rw-r--r--test/SemaCXX/overload-call-copycon.cpp3
-rw-r--r--test/SemaCXX/overload-call.cpp12
-rw-r--r--test/SemaCXX/overload-member-call.cpp2
-rw-r--r--test/SemaCXX/overloaded-operator-decl.cpp6
-rw-r--r--test/SemaCXX/overloaded-operator.cpp2
-rw-r--r--test/SemaCXX/references.cpp13
-rw-r--r--test/SemaCXX/reinterpret-cast.cpp2
-rw-r--r--test/SemaCXX/static-cast.cpp11
-rw-r--r--test/SemaCXX/templated-friend-decl.cpp15
-rw-r--r--test/SemaCXX/using-decl-1.cpp35
-rw-r--r--test/SemaCXX/virtual-override.cpp27
-rw-r--r--test/SemaCXX/warn-missing-noreturn.cpp24
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp18
-rw-r--r--test/SemaCXX/warn-weak-vtables.cpp21
-rw-r--r--test/SemaObjC/cocoa.m2
-rw-r--r--test/SemaObjC/default-synthesize.m81
-rw-r--r--test/SemaObjC/duplicate-property-class-extension.m13
-rw-r--r--test/SemaObjC/exprs.m2
-rw-r--r--test/SemaObjC/format-strings-objc.m11
-rw-r--r--test/SemaObjC/method-arg-decay.m2
-rw-r--r--test/SemaObjC/property-13.m2
-rw-r--r--test/SemaObjC/property-not-lvalue.m14
-rw-r--r--test/SemaObjC/protocol-warn.m55
-rw-r--r--test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm23
-rw-r--r--test/SemaTemplate/deduction.cpp12
-rw-r--r--test/SemaTemplate/default-expr-arguments.cpp7
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp7
-rw-r--r--test/SemaTemplate/instantiate-decl-init.cpp24
-rw-r--r--test/SemaTemplate/instantiate-declref-ice.cpp2
-rw-r--r--test/SemaTemplate/instantiate-declref.cpp8
-rw-r--r--test/SemaTemplate/instantiate-expr-1.cpp25
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp6
-rw-r--r--test/SemaTemplate/instantiate-local-class.cpp18
-rw-r--r--test/SemaTemplate/instantiate-member-initializers.cpp2
-rw-r--r--test/SemaTemplate/instantiate-member-template.cpp25
-rw-r--r--test/SemaTemplate/member-function-template.cpp12
-rw-r--r--test/SemaTemplate/qualified-id.cpp15
-rw-r--r--test/SemaTemplate/recursive-template-instantiation.cpp2
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp21
-rw-r--r--test/SemaTemplate/temp_class_spec.cpp13
-rw-r--r--test/SemaTemplate/template-id-expr.cpp17
-rw-r--r--test/SemaTemplate/typename-specifier-4.cpp31
-rw-r--r--tools/CIndex/CIndex.cpp704
-rw-r--r--tools/CIndex/CIndex.exports19
-rw-r--r--tools/CIndex/CIndexCodeCompletion.cpp49
-rw-r--r--tools/CIndex/CIndexDiagnostic.cpp260
-rw-r--r--tools/CIndex/CIndexDiagnostic.h66
-rw-r--r--tools/CIndex/CIndexInclusionStack.cpp65
-rw-r--r--tools/CIndex/CIndexUSRs.cpp2
-rw-r--r--tools/CIndex/CIndexer.cpp34
-rw-r--r--tools/CIndex/CIndexer.h31
-rw-r--r--tools/CIndex/CMakeLists.txt2
-rw-r--r--tools/CIndex/CXCursor.cpp11
-rw-r--r--tools/CIndex/CXCursor.h2
-rw-r--r--tools/CIndex/CXSourceLocation.h76
-rw-r--r--tools/CIndex/Makefile1
-rw-r--r--tools/c-index-test/Makefile1
-rw-r--r--tools/c-index-test/c-index-test.c548
-rw-r--r--tools/driver/CMakeLists.txt5
-rw-r--r--tools/driver/Makefile7
-rw-r--r--tools/driver/cc1_main.cpp22
-rwxr-xr-xtools/scan-build/ccc-analyzer7
-rwxr-xr-xtools/scan-build/scan-build57
-rwxr-xr-xtools/scan-build/set-xcode-analyzer77
-rwxr-xr-xutils/ABITest/ABITestGen.py17
-rw-r--r--utils/ABITest/TypeGen.py83
-rw-r--r--www/analyzer/annotations.html34
-rw-r--r--www/analyzer/available_checks.html3
-rw-r--r--www/analyzer/content.css30
-rw-r--r--www/analyzer/dev_cxx.html52
-rw-r--r--www/analyzer/filing_bugs.html8
-rw-r--r--www/analyzer/images/analyzer_html.pngbin0 -> 63091 bytes
-rw-r--r--www/analyzer/images/analyzer_xcode.pngbin0 -> 87697 bytes
-rw-r--r--www/analyzer/images/tree/bullet.gifbin0 -> 64 bytes
-rw-r--r--www/analyzer/images/tree/minus.gifbin0 -> 79 bytes
-rw-r--r--www/analyzer/images/tree/plus.gifbin0 -> 83 bytes
-rw-r--r--www/analyzer/index.html25
-rw-r--r--www/analyzer/installation.html5
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/menu.css80
-rw-r--r--www/analyzer/menu.html.incl74
-rw-r--r--www/analyzer/menu.js17
-rw-r--r--www/analyzer/scan-build.html42
-rw-r--r--www/analyzer/scripts/dbtree.js1
-rw-r--r--www/analyzer/scripts/menu.js17
-rw-r--r--www/comparison.html3
-rw-r--r--www/cxx_status.html92
-rw-r--r--www/diagnostics.html29
-rw-r--r--www/index.html16
725 files changed, 29252 insertions, 10340 deletions
diff --git a/bindings/python/README.txt b/bindings/python/README.txt
new file mode 100644
index 000000000000..ccc2619ccf5b
--- /dev/null
+++ b/bindings/python/README.txt
@@ -0,0 +1,18 @@
+//===----------------------------------------------------------------------===//
+// Clang Python Bindings
+//===----------------------------------------------------------------------===//
+
+This directory implements Python bindings for Clang. Currently, only bindings
+for the CIndex C API exist.
+
+You may need to alter LD_LIBRARY_PATH so that the CIndex library can be
+found. The unit tests are designed to be run with 'nosetests'. For example:
+--
+$ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \
+ LD_LIBRARY_PATH=$(llvm-config --libdir) \
+ nosetests -v
+tests.cindex.test_index.test_create ... ok
+...
+
+OK
+--
diff --git a/bindings/python/clang/__init__.py b/bindings/python/clang/__init__.py
new file mode 100644
index 000000000000..88f30812383f
--- /dev/null
+++ b/bindings/python/clang/__init__.py
@@ -0,0 +1,24 @@
+#===- __init__.py - Clang Python Bindings --------------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+Clang Library Bindings
+======================
+
+This package provides access to the Clang compiler and libraries.
+
+The available modules are:
+
+ cindex
+
+ Bindings for the Clang indexing library.
+"""
+
+__all__ = ['cindex']
+
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
new file mode 100644
index 000000000000..c37c69b79b38
--- /dev/null
+++ b/bindings/python/clang/cindex.py
@@ -0,0 +1,933 @@
+#===- cindex.py - Python Indexing Library Bindings -----------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+Clang Indexing Library Bindings
+===============================
+
+This module provides an interface to the Clang indexing library. It is a
+low-level interface to the indexing library which attempts to match the Clang
+API directly while also being "pythonic". Notable differences from the C API
+are:
+
+ * string results are returned as Python strings, not CXString objects.
+
+ * null cursors are translated to None.
+
+ * access to child cursors is done via iteration, not visitation.
+
+The major indexing objects are:
+
+ Index
+
+ The top-level object which manages some global library state.
+
+ TranslationUnit
+
+ High-level object encapsulating the AST for a single translation unit. These
+ can be loaded from .ast files or parsed on the fly.
+
+ Cursor
+
+ Generic object for representing a node in the AST.
+
+ SourceRange, SourceLocation, and File
+
+ Objects representing information about the input source.
+
+Most object information is exposed using properties, when the underlying API
+call is efficient.
+"""
+
+# TODO
+# ====
+#
+# o API support for invalid translation units. Currently we can't even get the
+# diagnostics on failure because they refer to locations in an object that
+# will have been invalidated.
+#
+# o fix memory management issues (currently client must hold on to index and
+# translation unit, or risk crashes).
+#
+# o expose code completion APIs.
+#
+# o cleanup ctypes wrapping, would be nice to separate the ctypes details more
+# clearly, and hide from the external interface (i.e., help(cindex)).
+#
+# o implement additional SourceLocation, SourceRange, and File methods.
+
+from ctypes import *
+
+def get_cindex_library():
+ # FIXME: It's probably not the case that the library is actually found in
+ # this location. We need a better system of identifying and loading the
+ # CIndex library. It could be on path or elsewhere, or versioned, etc.
+ import platform
+ name = platform.system()
+ if name == 'Darwin':
+ return cdll.LoadLibrary('libCIndex.dylib')
+ elif name == 'Windows':
+ return cdll.LoadLibrary('libCIndex.dll')
+ else:
+ return cdll.LoadLibrary('libCIndex.so')
+
+# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
+# object. This is a problem, because it means that from_parameter will see an
+# integer and pass the wrong value on platforms where int != void*. Work around
+# this by marshalling object arguments as void**.
+c_object_p = POINTER(c_void_p)
+
+lib = get_cindex_library()
+
+### Structures and Utility Classes ###
+
+class _CXString(Structure):
+ """Helper for transforming CXString results."""
+
+ _fields_ = [("spelling", c_char_p), ("free", c_int)]
+
+ def __del__(self):
+ _CXString_dispose(self)
+
+ @staticmethod
+ def from_result(res, fn, args):
+ assert isinstance(res, _CXString)
+ return _CXString_getCString(res)
+
+class SourceLocation(Structure):
+ """
+ A SourceLocation represents a particular location within a source file.
+ """
+ _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
+ _data = None
+
+ def _get_instantiation(self):
+ if self._data is None:
+ f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
+ SourceLocation_loc(self, byref(f), byref(l), byref(c), byref(o))
+ f = File(f) if f else None
+ self._data = (f, int(l.value), int(c.value), int(c.value))
+ return self._data
+
+ @property
+ def file(self):
+ """Get the file represented by this source location."""
+ return self._get_instantiation()[0]
+
+ @property
+ def line(self):
+ """Get the line represented by this source location."""
+ return self._get_instantiation()[1]
+
+ @property
+ def column(self):
+ """Get the column represented by this source location."""
+ return self._get_instantiation()[2]
+
+ @property
+ def offset(self):
+ """Get the file offset represented by this source location."""
+ return self._get_instantiation()[3]
+
+ def __repr__(self):
+ return "<SourceLocation file %r, line %r, column %r>" % (
+ self.file.name if self.file else None, self.line, self.column)
+
+class SourceRange(Structure):
+ """
+ A SourceRange describes a range of source locations within the source
+ code.
+ """
+ _fields_ = [
+ ("ptr_data", c_void_p * 2),
+ ("begin_int_data", c_uint),
+ ("end_int_data", c_uint)]
+
+ # FIXME: Eliminate this and make normal constructor? Requires hiding ctypes
+ # object.
+ @staticmethod
+ def from_locations(start, end):
+ return SourceRange_getRange(start, end)
+
+ @property
+ def start(self):
+ """
+ Return a SourceLocation representing the first character within a
+ source range.
+ """
+ return SourceRange_start(self)
+
+ @property
+ def end(self):
+ """
+ Return a SourceLocation representing the last character within a
+ source range.
+ """
+ return SourceRange_end(self)
+
+ def __repr__(self):
+ return "<SourceRange start %r, end %r>" % (self.start, self.end)
+
+class Diagnostic(object):
+ """
+ A Diagnostic is a single instance of a Clang diagnostic. It includes the
+ diagnostic severity, the message, the location the diagnostic occurred, as
+ well as additional source ranges and associated fix-it hints.
+ """
+
+ Ignored = 0
+ Note = 1
+ Warning = 2
+ Error = 3
+ Fatal = 4
+
+ def __init__(self, severity, location, spelling, ranges, fixits):
+ self.severity = severity
+ self.location = location
+ self.spelling = spelling
+ self.ranges = ranges
+ self.fixits = fixits
+
+ def __repr__(self):
+ return "<Diagnostic severity %r, location %r, spelling %r>" % (
+ self.severity, self.location, self.spelling)
+
+class FixIt(object):
+ """
+ A FixIt represents a transformation to be applied to the source to
+ "fix-it". The fix-it shouldbe applied by replacing the given source range
+ with the given value.
+ """
+
+ def __init__(self, range, value):
+ self.range = range
+ self.value = value
+
+ def __repr__(self):
+ return "<FixIt range %r, value %r>" % (self.range, self.value)
+
+### Cursor Kinds ###
+
+class CursorKind(object):
+ """
+ A CursorKind describes the kind of entity that a cursor points to.
+ """
+
+ # The unique kind objects, indexed by id.
+ _kinds = []
+ _name_map = None
+
+ def __init__(self, value):
+ if value >= len(CursorKind._kinds):
+ CursorKind._kinds += [None] * (value - len(CursorKind._kinds) + 1)
+ if CursorKind._kinds[value] is not None:
+ raise ValueError,'CursorKind already loaded'
+ self.value = value
+ CursorKind._kinds[value] = self
+ CursorKind._name_map = None
+
+ def from_param(self):
+ return self.value
+
+ @property
+ def name(self):
+ """Get the enumeration name of this cursor kind."""
+ if self._name_map is None:
+ self._name_map = {}
+ for key,value in CursorKind.__dict__.items():
+ if isinstance(value,CursorKind):
+ self._name_map[value] = key
+ return self._name_map[self]
+
+ @staticmethod
+ def from_id(id):
+ if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None:
+ raise ValueError,'Unknown cursor kind'
+ return CursorKind._kinds[id]
+
+ @staticmethod
+ def get_all_kinds():
+ """Return all CursorKind enumeration instances."""
+ return filter(None, CursorKind._kinds)
+
+ def is_declaration(self):
+ """Test if this is a declaration kind."""
+ return CursorKind_is_decl(self)
+
+ def is_reference(self):
+ """Test if this is a reference kind."""
+ return CursorKind_is_ref(self)
+
+ def is_expression(self):
+ """Test if this is an expression kind."""
+ return CursorKind_is_expr(self)
+
+ def is_statement(self):
+ """Test if this is a statement kind."""
+ return CursorKind_is_stmt(self)
+
+ def is_invalid(self):
+ """Test if this is an invalid kind."""
+ return CursorKind_is_inv(self)
+
+ def __repr__(self):
+ return 'CursorKind.%s' % (self.name,)
+
+# FIXME: Is there a nicer way to expose this enumeration? We could potentially
+# represent the nested structure, or even build a class hierarchy. The main
+# things we want for sure are (a) simple external access to kinds, (b) a place
+# to hang a description and name, (c) easy to keep in sync with Index.h.
+
+###
+# Declaration Kinds
+
+# A declaration whose specific kind is not exposed via this interface.
+#
+# Unexposed declarations have the same operations as any other kind of
+# declaration; one can extract their location information, spelling, find their
+# definitions, etc. However, the specific kind of the declaration is not
+# reported.
+CursorKind.UNEXPOSED_DECL = CursorKind(1)
+
+# A C or C++ struct.
+CursorKind.STRUCT_DECL = CursorKind(2)
+
+# A C or C++ union.
+CursorKind.UNION_DECL = CursorKind(3)
+
+# A C++ class.
+CursorKind.CLASS_DECL = CursorKind(4)
+
+# An enumeration.
+CursorKind.ENUM_DECL = CursorKind(5)
+
+# A field (in C) or non-static data member (in C++) in a struct, union, or C++
+# class.
+CursorKind.FIELD_DECL = CursorKind(6)
+
+# An enumerator constant.
+CursorKind.ENUM_CONSTANT_DECL = CursorKind(7)
+
+# A function.
+CursorKind.FUNCTION_DECL = CursorKind(8)
+
+# A variable.
+CursorKind.VAR_DECL = CursorKind(9)
+
+# A function or method parameter.
+CursorKind.PARM_DECL = CursorKind(10)
+
+# An Objective-C @interface.
+CursorKind.OBJC_INTERFACE_DECL = CursorKind(11)
+
+# An Objective-C @interface for a category.
+CursorKind.OBJC_CATEGORY_DECL = CursorKind(12)
+
+# An Objective-C @protocol declaration.
+CursorKind.OBJC_PROTOCOL_DECL = CursorKind(13)
+
+# An Objective-C @property declaration.
+CursorKind.OBJC_PROPERTY_DECL = CursorKind(14)
+
+# An Objective-C instance variable.
+CursorKind.OBJC_IVAR_DECL = CursorKind(15)
+
+# An Objective-C instance method.
+CursorKind.OBJC_INSTANCE_METHOD_DECL = CursorKind(16)
+
+# An Objective-C class method.
+CursorKind.OBJC_CLASS_METHOD_DECL = CursorKind(17)
+
+# An Objective-C @implementation.
+CursorKind.OBJC_IMPLEMENTATION_DECL = CursorKind(18)
+
+# An Objective-C @implementation for a category.
+CursorKind.OBJC_CATEGORY_IMPL_DECL = CursorKind(19)
+
+# A typedef.
+CursorKind.TYPEDEF_DECL = CursorKind(20)
+
+###
+# Reference Kinds
+
+CursorKind.OBJC_SUPER_CLASS_REF = CursorKind(40)
+CursorKind.OBJC_PROTOCOL_REF = CursorKind(41)
+CursorKind.OBJC_CLASS_REF = CursorKind(42)
+
+# A reference to a type declaration.
+#
+# A type reference occurs anywhere where a type is named but not
+# declared. For example, given:
+# typedef unsigned size_type;
+# size_type size;
+#
+# The typedef is a declaration of size_type (CXCursor_TypedefDecl),
+# while the type of the variable "size" is referenced. The cursor
+# referenced by the type of size is the typedef for size_type.
+CursorKind.TYPE_REF = CursorKind(43)
+
+###
+# Invalid/Error Kinds
+
+CursorKind.INVALID_FILE = CursorKind(70)
+CursorKind.NO_DECL_FOUND = CursorKind(71)
+CursorKind.NOT_IMPLEMENTED = CursorKind(72)
+
+###
+# Expression Kinds
+
+# An expression whose specific kind is not exposed via this interface.
+#
+# Unexposed expressions have the same operations as any other kind of
+# expression; one can extract their location information, spelling, children,
+# etc. However, the specific kind of the expression is not reported.
+CursorKind.UNEXPOSED_EXPR = CursorKind(100)
+
+# An expression that refers to some value declaration, such as a function,
+# varible, or enumerator.
+CursorKind.DECL_REF_EXPR = CursorKind(101)
+
+# An expression that refers to a member of a struct, union, class, Objective-C
+# class, etc.
+CursorKind.MEMBER_REF_EXPR = CursorKind(102)
+
+# An expression that calls a function.
+CursorKind.CALL_EXPR = CursorKind(103)
+
+# An expression that sends a message to an Objective-C object or class.
+CursorKind.OBJC_MESSAGE_EXPR = CursorKind(104)
+
+# A statement whose specific kind is not exposed via this interface.
+#
+# Unexposed statements have the same operations as any other kind of statement;
+# one can extract their location information, spelling, children, etc. However,
+# the specific kind of the statement is not reported.
+CursorKind.UNEXPOSED_STMT = CursorKind(200)
+
+###
+# Other Kinds
+
+# Cursor that represents the translation unit itself.
+#
+# The translation unit cursor exists primarily to act as the root cursor for
+# traversing the contents of a translation unit.
+CursorKind.TRANSLATION_UNIT = CursorKind(300)
+
+### Cursors ###
+
+class Cursor(Structure):
+ """
+ The Cursor class represents a reference to an element within the AST. It
+ acts as a kind of iterator.
+ """
+ _fields_ = [("_kind_id", c_int), ("data", c_void_p * 3)]
+
+ def __eq__(self, other):
+ return Cursor_eq(self, other)
+
+ def __ne__(self, other):
+ return not Cursor_eq(self, other)
+
+ def is_definition(self):
+ """
+ Returns true if the declaration pointed at by the cursor is also a
+ definition of that entity.
+ """
+ return Cursor_is_def(self)
+
+ def get_definition(self):
+ """
+ If the cursor is a reference to a declaration or a declaration of
+ some entity, return a cursor that points to the definition of that
+ entity.
+ """
+ # TODO: Should probably check that this is either a reference or
+ # declaration prior to issuing the lookup.
+ return Cursor_def(self)
+
+ def get_usr(self):
+ """Return the Unified Symbol Resultion (USR) for the entity referenced
+ by the given cursor (or None).
+
+ A Unified Symbol Resolution (USR) is a string that identifies a
+ particular entity (function, class, variable, etc.) within a
+ program. USRs can be compared across translation units to determine,
+ e.g., when references in one translation refer to an entity defined in
+ another translation unit."""
+ return Cursor_usr(self)
+
+ @property
+ def kind(self):
+ """Return the kind of this cursor."""
+ return CursorKind.from_id(self._kind_id)
+
+ @property
+ def spelling(self):
+ """Return the spelling of the entity pointed at by the cursor."""
+ if not self.kind.is_declaration():
+ # FIXME: clang_getCursorSpelling should be fixed to not assert on
+ # this, for consistency with clang_getCursorUSR.
+ return None
+ return Cursor_spelling(self)
+
+ @property
+ def location(self):
+ """
+ Return the source location (the starting character) of the entity
+ pointed at by the cursor.
+ """
+ return Cursor_loc(self)
+
+ @property
+ def extent(self):
+ """
+ Return the source range (the range of text) occupied by the entity
+ pointed at by the cursor.
+ """
+ return Cursor_extent(self)
+
+ def get_children(self):
+ """Return an iterator for accessing the children of this cursor."""
+
+ # FIXME: Expose iteration from CIndex, PR6125.
+ def visitor(child, parent, children):
+ # FIXME: Document this assertion in API.
+ # FIXME: There should just be an isNull method.
+ assert child != Cursor_null()
+ children.append(child)
+ return 1 # continue
+ children = []
+ Cursor_visit(self, Cursor_visit_callback(visitor), children)
+ return iter(children)
+
+ @staticmethod
+ def from_result(res, fn, args):
+ assert isinstance(res, Cursor)
+ # FIXME: There should just be an isNull method.
+ if res == Cursor_null():
+ return None
+ return res
+
+## CIndex Objects ##
+
+# CIndex objects (derived from ClangObject) are essentially lightweight
+# wrappers attached to some underlying object, which is exposed via CIndex as
+# a void*.
+
+class ClangObject(object):
+ """
+ A helper for Clang objects. This class helps act as an intermediary for
+ the ctypes library and the Clang CIndex library.
+ """
+ def __init__(self, obj):
+ assert isinstance(obj, c_object_p) and obj
+ self.obj = self._as_parameter_ = obj
+
+ def from_param(self):
+ return self._as_parameter_
+
+
+class _CXUnsavedFile(Structure):
+ """Helper for passing unsaved file arguments."""
+ _fields_ = [("name", c_char_p), ("contents", c_char_p), ('length', c_ulong)]
+
+## Diagnostic Conversion ##
+
+# Diagnostic objects are temporary, we must extract all the information from the
+# diagnostic object when it is passed to the callback.
+
+_clang_getDiagnosticSeverity = lib.clang_getDiagnosticSeverity
+_clang_getDiagnosticSeverity.argtypes = [c_object_p]
+_clang_getDiagnosticSeverity.restype = c_int
+
+_clang_getDiagnosticLocation = lib.clang_getDiagnosticLocation
+_clang_getDiagnosticLocation.argtypes = [c_object_p]
+_clang_getDiagnosticLocation.restype = SourceLocation
+
+_clang_getDiagnosticSpelling = lib.clang_getDiagnosticSpelling
+_clang_getDiagnosticSpelling.argtypes = [c_object_p]
+_clang_getDiagnosticSpelling.restype = _CXString
+_clang_getDiagnosticSpelling.errcheck = _CXString.from_result
+
+_clang_getDiagnosticNumRanges = lib.clang_getDiagnosticNumRanges
+_clang_getDiagnosticNumRanges.argtypes = [c_object_p]
+_clang_getDiagnosticNumRanges.restype = c_uint
+
+_clang_getDiagnosticRange = lib.clang_getDiagnosticRange
+_clang_getDiagnosticRange.argtypes = [c_object_p, c_uint]
+_clang_getDiagnosticRange.restype = SourceRange
+
+_clang_getDiagnosticNumFixIts = lib.clang_getDiagnosticNumFixIts
+_clang_getDiagnosticNumFixIts.argtypes = [c_object_p]
+_clang_getDiagnosticNumFixIts.restype = c_uint
+
+_clang_getDiagnosticFixItKind = lib.clang_getDiagnosticFixItKind
+_clang_getDiagnosticFixItKind.argtypes = [c_object_p, c_uint]
+_clang_getDiagnosticFixItKind.restype = c_int
+
+_clang_getDiagnosticFixItInsertion = lib.clang_getDiagnosticFixItInsertion
+_clang_getDiagnosticFixItInsertion.argtypes = [c_object_p, c_uint,
+ POINTER(SourceLocation)]
+_clang_getDiagnosticFixItInsertion.restype = _CXString
+_clang_getDiagnosticFixItInsertion.errcheck = _CXString.from_result
+
+_clang_getDiagnosticFixItRemoval = lib.clang_getDiagnosticFixItRemoval
+_clang_getDiagnosticFixItRemoval.argtypes = [c_object_p, c_uint,
+ POINTER(SourceLocation)]
+_clang_getDiagnosticFixItRemoval.restype = _CXString
+_clang_getDiagnosticFixItRemoval.errcheck = _CXString.from_result
+
+_clang_getDiagnosticFixItReplacement = lib.clang_getDiagnosticFixItReplacement
+_clang_getDiagnosticFixItReplacement.argtypes = [c_object_p, c_uint,
+ POINTER(SourceRange)]
+_clang_getDiagnosticFixItReplacement.restype = _CXString
+_clang_getDiagnosticFixItReplacement.errcheck = _CXString.from_result
+
+def _convert_fixit(diag_ptr, index):
+ # We normalize all the fix-its to a single representation, this is more
+ # convenient.
+ #
+ # FIXME: Push this back into API? It isn't exactly clear what the
+ # SourceRange semantics are, we should make sure we can represent an empty
+ # range.
+ kind = _clang_getDiagnosticFixItKind(diag_ptr, index)
+ range = None
+ value = None
+ if kind == 0: # insertion
+ location = SourceLocation()
+ value = _clang_getDiagnosticFixItInsertion(diag_ptr, index,
+ byref(location))
+ range = SourceRange.from_locations(location, location)
+ elif kind == 1: # removal
+ range = _clang_getDiagnosticFixItRemoval(diag_ptr, index)
+ value = ''
+ else: # replacement
+ assert kind == 2
+ range = SourceRange()
+ value = _clang_getDiagnosticFixItReplacement(diag_ptr, index,
+ byref(range))
+ return FixIt(range, value)
+
+def _convert_diag(diag_ptr, diag_list):
+ severity = _clang_getDiagnosticSeverity(diag_ptr)
+ loc = _clang_getDiagnosticLocation(diag_ptr)
+ spelling = _clang_getDiagnosticSpelling(diag_ptr)
+
+ # Diagnostic ranges.
+ num_ranges = _clang_getDiagnosticNumRanges(diag_ptr)
+ ranges = [_clang_getDiagnosticRange(diag_ptr, i)
+ for i in range(num_ranges)]
+
+ fixits = [_convert_fixit(diag_ptr, i)
+ for i in range(_clang_getDiagnosticNumFixIts(diag_ptr))]
+
+ diag_list.append(Diagnostic(severity, loc, spelling, ranges, fixits))
+
+###
+
+class Index(ClangObject):
+ """
+ The Index type provides the primary interface to the Clang CIndex library,
+ primarily by providing an interface for reading and parsing translation
+ units.
+ """
+
+ @staticmethod
+ def create(excludeDecls=False):
+ """
+ Create a new Index.
+ Parameters:
+ excludeDecls -- Exclude local declarations from translation units.
+ """
+ return Index(Index_create(excludeDecls))
+
+ def __del__(self):
+ Index_dispose(self)
+
+ def read(self, path):
+ """Load the translation unit from the given AST file."""
+ # FIXME: In theory, we could support streaming diagnostics. It's hard to
+ # integrate this into the API cleanly, however. Resolve.
+ diags = []
+ ptr = TranslationUnit_read(self, path,
+ Diagnostic_callback(_convert_diag), diags)
+ return TranslationUnit(ptr) if ptr else None
+
+ def parse(self, path, args = [], unsaved_files = []):
+ """
+ Load the translation unit from the given source code file by running
+ clang and generating the AST before loading. Additional command line
+ parameters can be passed to clang via the args parameter.
+
+ In-memory contents for files can be provided by passing a list of pairs
+ to as unsaved_files, the first item should be the filenames to be mapped
+ and the second should be the contents to be substituted for the
+ file. The contents may be passed as strings or file objects.
+ """
+ arg_array = 0
+ if len(args):
+ arg_array = (c_char_p * len(args))(* args)
+ unsaved_files_array = 0
+ if len(unsaved_files):
+ unsaved_files_array = (_CXUnsavedFile * len(unsaved_files))()
+ for i,(name,value) in enumerate(unsaved_files):
+ if not isinstance(value, str):
+ # FIXME: It would be great to support an efficient version
+ # of this, one day.
+ value = value.read()
+ print value
+ if not isinstance(value, str):
+ raise TypeError,'Unexpected unsaved file contents.'
+ unsaved_files_array[i].name = name
+ unsaved_files_array[i].contents = value
+ unsaved_files_array[i].length = len(value)
+ # FIXME: In theory, we could support streaming diagnostics. It's hard to
+ # integrate this into the API cleanly, however. Resolve.
+ diags = []
+ ptr = TranslationUnit_parse(self, path, len(args), arg_array,
+ len(unsaved_files), unsaved_files_array,
+ Diagnostic_callback(_convert_diag), diags)
+ return TranslationUnit(ptr, diags) if ptr else None
+
+
+class TranslationUnit(ClangObject):
+ """
+ The TranslationUnit class represents a source code translation unit and
+ provides read-only access to its top-level declarations.
+ """
+
+ def __init__(self, ptr, diagnostics):
+ ClangObject.__init__(self, ptr)
+ self.diagnostics = diagnostics
+
+ def __del__(self):
+ TranslationUnit_dispose(self)
+
+ @property
+ def cursor(self):
+ """Retrieve the cursor that represents the given translation unit."""
+ return TranslationUnit_cursor(self)
+
+ @property
+ def spelling(self):
+ """Get the original translation unit source file name."""
+ return TranslationUnit_spelling(self)
+
+ def get_includes(self):
+ """
+ Return an iterable sequence of FileInclusion objects that describe the
+ sequence of inclusions in a translation unit. The first object in
+ this sequence is always the input file. Note that this method will not
+ recursively iterate over header files included through precompiled
+ headers.
+ """
+ def visitor(fobj, lptr, depth, includes):
+ loc = lptr.contents
+ includes.append(FileInclusion(loc.file, File(fobj), loc, depth))
+
+ # Automatically adapt CIndex/ctype pointers to python objects
+ includes = []
+ TranslationUnit_includes(self,
+ TranslationUnit_includes_callback(visitor),
+ includes)
+ return iter(includes)
+
+class File(ClangObject):
+ """
+ The File class represents a particular source file that is part of a
+ translation unit.
+ """
+
+ @property
+ def name(self):
+ """Return the complete file and path name of the file."""
+ return File_name(self)
+
+ @property
+ def time(self):
+ """Return the last modification time of the file."""
+ return File_time(self)
+
+class FileInclusion(object):
+ """
+ The FileInclusion class represents the inclusion of one source file by
+ another via a '#include' directive or as the input file for the translation
+ unit. This class provides information about the included file, the including
+ file, the location of the '#include' directive and the depth of the included
+ file in the stack. Note that the input file has depth 0.
+ """
+
+ def __init__(self, src, tgt, loc, depth):
+ self.source = src
+ self.include = tgt
+ self.location = loc
+ self.depth = depth
+
+ @property
+ def is_input_file(self):
+ """True if the included file is the input file."""
+ return self.depth == 0
+
+# Additional Functions and Types
+
+# String Functions
+_CXString_dispose = lib.clang_disposeString
+_CXString_dispose.argtypes = [_CXString]
+
+_CXString_getCString = lib.clang_getCString
+_CXString_getCString.argtypes = [_CXString]
+_CXString_getCString.restype = c_char_p
+
+# Source Location Functions
+SourceLocation_loc = lib.clang_getInstantiationLocation
+SourceLocation_loc.argtypes = [SourceLocation, POINTER(c_object_p),
+ POINTER(c_uint), POINTER(c_uint),
+ POINTER(c_uint)]
+
+# Source Range Functions
+SourceRange_getRange = lib.clang_getRange
+SourceRange_getRange.argtypes = [SourceLocation, SourceLocation]
+SourceRange_getRange.restype = SourceRange
+
+SourceRange_start = lib.clang_getRangeStart
+SourceRange_start.argtypes = [SourceRange]
+SourceRange_start.restype = SourceLocation
+
+SourceRange_end = lib.clang_getRangeEnd
+SourceRange_end.argtypes = [SourceRange]
+SourceRange_end.restype = SourceLocation
+
+# CursorKind Functions
+CursorKind_is_decl = lib.clang_isDeclaration
+CursorKind_is_decl.argtypes = [CursorKind]
+CursorKind_is_decl.restype = bool
+
+CursorKind_is_ref = lib.clang_isReference
+CursorKind_is_ref.argtypes = [CursorKind]
+CursorKind_is_ref.restype = bool
+
+CursorKind_is_expr = lib.clang_isExpression
+CursorKind_is_expr.argtypes = [CursorKind]
+CursorKind_is_expr.restype = bool
+
+CursorKind_is_stmt = lib.clang_isStatement
+CursorKind_is_stmt.argtypes = [CursorKind]
+CursorKind_is_stmt.restype = bool
+
+CursorKind_is_inv = lib.clang_isInvalid
+CursorKind_is_inv.argtypes = [CursorKind]
+CursorKind_is_inv.restype = bool
+
+# Cursor Functions
+# TODO: Implement this function
+Cursor_get = lib.clang_getCursor
+Cursor_get.argtypes = [TranslationUnit, SourceLocation]
+Cursor_get.restype = Cursor
+
+Cursor_null = lib.clang_getNullCursor
+Cursor_null.restype = Cursor
+
+Cursor_usr = lib.clang_getCursorUSR
+Cursor_usr.argtypes = [Cursor]
+Cursor_usr.restype = _CXString
+Cursor_usr.errcheck = _CXString.from_result
+
+Cursor_is_def = lib.clang_isCursorDefinition
+Cursor_is_def.argtypes = [Cursor]
+Cursor_is_def.restype = bool
+
+Cursor_def = lib.clang_getCursorDefinition
+Cursor_def.argtypes = [Cursor]
+Cursor_def.restype = Cursor
+Cursor_def.errcheck = Cursor.from_result
+
+Cursor_eq = lib.clang_equalCursors
+Cursor_eq.argtypes = [Cursor, Cursor]
+Cursor_eq.restype = c_uint
+
+Cursor_spelling = lib.clang_getCursorSpelling
+Cursor_spelling.argtypes = [Cursor]
+Cursor_spelling.restype = _CXString
+Cursor_spelling.errcheck = _CXString.from_result
+
+Cursor_loc = lib.clang_getCursorLocation
+Cursor_loc.argtypes = [Cursor]
+Cursor_loc.restype = SourceLocation
+
+Cursor_extent = lib.clang_getCursorExtent
+Cursor_extent.argtypes = [Cursor]
+Cursor_extent.restype = SourceRange
+
+Cursor_ref = lib.clang_getCursorReferenced
+Cursor_ref.argtypes = [Cursor]
+Cursor_ref.restype = Cursor
+Cursor_ref.errcheck = Cursor.from_result
+
+Cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
+Cursor_visit = lib.clang_visitChildren
+Cursor_visit.argtypes = [Cursor, Cursor_visit_callback, py_object]
+Cursor_visit.restype = c_uint
+
+# Index Functions
+Index_create = lib.clang_createIndex
+Index_create.argtypes = [c_int]
+Index_create.restype = c_object_p
+
+Index_dispose = lib.clang_disposeIndex
+Index_dispose.argtypes = [Index]
+
+# Translation Unit Functions
+Diagnostic_callback = CFUNCTYPE(None, c_object_p, py_object)
+
+TranslationUnit_read = lib.clang_createTranslationUnit
+TranslationUnit_read.argtypes = [Index, c_char_p,
+ Diagnostic_callback, py_object]
+TranslationUnit_read.restype = c_object_p
+
+TranslationUnit_parse = lib.clang_createTranslationUnitFromSourceFile
+TranslationUnit_parse.argtypes = [Index, c_char_p, c_int, c_void_p,
+ c_int, c_void_p,
+ Diagnostic_callback, py_object]
+TranslationUnit_parse.restype = c_object_p
+
+TranslationUnit_cursor = lib.clang_getTranslationUnitCursor
+TranslationUnit_cursor.argtypes = [TranslationUnit]
+TranslationUnit_cursor.restype = Cursor
+TranslationUnit_cursor.errcheck = Cursor.from_result
+
+TranslationUnit_spelling = lib.clang_getTranslationUnitSpelling
+TranslationUnit_spelling.argtypes = [TranslationUnit]
+TranslationUnit_spelling.restype = _CXString
+TranslationUnit_spelling.errcheck = _CXString.from_result
+
+TranslationUnit_dispose = lib.clang_disposeTranslationUnit
+TranslationUnit_dispose.argtypes = [TranslationUnit]
+
+TranslationUnit_includes_callback = CFUNCTYPE(None,
+ c_object_p,
+ POINTER(SourceLocation),
+ c_uint, py_object)
+TranslationUnit_includes = lib.clang_getInclusions
+TranslationUnit_includes.argtypes = [TranslationUnit,
+ TranslationUnit_includes_callback,
+ py_object]
+
+# File Functions
+File_name = lib.clang_getFileName
+File_name.argtypes = [File]
+File_name.restype = c_char_p
+
+File_time = lib.clang_getFileTime
+File_time.argtypes = [File]
+File_time.restype = c_uint
+
+###
+
+__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind',
+ 'Diagnostic', 'FixIt', 'SourceRange', 'SourceLocation', 'File']
diff --git a/bindings/python/examples/cindex/cindex-dump.py b/bindings/python/examples/cindex/cindex-dump.py
new file mode 100644
index 000000000000..af7ddab6ea53
--- /dev/null
+++ b/bindings/python/examples/cindex/cindex-dump.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+#===- cindex-dump.py - cindex/Python Source Dump -------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+"""
+A simple command line tool for dumping a source file using the Clang Index
+Library.
+"""
+
+def get_diag_info(diag):
+ return { 'severity' : diag.severity,
+ 'location' : diag.location,
+ 'spelling' : diag.spelling,
+ 'ranges' : diag.ranges,
+ 'fixits' : diag.fixits }
+
+def get_cursor_id(cursor, cursor_list = []):
+ if not opts.showIDs:
+ return None
+
+ if cursor is None:
+ return None
+
+ # FIXME: This is really slow. It would be nice if the index API exposed
+ # something that let us hash cursors.
+ for i,c in enumerate(cursor_list):
+ if cursor == c:
+ return i
+ cursor_list.append(cursor)
+ return len(cursor_list) - 1
+
+def get_info(node, depth=0):
+ if opts.maxDepth is not None and depth >= opts.maxDepth:
+ children = None
+ else:
+ children = [get_info(c, depth+1)
+ for c in node.get_children()]
+ return { 'id' : get_cursor_id(node),
+ 'kind' : node.kind,
+ 'usr' : node.get_usr(),
+ 'spelling' : node.spelling,
+ 'location' : node.location,
+ 'extent.start' : node.extent.start,
+ 'extent.end' : node.extent.end,
+ 'is_definition' : node.is_definition(),
+ 'definition id' : get_cursor_id(node.get_definition()),
+ 'children' : children }
+
+def main():
+ from clang.cindex import Index
+ from pprint import pprint
+
+ from optparse import OptionParser, OptionGroup
+
+ global opts
+
+ parser = OptionParser("usage: %prog [options] {filename} [clang-args*]")
+ parser.add_option("", "--show-ids", dest="showIDs",
+ help="Don't compute cursor IDs (very slow)",
+ default=False)
+ parser.add_option("", "--max-depth", dest="maxDepth",
+ help="Limit cursor expansion to depth N",
+ metavar="N", type=int, default=None)
+ parser.disable_interspersed_args()
+ (opts, args) = parser.parse_args()
+
+ if len(args) == 0:
+ parser.error('invalid number arguments')
+
+ index = Index.create()
+ tu = index.parse(None, args)
+ if not tu:
+ parser.error("unable to load input")
+
+ pprint(('diags', map(get_diag_info, tu.diagnostics)))
+ pprint(('nodes', get_info(tu.cursor)))
+
+if __name__ == '__main__':
+ main()
+
diff --git a/bindings/python/examples/cindex/cindex-includes.py b/bindings/python/examples/cindex/cindex-includes.py
new file mode 100644
index 000000000000..17500227a349
--- /dev/null
+++ b/bindings/python/examples/cindex/cindex-includes.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+#===- cindex-includes.py - cindex/Python Inclusion Graph -----*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+"""
+A simple command line tool for dumping a Graphviz description (dot) that
+describes include dependencies.
+"""
+
+def main():
+ import sys
+ from clang.cindex import Index
+
+ from optparse import OptionParser, OptionGroup
+
+ parser = OptionParser("usage: %prog [options] {filename} [clang-args*]")
+ parser.disable_interspersed_args()
+ (opts, args) = parser.parse_args()
+ if len(args) == 0:
+ parser.error('invalid number arguments')
+
+ # FIXME: Add an output file option
+ out = sys.stdout
+
+ index = Index.create()
+ tu = index.parse(None, args)
+ if not tu:
+ parser.error("unable to load input")
+
+ # A helper function for generating the node name.
+ def name(f):
+ if f:
+ return "\"" + f.name + "\""
+
+ # Generate the include graph
+ out.write("digraph G {\n")
+ for i in tu.get_includes():
+ line = " ";
+ if i.is_input_file:
+ # Always write the input file as a node just in case it doesn't
+ # actually include anything. This would generate a 1 node graph.
+ line += name(i.include)
+ else:
+ line += '%s->%s' % (name(i.source), name(i.include))
+ line += "\n";
+ out.write(line)
+ out.write("}\n")
+
+if __name__ == '__main__':
+ main()
+
diff --git a/bindings/python/tests/__init__.py b/bindings/python/tests/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/bindings/python/tests/__init__.py
diff --git a/bindings/python/tests/cindex/INPUTS/header1.h b/bindings/python/tests/cindex/INPUTS/header1.h
new file mode 100644
index 000000000000..b4eacbee3754
--- /dev/null
+++ b/bindings/python/tests/cindex/INPUTS/header1.h
@@ -0,0 +1,6 @@
+#ifndef HEADER1
+#define HEADER1
+
+#include "header3.h"
+
+#endif
diff --git a/bindings/python/tests/cindex/INPUTS/header2.h b/bindings/python/tests/cindex/INPUTS/header2.h
new file mode 100644
index 000000000000..c4eddc0c5620
--- /dev/null
+++ b/bindings/python/tests/cindex/INPUTS/header2.h
@@ -0,0 +1,6 @@
+#ifndef HEADER2
+#define HEADER2
+
+#include "header3.h"
+
+#endif
diff --git a/bindings/python/tests/cindex/INPUTS/header3.h b/bindings/python/tests/cindex/INPUTS/header3.h
new file mode 100644
index 000000000000..6dca764860e1
--- /dev/null
+++ b/bindings/python/tests/cindex/INPUTS/header3.h
@@ -0,0 +1,3 @@
+// Not a guarded header!
+
+void f();
diff --git a/bindings/python/tests/cindex/INPUTS/hello.cpp b/bindings/python/tests/cindex/INPUTS/hello.cpp
new file mode 100644
index 000000000000..7ef086e56b2c
--- /dev/null
+++ b/bindings/python/tests/cindex/INPUTS/hello.cpp
@@ -0,0 +1,6 @@
+#include "stdio.h"
+
+int main(int argc, char* argv[]) {
+ printf("hello world\n");
+ return 0;
+}
diff --git a/bindings/python/tests/cindex/INPUTS/include.cpp b/bindings/python/tests/cindex/INPUTS/include.cpp
new file mode 100644
index 000000000000..60cfdaae4d09
--- /dev/null
+++ b/bindings/python/tests/cindex/INPUTS/include.cpp
@@ -0,0 +1,5 @@
+#include "header1.h"
+#include "header2.h"
+#include "header1.h"
+
+int main() { }
diff --git a/bindings/python/tests/cindex/INPUTS/parse_arguments.c b/bindings/python/tests/cindex/INPUTS/parse_arguments.c
new file mode 100644
index 000000000000..7196486c78a1
--- /dev/null
+++ b/bindings/python/tests/cindex/INPUTS/parse_arguments.c
@@ -0,0 +1,2 @@
+int DECL_ONE = 1;
+int DECL_TWO = 2;
diff --git a/bindings/python/tests/cindex/__init__.py b/bindings/python/tests/cindex/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/bindings/python/tests/cindex/__init__.py
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
new file mode 100644
index 000000000000..a653ba7bf28e
--- /dev/null
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -0,0 +1,59 @@
+from clang.cindex import Index, CursorKind
+
+kInput = """\
+// FIXME: Find nicer way to drop builtins and other cruft.
+int start_decl;
+
+struct s0 {
+ int a;
+ int b;
+};
+
+struct s1;
+
+void f0(int a0, int a1) {
+ int l0, l1;
+
+ if (a0)
+ return;
+
+ for (;;) {
+ break;
+ }
+}
+"""
+
+def test_get_children():
+ index = Index.create()
+ tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
+
+ # Skip until past start_decl.
+ it = tu.cursor.get_children()
+ while it.next().spelling != 'start_decl':
+ pass
+
+ tu_nodes = list(it)
+
+ assert len(tu_nodes) == 3
+
+ assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
+ assert tu_nodes[0].spelling == 's0'
+ assert tu_nodes[0].is_definition() == True
+ assert tu_nodes[0].location.file.name == 't.c'
+ assert tu_nodes[0].location.line == 4
+ assert tu_nodes[0].location.column == 8
+
+ s0_nodes = list(tu_nodes[0].get_children())
+ assert len(s0_nodes) == 2
+ assert s0_nodes[0].kind == CursorKind.FIELD_DECL
+ assert s0_nodes[0].spelling == 'a'
+ assert s0_nodes[1].kind == CursorKind.FIELD_DECL
+ assert s0_nodes[1].spelling == 'b'
+
+ assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
+ assert tu_nodes[1].spelling == 's1'
+ assert tu_nodes[1].is_definition() == False
+
+ assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
+ assert tu_nodes[2].spelling == 'f0'
+ assert tu_nodes[2].is_definition() == True
diff --git a/bindings/python/tests/cindex/test_cursor_kind.py b/bindings/python/tests/cindex/test_cursor_kind.py
new file mode 100644
index 000000000000..bdfa31855835
--- /dev/null
+++ b/bindings/python/tests/cindex/test_cursor_kind.py
@@ -0,0 +1,27 @@
+from clang.cindex import CursorKind
+
+def test_name():
+ assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
+
+def test_get_all_kinds():
+ assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds()
+ assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds()
+
+def test_kind_groups():
+ """Check that every kind classifies to exactly one group."""
+
+ assert CursorKind.UNEXPOSED_DECL.is_declaration()
+ assert CursorKind.TYPE_REF.is_reference()
+ assert CursorKind.DECL_REF_EXPR.is_expression()
+ assert CursorKind.UNEXPOSED_STMT.is_statement()
+ assert CursorKind.INVALID_FILE.is_invalid()
+
+ for k in CursorKind.get_all_kinds():
+ group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
+ 'is_statement', 'is_invalid')
+ if getattr(k, n)()]
+
+ if k == CursorKind.TRANSLATION_UNIT:
+ assert len(group) == 0
+ else:
+ assert len(group) == 1
diff --git a/bindings/python/tests/cindex/test_diagnostics.py b/bindings/python/tests/cindex/test_diagnostics.py
new file mode 100644
index 000000000000..85187652917b
--- /dev/null
+++ b/bindings/python/tests/cindex/test_diagnostics.py
@@ -0,0 +1,48 @@
+from clang.cindex import *
+
+def tu_from_source(source):
+ index = Index.create()
+ tu = index.parse('INPUT.c', unsaved_files = [('INPUT.c', source)])
+ # FIXME: Remove the need for this.
+ tu.index = index
+ return tu
+
+# FIXME: We need support for invalid translation units to test better.
+
+def test_diagnostic_warning():
+ tu = tu_from_source("""int f0() {}\n""")
+ assert len(tu.diagnostics) == 1
+ assert tu.diagnostics[0].severity == Diagnostic.Warning
+ assert tu.diagnostics[0].location.line == 1
+ assert tu.diagnostics[0].location.column == 11
+ assert (tu.diagnostics[0].spelling ==
+ 'control reaches end of non-void function')
+
+def test_diagnostic_note():
+ # FIXME: We aren't getting notes here for some reason.
+ index = Index.create()
+ tu = tu_from_source("""#define A x\nvoid *A = 1;\n""")
+ assert len(tu.diagnostics) == 1
+ assert tu.diagnostics[0].severity == Diagnostic.Warning
+ assert tu.diagnostics[0].location.line == 2
+ assert tu.diagnostics[0].location.column == 7
+ assert 'incompatible' in tu.diagnostics[0].spelling
+# assert tu.diagnostics[1].severity == Diagnostic.Note
+# assert tu.diagnostics[1].location.line == 1
+# assert tu.diagnostics[1].location.column == 11
+# assert tu.diagnostics[1].spelling == 'instantiated from'
+
+def test_diagnostic_fixit():
+ index = Index.create()
+ tu = tu_from_source("""struct { int f0; } x = { f0 : 1 };""")
+ assert len(tu.diagnostics) == 1
+ assert tu.diagnostics[0].severity == Diagnostic.Warning
+ assert tu.diagnostics[0].location.line == 1
+ assert tu.diagnostics[0].location.column == 31
+ assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
+ assert len(tu.diagnostics[0].fixits) == 1
+ assert tu.diagnostics[0].fixits[0].range.start.line == 1
+ assert tu.diagnostics[0].fixits[0].range.start.column == 26
+ assert tu.diagnostics[0].fixits[0].range.end.line == 1
+ assert tu.diagnostics[0].fixits[0].range.end.column == 30
+ assert tu.diagnostics[0].fixits[0].value == '.f0 = '
diff --git a/bindings/python/tests/cindex/test_index.py b/bindings/python/tests/cindex/test_index.py
new file mode 100644
index 000000000000..dc173f04d218
--- /dev/null
+++ b/bindings/python/tests/cindex/test_index.py
@@ -0,0 +1,15 @@
+from clang.cindex import *
+import os
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+def test_create():
+ index = Index.create()
+
+# FIXME: test Index.read
+
+def test_parse():
+ index = Index.create()
+ assert isinstance(index, Index)
+ tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
+ assert isinstance(tu, TranslationUnit)
diff --git a/bindings/python/tests/cindex/test_translation_unit.py b/bindings/python/tests/cindex/test_translation_unit.py
new file mode 100644
index 000000000000..3c05c3f06af4
--- /dev/null
+++ b/bindings/python/tests/cindex/test_translation_unit.py
@@ -0,0 +1,73 @@
+from clang.cindex import *
+import os
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+def test_spelling():
+ path = os.path.join(kInputsDir, 'hello.cpp')
+ index = Index.create()
+ tu = index.parse(path)
+ assert tu.spelling == path
+
+def test_cursor():
+ path = os.path.join(kInputsDir, 'hello.cpp')
+ index = Index.create()
+ tu = index.parse(path)
+ c = tu.cursor
+ assert isinstance(c, Cursor)
+ assert c.kind is CursorKind.TRANSLATION_UNIT
+
+def test_parse_arguments():
+ path = os.path.join(kInputsDir, 'parse_arguments.c')
+ index = Index.create()
+ tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'hello'
+ assert spellings[-1] == 'hi'
+
+def test_unsaved_files():
+ index = Index.create()
+ # FIXME: Why can't we just use "fake.h" here (instead of /tmp/fake.h)?
+ tu = index.parse('fake.c', unsaved_files = [
+ ('fake.c', """
+#include "/tmp/fake.h"
+int x;
+int SOME_DEFINE;
+"""),
+ ('/tmp/fake.h', """
+#define SOME_DEFINE y
+""")
+ ])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'x'
+ assert spellings[-1] == 'y'
+
+def test_unsaved_files_2():
+ import StringIO
+ index = Index.create()
+ tu = index.parse('fake.c', unsaved_files = [
+ ('fake.c', StringIO.StringIO('int x;'))])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-1] == 'x'
+
+
+def test_includes():
+ def eq(expected, actual):
+ if not actual.is_input_file:
+ return expected[0] == actual.source.name and \
+ expected[1] == actual.include.name
+ else:
+ return expected[1] == actual.include.name
+
+ src = os.path.join(kInputsDir, 'include.cpp')
+ h1 = os.path.join(kInputsDir, "header1.h")
+ h2 = os.path.join(kInputsDir, "header2.h")
+ h3 = os.path.join(kInputsDir, "header3.h")
+ inc = [(None, src), (src, h1), (h1, h3), (src, h2), (h2, h3)]
+
+ index = Index.create()
+ tu = index.parse(src)
+ for i in zip(inc, tu.get_includes()):
+ assert eq(i[0], i[1])
+
+
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index d1cd032ec033..e24b54d3e892 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -33,6 +33,12 @@
1A4C41BF105B4C0B0047B5E7 /* CGClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */; };
1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */; };
1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5D5E570E5E81010023C059 /* CGCXX.cpp */; };
+ 1A621BB7110FE6AA009E6834 /* TargetInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621BB5110FE6AA009E6834 /* TargetInfo.cpp */; };
+ 1A621C4211111D61009E6834 /* CIndexCodeCompletion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621C3A11111D61009E6834 /* CIndexCodeCompletion.cpp */; };
+ 1A621C4311111D61009E6834 /* CIndexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621C3B11111D61009E6834 /* CIndexer.cpp */; };
+ 1A621C4411111D61009E6834 /* CIndexInclusionStack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621C3D11111D61009E6834 /* CIndexInclusionStack.cpp */; };
+ 1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621C3E11111D61009E6834 /* CIndexUSRs.cpp */; };
+ 1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621C3F11111D61009E6834 /* CXCursor.cpp */; };
1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */; };
1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */; };
1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */; };
@@ -62,7 +68,6 @@
1ADD795610A90C6100741BBA /* TemplateBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795310A90C6100741BBA /* TemplateBase.cpp */; };
1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; };
1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; };
- 1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */; };
1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */; };
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; };
3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; };
@@ -382,6 +387,16 @@
1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXInheritance.cpp; path = lib/AST/CXXInheritance.cpp; sourceTree = "<group>"; };
1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = "<group>"; };
1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A621BB5110FE6AA009E6834 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetInfo.cpp; path = lib/CodeGen/TargetInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A621BB6110FE6AA009E6834 /* TargetInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TargetInfo.h; path = lib/CodeGen/TargetInfo.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A621C3A11111D61009E6834 /* CIndexCodeCompletion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexCodeCompletion.cpp; path = tools/CIndex/CIndexCodeCompletion.cpp; sourceTree = "<group>"; };
+ 1A621C3B11111D61009E6834 /* CIndexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexer.cpp; path = tools/CIndex/CIndexer.cpp; sourceTree = "<group>"; };
+ 1A621C3C11111D61009E6834 /* CIndexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CIndexer.h; path = tools/CIndex/CIndexer.h; sourceTree = "<group>"; };
+ 1A621C3D11111D61009E6834 /* CIndexInclusionStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexInclusionStack.cpp; path = tools/CIndex/CIndexInclusionStack.cpp; sourceTree = "<group>"; };
+ 1A621C3E11111D61009E6834 /* CIndexUSRs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndexUSRs.cpp; path = tools/CIndex/CIndexUSRs.cpp; sourceTree = "<group>"; };
+ 1A621C3F11111D61009E6834 /* CXCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXCursor.cpp; path = tools/CIndex/CXCursor.cpp; sourceTree = "<group>"; };
+ 1A621C4011111D61009E6834 /* CXCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXCursor.h; path = tools/CIndex/CXCursor.h; sourceTree = "<group>"; };
+ 1A621C4111111D61009E6834 /* CXSourceLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXSourceLocation.h; path = tools/CIndex/CXSourceLocation.h; sourceTree = "<group>"; };
1A649E1D0F9599D9005B965E /* CGBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGBlocks.h; path = lib/CodeGen/CGBlocks.h; sourceTree = "<group>"; };
1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = "<group>"; tabWidth = 2; };
1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeCompleteConsumer.cpp; path = lib/Sema/CodeCompleteConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
@@ -428,7 +443,6 @@
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; };
1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetABIInfo.cpp; path = lib/CodeGen/TargetABIInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AF1B50E109A4FB800AFAFAC /* CGException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGException.cpp; path = lib/CodeGen/CGException.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -543,7 +557,6 @@
9012911510470FCE0083456D /* Index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Index.h; path = "clang-c/Index.h"; sourceTree = "<group>"; };
9012911C1048068D0083456D /* ASTUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTUnit.cpp; path = lib/Frontend/ASTUnit.cpp; sourceTree = "<group>"; };
9012911F104812F90083456D /* CIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndex.cpp; path = tools/CIndex/CIndex.cpp; sourceTree = "<group>"; };
- 90129120104812F90083456D /* CIndex.exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CIndex.exports; path = tools/CIndex/CIndex.exports; sourceTree = "<group>"; };
904753791096376F00CBDDDD /* CXXInheritance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXXInheritance.h; path = clang/AST/CXXInheritance.h; sourceTree = "<group>"; };
9047537A1096376F00CBDDDD /* Redeclarable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Redeclarable.h; path = clang/AST/Redeclarable.h; sourceTree = "<group>"; };
9047537B1096376F00CBDDDD /* TypeLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLoc.h; path = clang/AST/TypeLoc.h; sourceTree = "<group>"; };
@@ -727,7 +740,7 @@
DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitPreprocessor.cpp; path = lib/Frontend/InitPreprocessor.cpp; sourceTree = "<group>"; };
DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = "<group>"; };
DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtCXX.h; path = clang/AST/StmtCXX.h; sourceTree = "<group>"; };
- DECB77120FA5752300F5FBC7 /* PCHReaderStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReaderStmt.cpp; path = lib/Frontend/PCHReaderStmt.cpp; sourceTree = "<group>"; };
+ DECB77120FA5752300F5FBC7 /* PCHReaderStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReaderStmt.cpp; path = lib/Frontend/PCHReaderStmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
DECB77780FA579B000F5FBC7 /* PCHReaderDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReaderDecl.cpp; path = lib/Frontend/PCHReaderDecl.cpp; sourceTree = "<group>"; };
DECB77F60FA5850200F5FBC7 /* PCHWriterDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriterDecl.cpp; path = lib/Frontend/PCHWriterDecl.cpp; sourceTree = "<group>"; };
DECB78160FA5882F00F5FBC7 /* PCHWriterStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriterStmt.cpp; path = lib/Frontend/PCHWriterStmt.cpp; sourceTree = "<group>"; };
@@ -1037,6 +1050,7 @@
356EF9B30C8F7DCA006650F5 /* Analysis */ = {
isa = PBXGroup;
children = (
+ DE67E70A0C020EC500F66BC5 /* SemaType.cpp */,
35544B840F5C7F9D00D92AA9 /* Path-Sensitive */,
3507E4CC0E27FEB900FB7B57 /* Flow-Sensitive Analyses */,
3507E4C30E27FE3800FB7B57 /* Checks */,
@@ -1093,7 +1107,14 @@
isa = PBXGroup;
children = (
9012911F104812F90083456D /* CIndex.cpp */,
- 90129120104812F90083456D /* CIndex.exports */,
+ 1A621C3B11111D61009E6834 /* CIndexer.cpp */,
+ 1A621C3A11111D61009E6834 /* CIndexCodeCompletion.cpp */,
+ 1A621C3C11111D61009E6834 /* CIndexer.h */,
+ 1A621C3D11111D61009E6834 /* CIndexInclusionStack.cpp */,
+ 1A621C3E11111D61009E6834 /* CIndexUSRs.cpp */,
+ 1A621C3F11111D61009E6834 /* CXCursor.cpp */,
+ 1A621C4011111D61009E6834 /* CXCursor.h */,
+ 1A621C4111111D61009E6834 /* CXSourceLocation.h */,
);
name = CIndex;
sourceTree = "<group>";
@@ -1265,7 +1286,6 @@
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */,
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
- DE67E70A0C020EC500F66BC5 /* SemaType.cpp */,
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */,
);
name = Sema;
@@ -1330,7 +1350,8 @@
1A2193CC0F45EEB700C0713D /* Mangle.cpp */,
1A2193CD0F45EEB700C0713D /* Mangle.h */,
DE928B120C05659200231DA4 /* ModuleBuilder.cpp */,
- 1AE4EE3F103B8A0A00888A23 /* TargetABIInfo.cpp */,
+ 1A621BB5110FE6AA009E6834 /* TargetInfo.cpp */,
+ 1A621BB6110FE6AA009E6834 /* TargetInfo.h */,
);
name = CodeGen;
sourceTree = "<group>";
@@ -1927,7 +1948,6 @@
1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */,
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */,
1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */,
- 1AE4EE40103B8A0A00888A23 /* TargetABIInfo.cpp in Sources */,
90FD6D7B103C3D49005F5B73 /* Analyzer.cpp in Sources */,
90FD6D7C103C3D49005F5B73 /* ASTLocation.cpp in Sources */,
90FD6D7D103C3D49005F5B73 /* DeclReferenceMap.cpp in Sources */,
@@ -1967,6 +1987,12 @@
1ACB57EB1105820D0047B991 /* TypeXML.cpp in Sources */,
1ACB57EC1105820D0047B991 /* VerifyDiagnosticsClient.cpp in Sources */,
1A97825B1108BA18002B98FC /* CGVTT.cpp in Sources */,
+ 1A621BB7110FE6AA009E6834 /* TargetInfo.cpp in Sources */,
+ 1A621C4211111D61009E6834 /* CIndexCodeCompletion.cpp in Sources */,
+ 1A621C4311111D61009E6834 /* CIndexer.cpp in Sources */,
+ 1A621C4411111D61009E6834 /* CIndexInclusionStack.cpp in Sources */,
+ 1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */,
+ 1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index e2a44eaed0b9..d32842b5d23d 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -205,12 +205,28 @@ is used in the file argument.</p>
<h2 id="vectors">Vectors and Extended Vectors</h2>
<!-- ======================================================================= -->
-<p>Supports the GCC vector extensions, plus some stuff like V[1]. ext_vector
-with V.xyzw syntax and other tidbits. See also <a
-href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
+<p>Supports the GCC vector extensions, plus some stuff like V[1].</p>
+
+<p>Also supports <tt>ext_vector</tt>, which additionally support for V.xyzw
+syntax and other tidbits as seen in OpenCL. An example is:</p>
+
+<blockquote>
+<pre>
+typedef float float4 <b>__attribute__((ext_vector_type(4)))</b>;
+typedef float float2 <b>__attribute__((ext_vector_type(2)))</b>;
+
+float4 foo(float2 a, float2 b) {
+ float4 c;
+ c.xz = a;
+ c.yw = b;
+ return c;
+}
+</blockquote>
<p>Query for this feature with __has_feature(attribute_ext_vector_type).</p>
+<p>See also <a href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
+
<!-- ======================================================================= -->
<h2 id="checking_language_features">Checks for Standard Language Features</h2>
<!-- ======================================================================= -->
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 13e020941472..41715bb2ac65 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -789,14 +789,12 @@ definition.</li>
<h2 id="cxx">C++ Language Features</h2>
<!-- ======================================================================= -->
-<p>At this point, Clang C++ is not generally useful. However, Clang C++ support
+<p>At this point, Clang C++ is not production-quality and is not recommended for use beyond experimentation. However, Clang C++ support
is under active development and is progressing rapidly. Please see the <a
href="http://clang.llvm.org/cxx_status.html">C++ Status</a> page for details or
ask on the mailing list about how you can help.</p>
-<p>Note that the clang driver will refuse to even try to use clang to compile
-C++ code unless you pass the <tt>-ccc-clang-cxx</tt> option to the driver. If
-you really want to play with Clang's C++ support, please pass that flag. </p>
+<p>Note that released Clang compilers will refuse to even try to use clang to compile C++ code unless you pass the <tt>-ccc-clang-cxx</tt> option to the driver. To turn on Clang's C++ support, please pass that flag. Clang compilers built from the Subversion trunk enable C++ support by default, and do not require the <tt>-ccc-clang-cxx</tt> flag.</p>
<!-- ======================================================================= -->
<h2 id="objcxx">Objective C++ Language Features</h2>
diff --git a/examples/PrintFunctionNames/Makefile b/examples/PrintFunctionNames/Makefile
index 3c0c1f82ad8a..57d3ba9b0cd9 100644
--- a/examples/PrintFunctionNames/Makefile
+++ b/examples/PrintFunctionNames/Makefile
@@ -11,7 +11,6 @@ LEVEL = ../../../..
LIBRARYNAME = PrintFunctionNames
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
# Include this here so we can get the configuration of the targets that have
# been configured for construction. We have to do this early so we can set up
diff --git a/examples/wpa/Makefile b/examples/wpa/Makefile
index 54b61d08571a..2be7ff10d899 100644
--- a/examples/wpa/Makefile
+++ b/examples/wpa/Makefile
@@ -2,7 +2,6 @@ LEVEL = ../../../..
TOOLNAME = clang-wpa
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
NO_INSTALL = 1
# No plugins, optimize startup time.
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index ef17ed1ca8be..84ec4724e0db 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -36,23 +36,23 @@ extern "C" {
/** \defgroup CINDEX C Interface to Clang
*
- * The C Interface to Clang provides a relatively small API that exposes
+ * The C Interface to Clang provides a relatively small API that exposes
* facilities for parsing source code into an abstract syntax tree (AST),
* loading already-parsed ASTs, traversing the AST, associating
* physical source locations with elements within the AST, and other
* facilities that support Clang-based development tools.
*
- * This C interface to Clang will never provide all of the information
+ * This C interface to Clang will never provide all of the information
* representation stored in Clang's C++ AST, nor should it: the intent is to
* maintain an API that is relatively stable from one release to the next,
* providing only the basic functionality needed to support development tools.
- *
- * To avoid namespace pollution, data types are prefixed with "CX" and
+ *
+ * To avoid namespace pollution, data types are prefixed with "CX" and
* functions are prefixed with "clang_".
*
* @{
*/
-
+
/**
* \brief An "index" that consists of a set of translation units that would
* typically be linked together into an executable or library.
@@ -69,7 +69,7 @@ typedef void *CXTranslationUnit; /* A translation unit instance. */
* to various callbacks and visitors.
*/
typedef void *CXClientData;
-
+
/**
* \brief Provides the contents of a file that has not yet been saved to disk.
*
@@ -78,14 +78,14 @@ typedef void *CXClientData;
* yet been saved to disk.
*/
struct CXUnsavedFile {
- /**
- * \brief The file whose contents have not yet been saved.
+ /**
+ * \brief The file whose contents have not yet been saved.
*
* This file must already exist in the file system.
*/
const char *Filename;
- /**
+ /**
* \brief A null-terminated buffer containing the unsaved contents
* of this file.
*/
@@ -103,7 +103,7 @@ struct CXUnsavedFile {
*
* @{
*/
-
+
/**
* \brief A character string.
*
@@ -132,38 +132,36 @@ CINDEX_LINKAGE void clang_disposeString(CXString string);
/**
* @}
*/
-
-/**
+
+/**
* \brief clang_createIndex() provides a shared context for creating
* translation units. It provides two options:
*
* - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local"
* declarations (when loading any new translation units). A "local" declaration
- * is one that belongs in the translation unit itself and not in a precompiled
+ * is one that belongs in the translation unit itself and not in a precompiled
* header that was used by the translation unit. If zero, all declarations
* will be enumerated.
*
- * - displayDiagnostics: when non-zero, diagnostics will be output. If zero,
- * diagnostics will be ignored.
- *
* Here is an example:
*
- * // excludeDeclsFromPCH = 1, displayDiagnostics = 1
- * Idx = clang_createIndex(1, 1);
+ * // excludeDeclsFromPCH = 1
+ * Idx = clang_createIndex(1);
*
* // IndexTest.pch was produced with the following command:
* // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch"
* TU = clang_createTranslationUnit(Idx, "IndexTest.pch");
*
* // This will load all the symbols from 'IndexTest.pch'
- * clang_visitChildren(clang_getTranslationUnitCursor(TU),
+ * clang_visitChildren(clang_getTranslationUnitCursor(TU),
* TranslationUnitVisitor, 0);
* clang_disposeTranslationUnit(TU);
*
* // This will load all the symbols from 'IndexTest.c', excluding symbols
* // from 'IndexTest.pch'.
- * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch", 0 };
- * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args);
+ * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch" };
+ * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args,
+ * 0, 0);
* clang_visitChildren(clang_getTranslationUnitCursor(TU),
* TranslationUnitVisitor, 0);
* clang_disposeTranslationUnit(TU);
@@ -172,14 +170,18 @@ CINDEX_LINKAGE void clang_disposeString(CXString string);
* -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks
* (which gives the indexer the same performance benefit as the compiler).
*/
-CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
- int displayDiagnostics);
+CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH);
+
+/**
+ * \brief Destroy the given index.
+ *
+ * The index must not be destroyed until all of the translation units created
+ * within that index have been destroyed.
+ */
CINDEX_LINKAGE void clang_disposeIndex(CXIndex index);
-CINDEX_LINKAGE CXString
-clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
/**
- * \brief Request that AST's be generated external for API calls which parse
+ * \brief Request that AST's be generated externally for API calls which parse
* source code on the fly, e.g. \see createTranslationUnitFromSourceFile.
*
* Note: This is for debugging purposes only, and may be removed at a later
@@ -190,71 +192,23 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
*/
CINDEX_LINKAGE void clang_setUseExternalASTGeneration(CXIndex index,
int value);
-
-/**
- * \brief Create a translation unit from an AST file (-emit-ast).
- */
-CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(
- CXIndex, const char *ast_filename
-);
-
-/**
- * \brief Destroy the specified CXTranslationUnit object.
- */
-CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
-
-/**
- * \brief Return the CXTranslationUnit for a given source file and the provided
- * command line arguments one would pass to the compiler.
- *
- * Note: The 'source_filename' argument is optional. If the caller provides a
- * NULL pointer, the name of the source file is expected to reside in the
- * specified command line arguments.
- *
- * Note: When encountered in 'clang_command_line_args', the following options
- * are ignored:
- *
- * '-c'
- * '-emit-ast'
- * '-fsyntax-only'
- * '-o <output file>' (both '-o' and '<output file>' are ignored)
- *
- *
- * \param source_filename - The name of the source file to load, or NULL if the
- * source file is included in clang_command_line_args.
- *
- * \param num_unsaved_files the number of unsaved file entries in \p
- * unsaved_files.
- *
- * \param unsaved_files the files that have not yet been saved to disk
- * but may be required for code completion, including the contents of
- * those files.
- */
-CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile(
- CXIndex CIdx,
- const char *source_filename,
- int num_clang_command_line_args,
- const char **clang_command_line_args,
- unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files);
-
/**
* \defgroup CINDEX_FILES File manipulation routines
*
* @{
*/
-
+
/**
* \brief A particular source file that is part of a translation unit.
*/
typedef void *CXFile;
-
+
/**
* \brief Retrieve the complete file and path name of the given file.
*/
CINDEX_LINKAGE const char *clang_getFileName(CXFile SFile);
-
+
/**
* \brief Retrieve the last modification time of the given file.
*/
@@ -264,15 +218,15 @@ CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile);
* \brief Retrieve a file handle within the given translation unit.
*
* \param tu the translation unit
- *
+ *
* \param file_name the name of the file.
*
* \returns the file handle for the named file in the translation unit \p tu,
* or a NULL file handle if the file was not a part of this translation unit.
*/
-CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
+CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
const char *file_name);
-
+
/**
* @}
*/
@@ -289,7 +243,7 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
*
* @{
*/
-
+
/**
* \brief Identifies a specific source location within a translation
* unit.
@@ -298,18 +252,18 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
* particular file, line, and column.
*/
typedef struct {
- void *ptr_data;
+ void *ptr_data[2];
unsigned int_data;
} CXSourceLocation;
/**
- * \brief Identifies a range of source locations in the source code.
+ * \brief Identifies a half-open character range in the source code.
*
* Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the
* starting and end locations from a source range, respectively.
*/
typedef struct {
- void *ptr_data;
+ void *ptr_data[2];
unsigned begin_int_data;
unsigned end_int_data;
} CXSourceRange;
@@ -318,10 +272,10 @@ typedef struct {
* \brief Retrieve a NULL (invalid) source location.
*/
CINDEX_LINKAGE CXSourceLocation clang_getNullLocation();
-
+
/**
* \determine Determine whether two source locations, which must refer into
- * the same translation unit, refer to exactly the same point in the source
+ * the same translation unit, refer to exactly the same point in the source
* code.
*
* \returns non-zero if the source locations refer to the same location, zero
@@ -329,15 +283,20 @@ CINDEX_LINKAGE CXSourceLocation clang_getNullLocation();
*/
CINDEX_LINKAGE unsigned clang_equalLocations(CXSourceLocation loc1,
CXSourceLocation loc2);
-
+
/**
- * \brief Retrieves the source location associated with a given
- * file/line/column in a particular translation unit.
+ * \brief Retrieves the source location associated with a given file/line/column
+ * in a particular translation unit.
*/
CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu,
CXFile file,
unsigned line,
unsigned column);
+
+/**
+ * \brief Retrieve a NULL (invalid) source range.
+ */
+CINDEX_LINKAGE CXSourceRange clang_getNullRange();
/**
* \brief Retrieve a source range given the beginning and ending source
@@ -345,37 +304,41 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu,
*/
CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin,
CXSourceLocation end);
-
+
/**
- * \brief Retrieve the file, line, and column represented by the
- * given source location.
+ * \brief Retrieve the file, line, column, and offset represented by
+ * the given source location.
+ *
+ * \param location the location within a source file that will be decomposed
+ * into its parts.
*
- * \param location the location within a source file that will be
- * decomposed into its parts.
+ * \param file [out] if non-NULL, will be set to the file to which the given
+ * source location points.
*
- * \param file if non-NULL, will be set to the file to which the given
+ * \param line [out] if non-NULL, will be set to the line to which the given
* source location points.
*
- * \param line if non-NULL, will be set to the line to which the given
+ * \param column [out] if non-NULL, will be set to the column to which the given
* source location points.
*
- * \param column if non-NULL, will be set to the column to which the
- * given source location points.
+ * \param offset [out] if non-NULL, will be set to the offset into the
+ * buffer to which the given source location points.
*/
CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location,
CXFile *file,
unsigned *line,
- unsigned *column);
+ unsigned *column,
+ unsigned *offset);
/**
- * \brief Retrieve a source location representing the first
- * character within a source range.
+ * \brief Retrieve a source location representing the first character within a
+ * source range.
*/
CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range);
/**
- * \brief Retrieve a source location representing the last
- * character within a source range.
+ * \brief Retrieve a source location representing the last character within a
+ * source range.
*/
CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range);
@@ -384,14 +347,289 @@ CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range);
*/
/**
+ * \defgroup CINDEX_DIAG Diagnostic reporting
+ *
+ * @{
+ */
+
+/**
+ * \brief Describes the severity of a particular diagnostic.
+ */
+enum CXDiagnosticSeverity {
+ /**
+ * \brief A diagnostic that has been suppressed, e.g., by a command-line
+ * option.
+ */
+ CXDiagnostic_Ignored = 0,
+
+ /**
+ * \brief This diagnostic is a note that should be attached to the
+ * previous (non-note) diagnostic.
+ */
+ CXDiagnostic_Note = 1,
+
+ /**
+ * \brief This diagnostic indicates suspicious code that may not be
+ * wrong.
+ */
+ CXDiagnostic_Warning = 2,
+
+ /**
+ * \brief This diagnostic indicates that the code is ill-formed.
+ */
+ CXDiagnostic_Error = 3,
+
+ /**
+ * \brief This diagnostic indicates that the code is ill-formed such
+ * that future parser recovery is unlikely to produce useful
+ * results.
+ */
+ CXDiagnostic_Fatal = 4
+};
+
+/**
+ * \brief Describes the kind of fix-it hint expressed within a
+ * diagnostic.
+ */
+enum CXFixItKind {
+ /**
+ * \brief A fix-it hint that inserts code at a particular position.
+ */
+ CXFixIt_Insertion = 0,
+
+ /**
+ * \brief A fix-it hint that removes code within a range.
+ */
+ CXFixIt_Removal = 1,
+
+ /**
+ * \brief A fix-it hint that replaces the code within a range with another
+ * string.
+ */
+ CXFixIt_Replacement = 2
+};
+
+/**
+ * \brief A single diagnostic, containing the diagnostic's severity,
+ * location, text, source ranges, and fix-it hints.
+ */
+typedef void *CXDiagnostic;
+
+/**
+ * \brief Callback function invoked for each diagnostic emitted during
+ * translation.
+ *
+ * \param Diagnostic the diagnostic emitted during translation. This
+ * diagnostic pointer is only valid during the execution of the
+ * callback.
+ *
+ * \param ClientData the callback client data.
+ */
+typedef void (*CXDiagnosticCallback)(CXDiagnostic Diagnostic,
+ CXClientData ClientData);
+
+/**
+ * \brief Determine the severity of the given diagnostic.
+ */
+CINDEX_LINKAGE enum CXDiagnosticSeverity
+clang_getDiagnosticSeverity(CXDiagnostic);
+
+/**
+ * \brief Retrieve the source location of the given diagnostic.
+ *
+ * This location is where Clang would print the caret ('^') when
+ * displaying the diagnostic on the command line.
+ */
+CINDEX_LINKAGE CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic);
+
+/**
+ * \brief Retrieve the text of the given diagnostic.
+ */
+CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic);
+
+/**
+ * \brief Determine the number of source ranges associated with the given
+ * diagnostic.
+ */
+CINDEX_LINKAGE unsigned clang_getDiagnosticNumRanges(CXDiagnostic);
+
+/**
+ * \brief Retrieve a source range associated with the diagnostic.
+ *
+ * A diagnostic's source ranges highlight important elements in the source
+ * code. On the command line, Clang displays source ranges by
+ * underlining them with '~' characters.
+ *
+ * \param Diagnostic the diagnostic whose range is being extracted.
+ *
+ * \param Range the zero-based index specifying which range to
+ *
+ * \returns the requested source range.
+ */
+CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic,
+ unsigned Range);
+
+/**
+ * \brief Determine the number of fix-it hints associated with the
+ * given diagnostic.
+ */
+CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic);
+
+/**
+ * \brief Retrieve the kind of the given fix-it.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the fix-it to query.
+ */
+CINDEX_LINKAGE enum CXFixItKind
+clang_getDiagnosticFixItKind(CXDiagnostic Diagnostic, unsigned FixIt);
+
+/**
+ * \brief Retrieve the insertion information for an insertion fix-it.
+ *
+ * For a fix-it that describes an insertion into a text buffer,
+ * retrieve the source location where the text should be inserted and
+ * the text to be inserted.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the insertion fix-it.
+ *
+ * \param Location will be set to the location where text should be
+ * inserted.
+ *
+ * \returns the text string to insert at the given location.
+ */
+CINDEX_LINKAGE CXString
+clang_getDiagnosticFixItInsertion(CXDiagnostic Diagnostic, unsigned FixIt,
+ CXSourceLocation *Location);
+
+/**
+ * \brief Retrieve the removal information for a removal fix-it.
+ *
+ * For a fix-it that describes a removal from a text buffer, retrieve
+ * the source range that should be removed.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the removal fix-it.
+ *
+ * \returns a source range describing the text that should be removed
+ * from the buffer.
+ */
+CINDEX_LINKAGE CXSourceRange
+clang_getDiagnosticFixItRemoval(CXDiagnostic Diagnostic, unsigned FixIt);
+
+/**
+ * \brief Retrieve the replacement information for an replacement fix-it.
+ *
+ * For a fix-it that describes replacement of text in the text buffer
+ * with alternative text.
+ *
+ * \param Diagnostic the diagnostic whose fix-its are being queried.
+ *
+ * \param FixIt the zero-based index of the replacement fix-it.
+ *
+ * \param Range will be set to the source range whose text should be
+ * replaced with the returned text.
+ *
+ * \returns the text string to use as replacement text.
+ */
+CINDEX_LINKAGE CXString
+clang_getDiagnosticFixItReplacement(CXDiagnostic Diagnostic, unsigned FixIt,
+ CXSourceRange *Range);
+
+/**
+ * @}
+ */
+
+/**
+ * \defgroup CINDEX_TRANSLATION_UNIT Translation unit manipulation
+ *
+ * The routines in this group provide the ability to create and destroy
+ * translation units from files, either by parsing the contents of the files or
+ * by reading in a serialized representation of a translation unit.
+ *
+ * @{
+ */
+
+/**
+ * \brief Get the original translation unit source file name.
+ */
+CINDEX_LINKAGE CXString
+clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
+
+/**
+ * \brief Return the CXTranslationUnit for a given source file and the provided
+ * command line arguments one would pass to the compiler.
+ *
+ * Note: The 'source_filename' argument is optional. If the caller provides a
+ * NULL pointer, the name of the source file is expected to reside in the
+ * specified command line arguments.
+ *
+ * Note: When encountered in 'clang_command_line_args', the following options
+ * are ignored:
+ *
+ * '-c'
+ * '-emit-ast'
+ * '-fsyntax-only'
+ * '-o <output file>' (both '-o' and '<output file>' are ignored)
+ *
+ *
+ * \param source_filename - The name of the source file to load, or NULL if the
+ * source file is included in clang_command_line_args.
+ *
+ * \param num_unsaved_files the number of unsaved file entries in \p
+ * unsaved_files.
+ *
+ * \param unsaved_files the files that have not yet been saved to disk
+ * but may be required for code completion, including the contents of
+ * those files.
+ *
+ * \param diag_callback callback function that will receive any diagnostics
+ * emitted while processing this source file. If NULL, diagnostics will be
+ * suppressed.
+ *
+ * \param diag_client_data client data that will be passed to the diagnostic
+ * callback function.
+ */
+CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile(
+ CXIndex CIdx,
+ const char *source_filename,
+ int num_clang_command_line_args,
+ const char **clang_command_line_args,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data);
+
+/**
+ * \brief Create a translation unit from an AST file (-emit-ast).
+ */
+CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex,
+ const char *ast_filename,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data);
+
+/**
+ * \brief Destroy the specified CXTranslationUnit object.
+ */
+CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
+
+/**
+ * @}
+ */
+
+/**
* \brief Describes the kind of entity that a cursor refers to.
*/
enum CXCursorKind {
/* Declarations */
CXCursor_FirstDecl = 1,
- /**
+ /**
* \brief A declaration whose specific kind is not exposed via this
- * interface.
+ * interface.
*
* Unexposed declarations have the same operations as any other kind
* of declaration; one can extract their location information,
@@ -400,14 +638,14 @@ enum CXCursorKind {
*/
CXCursor_UnexposedDecl = 1,
/** \brief A C or C++ struct. */
- CXCursor_StructDecl = 2,
+ CXCursor_StructDecl = 2,
/** \brief A C or C++ union. */
CXCursor_UnionDecl = 3,
/** \brief A C++ class. */
CXCursor_ClassDecl = 4,
/** \brief An enumeration. */
CXCursor_EnumDecl = 5,
- /**
+ /**
* \brief A field (in C) or non-static data member (in C++) in a
* struct, union, or C++ class.
*/
@@ -441,10 +679,10 @@ enum CXCursorKind {
/** \brief A typedef */
CXCursor_TypedefDecl = 20,
CXCursor_LastDecl = 20,
-
+
/* References */
CXCursor_FirstRef = 40, /* Decl references */
- CXCursor_ObjCSuperClassRef = 40,
+ CXCursor_ObjCSuperClassRef = 40,
CXCursor_ObjCProtocolRef = 41,
CXCursor_ObjCClassRef = 42,
/**
@@ -464,20 +702,20 @@ enum CXCursorKind {
*/
CXCursor_TypeRef = 43,
CXCursor_LastRef = 43,
-
+
/* Error conditions */
CXCursor_FirstInvalid = 70,
CXCursor_InvalidFile = 70,
CXCursor_NoDeclFound = 71,
CXCursor_NotImplemented = 72,
CXCursor_LastInvalid = 72,
-
+
/* Expressions */
CXCursor_FirstExpr = 100,
-
+
/**
* \brief An expression whose specific kind is not exposed via this
- * interface.
+ * interface.
*
* Unexposed expressions have the same operations as any other kind
* of expression; one can extract their location information,
@@ -485,27 +723,27 @@ enum CXCursorKind {
* expression is not reported.
*/
CXCursor_UnexposedExpr = 100,
-
+
/**
* \brief An expression that refers to some value declaration, such
* as a function, varible, or enumerator.
*/
CXCursor_DeclRefExpr = 101,
-
+
/**
* \brief An expression that refers to a member of a struct, union,
* class, Objective-C class, etc.
*/
CXCursor_MemberRefExpr = 102,
-
+
/** \brief An expression that calls a function. */
CXCursor_CallExpr = 103,
-
+
/** \brief An expression that sends a message to an Objective-C
object or class. */
CXCursor_ObjCMessageExpr = 104,
CXCursor_LastExpr = 104,
-
+
/* Statements */
CXCursor_FirstStmt = 200,
/**
@@ -519,7 +757,7 @@ enum CXCursorKind {
*/
CXCursor_UnexposedStmt = 200,
CXCursor_LastStmt = 200,
-
+
/**
* \brief Cursor that represents the translation unit itself.
*
@@ -533,7 +771,7 @@ enum CXCursorKind {
* \brief A cursor representing some element in the abstract syntax tree for
* a translation unit.
*
- * The cursor abstraction unifies the different kinds of entities in a
+ * The cursor abstraction unifies the different kinds of entities in a
* program--declaration, statements, expressions, references to declarations,
* etc.--under a single "cursor" abstraction with a common set of operations.
* Common operation for a cursor include: getting the physical location in
@@ -550,19 +788,19 @@ enum CXCursorKind {
typedef struct {
enum CXCursorKind kind;
void *data[3];
-} CXCursor;
+} CXCursor;
/**
* \defgroup CINDEX_CURSOR_MANIP Cursor manipulations
*
* @{
*/
-
+
/**
* \brief Retrieve the NULL cursor, which represents no entity.
*/
CINDEX_LINKAGE CXCursor clang_getNullCursor(void);
-
+
/**
* \brief Retrieve the cursor that represents the given translation unit.
*
@@ -575,7 +813,7 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
* \brief Determine whether two cursors are equivalent.
*/
CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
-
+
/**
* \brief Retrieve the kind of the given cursor.
*/
@@ -607,21 +845,21 @@ CINDEX_LINKAGE unsigned clang_isExpression(enum CXCursorKind);
CINDEX_LINKAGE unsigned clang_isStatement(enum CXCursorKind);
/**
- * \brief Determine whether the given cursor kind represents an invalid
+ * \brief Determine whether the given cursor kind represents an invalid
* cursor.
- */
+ */
CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind);
/**
- * \brief Determine whether the given cursor kind represents a translation
- * unit.
+ * \brief Determine whether the given cursor kind represents a translation
+ * unit.
*/
CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind);
-
+
/**
* @}
*/
-
+
/**
* \defgroup CINDEX_CURSOR_SOURCE Mapping between cursors and source code
*
@@ -632,16 +870,16 @@ CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind);
*
* @{
*/
-
+
/**
* \brief Map a source location to the cursor that describes the entity at that
* location in the source code.
*
* clang_getCursor() maps an arbitrary source location within a translation
* unit down to the most specific cursor that describes the entity at that
- * location. For example, given an expression \c x + y, invoking
+ * location. For example, given an expression \c x + y, invoking
* clang_getCursor() with a source location pointing to "x" will return the
- * cursor for "x"; similarly for "y". If the cursor points anywhere between
+ * cursor for "x"; similarly for "y". If the cursor points anywhere between
* "x" or "y" (e.g., on the + or the whitespace around it), clang_getCursor()
* will return a cursor referring to the "+" expression.
*
@@ -649,15 +887,15 @@ CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind);
* a NULL cursor if no such entity can be found.
*/
CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, CXSourceLocation);
-
+
/**
* \brief Retrieve the physical location of the source constructor referenced
* by the given cursor.
*
* The location of a declaration is typically the location of the name of that
- * declaration, where the name of that declaration would occur if it is
- * unnamed, or some keyword that introduces that particular declaration.
- * The location of a reference is where that reference occurs within the
+ * declaration, where the name of that declaration would occur if it is
+ * unnamed, or some keyword that introduces that particular declaration.
+ * The location of a reference is where that reference occurs within the
* source code.
*/
CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor);
@@ -668,7 +906,7 @@ CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor);
*
* The extent of a cursor starts with the file/line/column pointing at the
* first character within the source construct that the cursor refers to and
- * ends with the last character withinin that source construct. For a
+ * ends with the last character withinin that source construct. For a
* declaration, the extent covers the declaration itself. For a reference,
* the extent covers the location of the reference (e.g., where the referenced
* entity was actually used).
@@ -678,7 +916,7 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor);
/**
* @}
*/
-
+
/**
* \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors
*
@@ -687,7 +925,7 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor);
*
* @{
*/
-
+
/**
* \brief Describes how the traversal of the children of a particular
* cursor should proceed after visiting a particular child cursor.
@@ -697,10 +935,10 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor);
*/
enum CXChildVisitResult {
/**
- * \brief Terminates the cursor traversal.
+ * \brief Terminates the cursor traversal.
*/
CXChildVisit_Break,
- /**
+ /**
* \brief Continues the cursor traversal with the next sibling of
* the cursor just visited, without visiting its children.
*/
@@ -724,8 +962,8 @@ enum CXChildVisitResult {
* The visitor should return one of the \c CXChildVisitResult values
* to direct clang_visitCursorChildren().
*/
-typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
- CXCursor parent,
+typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
+ CXCursor parent,
CXClientData client_data);
/**
@@ -737,10 +975,8 @@ typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
* \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if
* the visitor returns \c CXChildVisit_Break.
*
- * \param tu the translation unit into which the cursor refers.
- *
* \param parent the cursor whose child may be visited. All kinds of
- * cursors can be visited, including invalid visitors (which, by
+ * cursors can be visited, including invalid cursors (which, by
* definition, have no children).
*
* \param visitor the visitor function that will be invoked for each
@@ -752,25 +988,25 @@ typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
* \returns a non-zero value if the traversal was terminated
* prematurely by the visitor returning \c CXChildVisit_Break.
*/
-CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent,
+CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data);
-
+
/**
* @}
*/
-
+
/**
* \defgroup CINDEX_CURSOR_XREF Cross-referencing in the AST
*
- * These routines provide the ability to determine references within and
+ * These routines provide the ability to determine references within and
* across translation units, by providing the names of the entities referenced
* by cursors, follow reference cursors to the declarations they reference,
* and associate declarations with their definitions.
*
* @{
*/
-
+
/**
* \brief Retrieve a Unified Symbol Resolution (USR) for the entity referenced
* by the given cursor.
@@ -792,14 +1028,14 @@ CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor);
*
* Reference cursors refer to other entities in the AST. For example, an
* Objective-C superclass reference cursor refers to an Objective-C class.
- * This function produces the cursor for the Objective-C class from the
+ * This function produces the cursor for the Objective-C class from the
* cursor for the superclass reference. If the input cursor is a declaration or
* definition, it returns that declaration or definition unchanged.
- * Othewise, returns the NULL cursor.
+ * Otherwise, returns the NULL cursor.
*/
CINDEX_LINKAGE CXCursor clang_getCursorReferenced(CXCursor);
-/**
+/**
* \brief For a cursor that is either a reference to or a declaration
* of some entity, retrieve a cursor that describes the definition of
* that entity.
@@ -829,7 +1065,7 @@ CINDEX_LINKAGE CXCursor clang_getCursorReferenced(CXCursor);
*/
CINDEX_LINKAGE CXCursor clang_getCursorDefinition(CXCursor);
-/**
+/**
* \brief Determine whether the declaration pointed to by this cursor
* is also a definition of that entity.
*/
@@ -838,6 +1074,142 @@ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor);
/**
* @}
*/
+
+/**
+ * \defgroup CINDEX_LEX Token extraction and manipulation
+ *
+ * The routines in this group provide access to the tokens within a
+ * translation unit, along with a semantic mapping of those tokens to
+ * their corresponding cursors.
+ *
+ * @{
+ */
+
+/**
+ * \brief Describes a kind of token.
+ */
+typedef enum CXTokenKind {
+ /**
+ * \brief A token that contains some kind of punctuation.
+ */
+ CXToken_Punctuation,
+
+ /**
+ * \brief A language keyword.
+ */
+ CXToken_Keyword,
+
+ /**
+ * \brief An identifier (that is not a keyword).
+ */
+ CXToken_Identifier,
+
+ /**
+ * \brief A numeric, string, or character literal.
+ */
+ CXToken_Literal,
+
+ /**
+ * \brief A comment.
+ */
+ CXToken_Comment
+} CXTokenKind;
+
+/**
+ * \brief Describes a single preprocessing token.
+ */
+typedef struct {
+ unsigned int_data[4];
+ void *ptr_data;
+} CXToken;
+
+/**
+ * \brief Determine the kind of the given token.
+ */
+CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken);
+
+/**
+ * \brief Determine the spelling of the given token.
+ *
+ * The spelling of a token is the textual representation of that token, e.g.,
+ * the text of an identifier or keyword.
+ */
+CINDEX_LINKAGE CXString clang_getTokenSpelling(CXTranslationUnit, CXToken);
+
+/**
+ * \brief Retrieve the source location of the given token.
+ */
+CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit,
+ CXToken);
+
+/**
+ * \brief Retrieve a source range that covers the given token.
+ */
+CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken);
+
+/**
+ * \brief Tokenize the source code described by the given range into raw
+ * lexical tokens.
+ *
+ * \param TU the translation unit whose text is being tokenized.
+ *
+ * \param Range the source range in which text should be tokenized. All of the
+ * tokens produced by tokenization will fall within this source range,
+ *
+ * \param Tokens this pointer will be set to point to the array of tokens
+ * that occur within the given source range. The returned pointer must be
+ * freed with clang_disposeTokens() before the translation unit is destroyed.
+ *
+ * \param NumTokens will be set to the number of tokens in the \c *Tokens
+ * array.
+ *
+ */
+CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
+ CXToken **Tokens, unsigned *NumTokens);
+
+/**
+ * \brief Annotate the given set of tokens by providing cursors for each token
+ * that can be mapped to a specific entity within the abstract syntax tree.
+ *
+ * This token-annotation routine is equivalent to invoking
+ * clang_getCursor() for the source locations of each of the
+ * tokens. The cursors provided are filtered, so that only those
+ * cursors that have a direct correspondence to the token are
+ * accepted. For example, given a function call \c f(x),
+ * clang_getCursor() would provide the following cursors:
+ *
+ * * when the cursor is over the 'f', a DeclRefExpr cursor referring to 'f'.
+ * * when the cursor is over the '(' or the ')', a CallExpr referring to 'f'.
+ * * when the cursor is over the 'x', a DeclRefExpr cursor referring to 'x'.
+ *
+ * Only the first and last of these cursors will occur within the
+ * annotate, since the tokens "f" and "x' directly refer to a function
+ * and a variable, respectively, but the parentheses are just a small
+ * part of the full syntax of the function call expression, which is
+ * not provided as an annotation.
+ *
+ * \param TU the translation unit that owns the given tokens.
+ *
+ * \param Tokens the set of tokens to annotate.
+ *
+ * \param NumTokens the number of tokens in \p Tokens.
+ *
+ * \param Cursors an array of \p NumTokens cursors, whose contents will be
+ * replaced with the cursors corresponding to each token.
+ */
+CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens,
+ CXCursor *Cursors);
+
+/**
+ * \brief Free the given set of tokens.
+ */
+CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens);
+
+/**
+ * @}
+ */
/**
* \defgroup CINDEX_DEBUG Debugging facilities
@@ -847,11 +1219,11 @@ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor);
*
* @{
*/
-
+
/* for debug/testing */
-CINDEX_LINKAGE const char *clang_getCursorKindSpelling(enum CXCursorKind Kind);
-CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
- const char **startBuf,
+CINDEX_LINKAGE const char *clang_getCursorKindSpelling(enum CXCursorKind Kind);
+CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
+ const char **startBuf,
const char **endBuf,
unsigned *startLine,
unsigned *startColumn,
@@ -861,7 +1233,7 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
/**
* @}
*/
-
+
/**
* \defgroup CINDEX_CODE_COMPLET Code completion
*
@@ -873,7 +1245,7 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
*
* @{
*/
-
+
/**
* \brief A semantic string that describes a code-completion result.
*
@@ -885,18 +1257,18 @@ CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor,
* the name of the entity being referenced, whether the text chunk is part of
* the template, or whether it is a "placeholder" that the user should replace
* with actual code,of a specific kind. See \c CXCompletionChunkKind for a
- * description of the different kinds of chunks.
+ * description of the different kinds of chunks.
*/
typedef void *CXCompletionString;
-
+
/**
* \brief A single result of code completion.
*/
typedef struct {
/**
- * \brief The kind of entity that this completion refers to.
+ * \brief The kind of entity that this completion refers to.
*
- * The cursor kind will be a macro, keyword, or a declaration (one of the
+ * The cursor kind will be a macro, keyword, or a declaration (one of the
* *Decl cursor kinds), describing the entity that the completion is
* referring to.
*
@@ -904,8 +1276,8 @@ typedef struct {
* the client to extract additional information from declaration.
*/
enum CXCursorKind CursorKind;
-
- /**
+
+ /**
* \brief The code-completion string that describes how to insert this
* code-completion result into the editing buffer.
*/
@@ -915,8 +1287,8 @@ typedef struct {
/**
* \brief Describes a single piece of text within a code-completion string.
*
- * Each "chunk" within a code-completion string (\c CXCompletionString) is
- * either a piece of text with a specific "kind" that describes how that text
+ * Each "chunk" within a code-completion string (\c CXCompletionString) is
+ * either a piece of text with a specific "kind" that describes how that text
* should be interpreted by the client or is another completion string.
*/
enum CXCompletionChunkKind {
@@ -925,7 +1297,7 @@ enum CXCompletionChunkKind {
* could be a part of the template (but is not required).
*
* The Optional chunk is the only kind of chunk that has a code-completion
- * string for its representation, which is accessible via
+ * string for its representation, which is accessible via
* \c clang_getCompletionChunkCompletionString(). The code-completion string
* describes an additional part of the template that is completely optional.
* For example, optional chunks can be used to describe the placeholders for
@@ -956,10 +1328,10 @@ enum CXCompletionChunkKind {
CXCompletionChunk_Optional,
/**
* \brief Text that a user would be expected to type to get this
- * code-completion result.
+ * code-completion result.
*
- * There will be exactly one "typed text" chunk in a semantic string, which
- * will typically provide the spelling of a keyword or the name of a
+ * There will be exactly one "typed text" chunk in a semantic string, which
+ * will typically provide the spelling of a keyword or the name of a
* declaration that could be used at the current code point. Clients are
* expected to filter the code-completion results based on the text in this
* chunk.
@@ -987,7 +1359,7 @@ enum CXCompletionChunkKind {
/**
* \brief Informative text that should be displayed but never inserted as
* part of the template.
- *
+ *
* An "informative" chunk contains annotations that can be displayed to
* help the user decide whether a particular code-completion result is the
* right option, but which is not part of the actual template to be inserted
@@ -1010,7 +1382,7 @@ enum CXCompletionChunkKind {
* "(", the code-completion string will contain a "current parameter" chunk
* for "int x", indicating that the current argument will initialize that
* parameter. After typing further, to \c add(17, (where the code-completion
- * point is after the ","), the code-completion string will contain a
+ * point is after the ","), the code-completion string will contain a
* "current paremeter" chunk to "int y".
*/
CXCompletionChunk_CurrentParameter,
@@ -1053,10 +1425,10 @@ enum CXCompletionChunkKind {
*/
CXCompletionChunk_Comma,
/**
- * \brief Text that specifies the result type of a given result.
+ * \brief Text that specifies the result type of a given result.
*
* This special kind of informative chunk is not meant to be inserted into
- * the text buffer. Rather, it is meant to illustrate the type that an
+ * the text buffer. Rather, it is meant to illustrate the type that an
* expression using the given completion string would have.
*/
CXCompletionChunk_ResultType,
@@ -1082,7 +1454,7 @@ enum CXCompletionChunkKind {
*/
CXCompletionChunk_VerticalSpace
};
-
+
/**
* \brief Determine the kind of a particular chunk within a completion string.
*
@@ -1092,12 +1464,12 @@ enum CXCompletionChunkKind {
*
* \returns the kind of the chunk at the index \c chunk_number.
*/
-CINDEX_LINKAGE enum CXCompletionChunkKind
+CINDEX_LINKAGE enum CXCompletionChunkKind
clang_getCompletionChunkKind(CXCompletionString completion_string,
unsigned chunk_number);
-
+
/**
- * \brief Retrieve the text associated with a particular chunk within a
+ * \brief Retrieve the text associated with a particular chunk within a
* completion string.
*
* \param completion_string the completion string to query.
@@ -1111,7 +1483,7 @@ clang_getCompletionChunkText(CXCompletionString completion_string,
unsigned chunk_number);
/**
- * \brief Retrieve the completion string associated with a particular chunk
+ * \brief Retrieve the completion string associated with a particular chunk
* within a completion string.
*
* \param completion_string the completion string to query.
@@ -1125,7 +1497,7 @@ clang_getCompletionChunkText(CXCompletionString completion_string,
CINDEX_LINKAGE CXCompletionString
clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
unsigned chunk_number);
-
+
/**
* \brief Retrieve the number of chunks in the given code-completion string.
*/
@@ -1136,7 +1508,7 @@ clang_getNumCompletionChunks(CXCompletionString completion_string);
* \brief Contains the results of code-completion.
*
* This data structure contains the results of code completion, as
- * produced by \c clang_codeComplete. Its contents must be freed by
+ * produced by \c clang_codeComplete. Its contents must be freed by
* \c clang_disposeCodeCompleteResults.
*/
typedef struct {
@@ -1162,12 +1534,12 @@ typedef struct {
* performing syntax checking up to the location where code-completion has
* been requested. At that point, a special code-completion token is passed
* to the parser, which recognizes this token and determines, based on the
- * current location in the C/Objective-C/C++ grammar and the state of
+ * current location in the C/Objective-C/C++ grammar and the state of
* semantic analysis, what completions to provide. These completions are
* returned via a new \c CXCodeCompleteResults structure.
*
* Code completion itself is meant to be triggered by the client when the
- * user types punctuation characters or whitespace, at which point the
+ * user types punctuation characters or whitespace, at which point the
* code-completion location will coincide with the cursor. For example, if \c p
* is a pointer, code-completion might be triggered after the "-" and then
* after the ">" in \c p->. When the code-completion location is afer the ">",
@@ -1196,9 +1568,9 @@ typedef struct {
* \p command_line_args.
*
* \param command_line_args the command-line arguments to pass to the Clang
- * compiler to build the given source file. This should include all of the
+ * compiler to build the given source file. This should include all of the
* necessary include paths, language-dialect switches, precompiled header
- * includes, etc., but should not include any information specific to
+ * includes, etc., but should not include any information specific to
* code completion.
*
* \param num_unsaved_files the number of unsaved file entries in \p
@@ -1210,59 +1582,104 @@ typedef struct {
*
* \param complete_filename the name of the source file where code completion
* should be performed. In many cases, this name will be the same as the
- * source filename. However, the completion filename may also be a file
- * included by the source file, which is required when producing
+ * source filename. However, the completion filename may also be a file
+ * included by the source file, which is required when producing
* code-completion results for a header.
*
* \param complete_line the line at which code-completion should occur.
*
- * \param complete_column the column at which code-completion should occur.
+ * \param complete_column the column at which code-completion should occur.
* Note that the column should point just after the syntactic construct that
* initiated code completion, and not in the middle of a lexical token.
*
+ * \param diag_callback callback function that will receive any diagnostics
+ * emitted while processing this source file. If NULL, diagnostics will be
+ * suppressed.
+ *
+ * \param diag_client_data client data that will be passed to the diagnostic
+ * callback function.
+ *
* \returns if successful, a new CXCodeCompleteResults structure
* containing code-completion results, which should eventually be
* freed with \c clang_disposeCodeCompleteResults(). If code
* completion fails, returns NULL.
*/
-CINDEX_LINKAGE
-CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
+CINDEX_LINKAGE
+CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
const char *source_filename,
- int num_command_line_args,
+ int num_command_line_args,
const char **command_line_args,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files,
const char *complete_filename,
unsigned complete_line,
- unsigned complete_column);
-
+ unsigned complete_column,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data);
+
/**
* \brief Free the given set of code-completion results.
*/
-CINDEX_LINKAGE
+CINDEX_LINKAGE
void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results);
-
+
/**
* @}
*/
-
-
+
+
/**
* \defgroup CINDEX_MISC Miscellaneous utility functions
*
* @{
*/
-
-CINDEX_LINKAGE const char *clang_getClangVersion();
+
+/**
+ * \brief Return a version string, suitable for showing to a user, but not
+ * intended to be parsed (the format is not guaranteed to be stable).
+ */
+CINDEX_LINKAGE CXString clang_getClangVersion();
+
+/**
+ * \brief Return a version string, suitable for showing to a user, but not
+ * intended to be parsed (the format is not guaranteed to be stable).
+ */
+
+
+ /**
+ * \brief Visitor invoked for each file in a translation unit
+ * (used with clang_getInclusions()).
+ *
+ * This visitor function will be invoked by clang_getInclusions() for each
+ * file included (either at the top-level or by #include directives) within
+ * a translation unit. The first argument is the file being included, and
+ * the second and third arguments provide the inclusion stack. The
+ * array is sorted in order of immediate inclusion. For example,
+ * the first element refers to the location that included 'included_file'.
+ */
+typedef void (*CXInclusionVisitor)(CXFile included_file,
+ CXSourceLocation* inclusion_stack,
+ unsigned include_len,
+ CXClientData client_data);
+
+/**
+ * \brief Visit the set of preprocessor inclusions in a translation unit.
+ * The visitor function is called with the provided data for every included
+ * file. This does not include headers included by the PCH file (unless one
+ * is inspecting the inclusions in the PCH file itself).
+ */
+CINDEX_LINKAGE void clang_getInclusions(CXTranslationUnit tu,
+ CXInclusionVisitor visitor,
+ CXClientData client_data);
/**
* @}
*/
-
+
/**
* @}
*/
-
+
#ifdef __cplusplus
}
#endif
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index e5429bec143c..2ed9fd708018 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -27,6 +27,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Allocator.h"
#include <vector>
@@ -46,6 +47,7 @@ namespace clang {
class SourceManager;
class TargetInfo;
// Decls
+ class DeclContext;
class CXXMethodDecl;
class CXXRecordDecl;
class Decl;
@@ -502,7 +504,8 @@ public:
/// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type.
- QualType getVectorType(QualType VectorType, unsigned NumElts);
+ QualType getVectorType(QualType VectorType, unsigned NumElts,
+ bool AltiVec, bool IsPixel);
/// getExtVectorType - Return the unique reference to an extended vector type
/// of the specified element type and size. VectorType must be a built-in
@@ -534,11 +537,11 @@ public:
/// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration.
- QualType getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl=0);
+ QualType getTypeDeclType(const TypeDecl *Decl, const TypeDecl* PrevDecl=0);
/// getTypedefType - Return the unique reference to the type for the
/// specified typename decl.
- QualType getTypedefType(TypedefDecl *Decl);
+ QualType getTypedefType(const TypedefDecl *Decl);
QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced,
QualType Replacement);
@@ -835,13 +838,23 @@ public:
return getTypeInfo(T).second;
}
+ /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
+ /// characters. This method does not work on incomplete types.
+ CharUnits getTypeAlignInChars(QualType T);
+ CharUnits getTypeAlignInChars(const Type *T);
+
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
/// type for the current target in bits. This can be different than the ABI
/// alignment in cases where it is beneficial for performance to overalign
/// a data type.
unsigned getPreferredTypeAlign(const Type *T);
- unsigned getDeclAlignInBytes(const Decl *D, bool RefAsPointee = false);
+ /// getDeclAlign - Return a conservative estimate of the alignment of
+ /// the specified decl. Note that bitfields do not have a valid alignment, so
+ /// this method will assert on them.
+ /// If @p RefAsPointee, references are treated like their underlying type
+ /// (for alignof), else they're treated like pointers (for CodeGen).
+ CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false);
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
@@ -878,7 +891,7 @@ public:
unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI);
unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD);
void CollectInheritedProtocols(const Decl *CDecl,
- llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols);
+ llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
//===--------------------------------------------------------------------===//
// Type Operators
@@ -960,6 +973,20 @@ public:
NestedNameSpecifier *
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS);
+ /// \brief Retrieves the canonical representation of the given
+ /// calling convention.
+ CallingConv getCanonicalCallConv(CallingConv CC) {
+ if (CC == CC_C)
+ return CC_Default;
+ return CC;
+ }
+
+ /// \brief Determines whether two calling conventions name the same
+ /// calling convention.
+ bool isSameCallConv(CallingConv lcc, CallingConv rcc) {
+ return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc));
+ }
+
/// \brief Retrieves the "canonical" template name that refers to a
/// given template.
///
@@ -1187,6 +1214,15 @@ private:
const ASTRecordLayout &getObjCLayout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl);
+
+private:
+ // FIXME: This currently contains the set of StoredDeclMaps used
+ // by DeclContext objects. This probably should not be in ASTContext,
+ // but we include it here so that ASTContext can quickly deallocate them.
+ std::vector<void*> SDMs;
+ friend class DeclContext;
+ void *CreateStoredDeclsMap();
+ void ReleaseDeclContextMaps();
};
/// @brief Utility function for constructing a nullary selector.
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index abd36f7e5f0f..2d314913469e 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -1,4 +1,4 @@
-//===--- DiagnosticAST.h - Diagnostics for the AST library ------*- C++ -*-===//
+//===--- ASTDiagnostic.h - Diagnostics for the AST library ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -22,6 +22,26 @@ namespace clang {
NUM_BUILTIN_AST_DIAGNOSTICS
};
} // end namespace diag
+
+ /// \brief Diagnostic argument formatting function for diagnostics that
+ /// involve AST nodes.
+ ///
+ /// This function formats diagnostic arguments for various AST nodes,
+ /// including types, declaration names, nested name specifiers, and
+ /// declaration contexts, into strings that can be printed as part of
+ /// diagnostics. It is meant to be used as the argument to
+ /// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext
+ /// pointer.
+ void FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
+ intptr_t Val,
+ const char *Modifier,
+ unsigned ModLen,
+ const char *Argument,
+ unsigned ArgLen,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie);
} // end namespace clang
#endif
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
new file mode 100644
index 000000000000..f5f11ca83662
--- /dev/null
+++ b/include/clang/AST/ASTImporter.h
@@ -0,0 +1,234 @@
+//===--- ASTImporter.h - Importing ASTs from other Contexts -----*- 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 ASTImporter class which imports AST nodes from one
+// context into another context.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_ASTIMPORTER_H
+#define LLVM_CLANG_AST_ASTIMPORTER_H
+
+#include "clang/AST/Type.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class ASTContext;
+ class Decl;
+ class DeclContext;
+ class Diagnostic;
+ class Expr;
+ class FileManager;
+ class IdentifierInfo;
+ class NestedNameSpecifier;
+ class Stmt;
+ class TypeSourceInfo;
+
+ /// \brief Imports selected nodes from one AST context into another context,
+ /// merging AST nodes where appropriate.
+ class ASTImporter {
+ public:
+ typedef llvm::DenseSet<std::pair<Decl *, Decl *> > NonEquivalentDeclSet;
+
+ private:
+ /// \brief The contexts we're importing to and from.
+ ASTContext &ToContext, &FromContext;
+
+ /// \brief The file managers we're importing to and from.
+ FileManager &ToFileManager, &FromFileManager;
+
+ /// \brief The diagnostics object that we should use to emit diagnostics.
+ Diagnostic &Diags;
+
+ /// \brief Mapping from the already-imported types in the "from" context
+ /// to the corresponding types in the "to" context.
+ llvm::DenseMap<Type *, Type *> ImportedTypes;
+
+ /// \brief Mapping from the already-imported declarations in the "from"
+ /// context to the corresponding declarations in the "to" context.
+ llvm::DenseMap<Decl *, Decl *> ImportedDecls;
+
+ /// \brief Mapping from the already-imported statements in the "from"
+ /// context to the corresponding statements in the "to" context.
+ llvm::DenseMap<Stmt *, Stmt *> ImportedStmts;
+
+ /// \brief Mapping from the already-imported FileIDs in the "from" source
+ /// manager to the corresponding FileIDs in the "to" source manager.
+ llvm::DenseMap<unsigned, FileID> ImportedFileIDs;
+
+ /// \brief Imported, anonymous tag declarations that are missing their
+ /// corresponding typedefs.
+ llvm::SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
+
+ /// \brief Declaration (from, to) pairs that are known not to be equivalent
+ /// (which we have already complained about).
+ NonEquivalentDeclSet NonEquivalentDecls;
+
+ public:
+ ASTImporter(Diagnostic &Diags,
+ ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager);
+
+ virtual ~ASTImporter();
+
+ /// \brief Import the given type from the "from" context into the "to"
+ /// context.
+ ///
+ /// \returns the equivalent type in the "to" context, or a NULL type if
+ /// an error occurred.
+ QualType Import(QualType FromT);
+
+ /// \brief Import the given type source information from the
+ /// "from" context into the "to" context.
+ ///
+ /// \returns the equivalent type source information in the "to"
+ /// context, or NULL if an error occurred.
+ TypeSourceInfo *Import(TypeSourceInfo *FromTSI);
+
+ /// \brief Import the given declaration from the "from" context into the
+ /// "to" context.
+ ///
+ /// \returns the equivalent declaration in the "to" context, or a NULL type
+ /// if an error occurred.
+ Decl *Import(Decl *FromD);
+
+ /// \brief Import the given declaration context from the "from"
+ /// AST context into the "to" AST context.
+ ///
+ /// \returns the equivalent declaration context in the "to"
+ /// context, or a NULL type if an error occurred.
+ DeclContext *ImportContext(DeclContext *FromDC);
+
+ /// \brief Import the given expression from the "from" context into the
+ /// "to" context.
+ ///
+ /// \returns the equivalent expression in the "to" context, or NULL if
+ /// an error occurred.
+ Expr *Import(Expr *FromE);
+
+ /// \brief Import the given statement from the "from" context into the
+ /// "to" context.
+ ///
+ /// \returns the equivalent statement in the "to" context, or NULL if
+ /// an error occurred.
+ Stmt *Import(Stmt *FromS);
+
+ /// \brief Import the given nested-name-specifier from the "from"
+ /// context into the "to" context.
+ ///
+ /// \returns the equivalent nested-name-specifier in the "to"
+ /// context, or NULL if an error occurred.
+ NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS);
+
+ /// \brief Import the given source location from the "from" context into
+ /// the "to" context.
+ ///
+ /// \returns the equivalent source location in the "to" context, or an
+ /// invalid source location if an error occurred.
+ SourceLocation Import(SourceLocation FromLoc);
+
+ /// \brief Import the given source range from the "from" context into
+ /// the "to" context.
+ ///
+ /// \returns the equivalent source range in the "to" context, or an
+ /// invalid source location if an error occurred.
+ SourceRange Import(SourceRange FromRange);
+
+ /// \brief Import the given declaration name from the "from"
+ /// context into the "to" context.
+ ///
+ /// \returns the equivalent declaration name in the "to" context,
+ /// or an empty declaration name if an error occurred.
+ DeclarationName Import(DeclarationName FromName);
+
+ /// \brief Import the given identifier from the "from" context
+ /// into the "to" context.
+ ///
+ /// \returns the equivalent identifier in the "to" context.
+ IdentifierInfo *Import(IdentifierInfo *FromId);
+
+ /// \brief Import the given file ID from the "from" context into the
+ /// "to" context.
+ ///
+ /// \returns the equivalent file ID in the source manager of the "to"
+ /// context.
+ FileID Import(FileID);
+
+ /// \brief Cope with a name conflict when importing a declaration into the
+ /// given context.
+ ///
+ /// This routine is invoked whenever there is a name conflict while
+ /// importing a declaration. The returned name will become the name of the
+ /// imported declaration. By default, the returned name is the same as the
+ /// original name, leaving the conflict unresolve such that name lookup
+ /// for this name is likely to find an ambiguity later.
+ ///
+ /// Subclasses may override this routine to resolve the conflict, e.g., by
+ /// renaming the declaration being imported.
+ ///
+ /// \param Name the name of the declaration being imported, which conflicts
+ /// with other declarations.
+ ///
+ /// \param DC the declaration context (in the "to" AST context) in which
+ /// the name is being imported.
+ ///
+ /// \param IDNS the identifier namespace in which the name will be found.
+ ///
+ /// \param Decls the set of declarations with the same name as the
+ /// declaration being imported.
+ ///
+ /// \param NumDecls the number of conflicting declarations in \p Decls.
+ ///
+ /// \returns the name that the newly-imported declaration should have.
+ virtual DeclarationName HandleNameConflict(DeclarationName Name,
+ DeclContext *DC,
+ unsigned IDNS,
+ NamedDecl **Decls,
+ unsigned NumDecls);
+
+ /// \brief Retrieve the context that AST nodes are being imported into.
+ ASTContext &getToContext() const { return ToContext; }
+
+ /// \brief Retrieve the context that AST nodes are being imported from.
+ ASTContext &getFromContext() const { return FromContext; }
+
+ /// \brief Retrieve the file manager that AST nodes are being imported into.
+ FileManager &getToFileManager() const { return ToFileManager; }
+
+ /// \brief Retrieve the file manager that AST nodes are being imported from.
+ FileManager &getFromFileManager() const { return FromFileManager; }
+
+ /// \brief Retrieve the diagnostic formatter.
+ Diagnostic &getDiags() const { return Diags; }
+
+ /// \brief Report a diagnostic in the "to" context.
+ DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID);
+
+ /// \brief Report a diagnostic in the "from" context.
+ DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID);
+
+ /// \brief Return the set of declarations that we know are not equivalent.
+ NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; }
+
+ /// \brief Note that we have imported the "from" declaration by mapping it
+ /// to the (potentially-newly-created) "to" declaration.
+ ///
+ /// \returns \p To
+ Decl *Imported(Decl *From, Decl *To);
+
+ /// \brief Determine whether the given types are structurally
+ /// equivalent.
+ bool IsStructurallyEquivalent(QualType From, QualType To);
+ };
+}
+
+#endif // LLVM_CLANG_AST_ASTIMPORTER_H
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 03ab0f07020b..37225907c6de 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -18,7 +18,6 @@
#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <cstring>
-#include <string>
#include <algorithm>
using llvm::dyn_cast;
@@ -96,7 +95,8 @@ public:
FIRST_TARGET_ATTRIBUTE,
DLLExport,
DLLImport,
- MSP430Interrupt
+ MSP430Interrupt,
+ X86ForceAlignArgPointer
};
private:
@@ -119,8 +119,7 @@ protected:
assert(Next == 0 && "Destroy didn't work");
}
public:
-
- void Destroy(ASTContext &C);
+ virtual void Destroy(ASTContext &C);
/// \brief Whether this attribute should be merged to new
/// declarations.
@@ -156,6 +155,18 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *) { return true; }
};
+
+class AttrWithString : public Attr {
+private:
+ const char *Str;
+ unsigned StrLen;
+protected:
+ AttrWithString(Attr::Kind AK, ASTContext &C, llvm::StringRef s);
+ llvm::StringRef getString() const { return llvm::StringRef(Str, StrLen); }
+ void ReplaceString(ASTContext &C, llvm::StringRef newS);
+public:
+ virtual void Destroy(ASTContext &C);
+};
#define DEF_SIMPLE_ATTR(ATTR) \
class ATTR##Attr : public Attr { \
@@ -213,12 +224,12 @@ public:
static bool classof(const AlignedAttr *A) { return true; }
};
-class AnnotateAttr : public Attr {
- std::string Annotation;
+class AnnotateAttr : public AttrWithString {
public:
- AnnotateAttr(llvm::StringRef ann) : Attr(Annotate), Annotation(ann) {}
+ AnnotateAttr(ASTContext &C, llvm::StringRef ann)
+ : AttrWithString(Annotate, C, ann) {}
- const std::string& getAnnotation() const { return Annotation; }
+ llvm::StringRef getAnnotation() const { return getString(); }
virtual Attr* clone(ASTContext &C) const;
@@ -229,12 +240,12 @@ public:
static bool classof(const AnnotateAttr *A) { return true; }
};
-class AsmLabelAttr : public Attr {
- std::string Label;
+class AsmLabelAttr : public AttrWithString {
public:
- AsmLabelAttr(llvm::StringRef L) : Attr(AsmLabel), Label(L) {}
+ AsmLabelAttr(ASTContext &C, llvm::StringRef L)
+ : AttrWithString(AsmLabel, C, L) {}
- const std::string& getLabel() const { return Label; }
+ llvm::StringRef getLabel() const { return getString(); }
virtual Attr* clone(ASTContext &C) const;
@@ -247,12 +258,12 @@ public:
DEF_SIMPLE_ATTR(AlwaysInline);
-class AliasAttr : public Attr {
- std::string Aliasee;
+class AliasAttr : public AttrWithString {
public:
- AliasAttr(llvm::StringRef aliasee) : Attr(Alias), Aliasee(aliasee) {}
+ AliasAttr(ASTContext &C, llvm::StringRef aliasee)
+ : AttrWithString(Alias, C, aliasee) {}
- const std::string& getAliasee() const { return Aliasee; }
+ llvm::StringRef getAliasee() const { return getString(); }
virtual Attr *clone(ASTContext &C) const;
@@ -321,12 +332,12 @@ DEF_SIMPLE_ATTR(AnalyzerNoReturn);
DEF_SIMPLE_ATTR(Deprecated);
DEF_SIMPLE_ATTR(Final);
-class SectionAttr : public Attr {
- std::string Name;
+class SectionAttr : public AttrWithString {
public:
- SectionAttr(llvm::StringRef N) : Attr(Section), Name(N) {}
+ SectionAttr(ASTContext &C, llvm::StringRef N)
+ : AttrWithString(Section, C, N) {}
- const std::string& getName() const { return Name; }
+ llvm::StringRef getName() const { return getString(); }
virtual Attr *clone(ASTContext &C) const;
@@ -350,19 +361,9 @@ class NonNullAttr : public Attr {
unsigned* ArgNums;
unsigned Size;
public:
- NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull),
- ArgNums(0), Size(0) {
-
- if (size == 0) return;
- assert(arg_nums);
- ArgNums = new unsigned[size];
- Size = size;
- memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
- }
+ NonNullAttr(ASTContext &C, unsigned* arg_nums = 0, unsigned size = 0);
- virtual ~NonNullAttr() {
- delete [] ArgNums;
- }
+ virtual void Destroy(ASTContext &C);
typedef const unsigned *iterator;
iterator begin() const { return ArgNums; }
@@ -379,15 +380,14 @@ public:
static bool classof(const NonNullAttr *A) { return true; }
};
-class FormatAttr : public Attr {
- std::string Type;
+class FormatAttr : public AttrWithString {
int formatIdx, firstArg;
public:
- FormatAttr(llvm::StringRef type, int idx, int first) : Attr(Format),
- Type(type), formatIdx(idx), firstArg(first) {}
+ FormatAttr(ASTContext &C, llvm::StringRef type, int idx, int first)
+ : AttrWithString(Format, C, type), formatIdx(idx), firstArg(first) {}
- const std::string& getType() const { return Type; }
- void setType(llvm::StringRef type) { Type = type; }
+ llvm::StringRef getType() const { return getString(); }
+ void setType(ASTContext &C, llvm::StringRef type);
int getFormatIdx() const { return formatIdx; }
int getFirstArg() const { return firstArg; }
@@ -570,6 +570,8 @@ public:
static bool classof(const MSP430InterruptAttr *A) { return true; }
};
+DEF_SIMPLE_ATTR(X86ForceAlignArgPointer);
+
#undef DEF_SIMPLE_ATTR
} // end namespace clang
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index 1491b1edbbac..79a3022ee014 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -161,7 +161,8 @@ class CXXBasePaths {
void ComputeDeclsFound();
public:
- typedef std::list<CXXBasePath>::const_iterator paths_iterator;
+ typedef std::list<CXXBasePath>::iterator paths_iterator;
+ typedef std::list<CXXBasePath>::const_iterator const_paths_iterator;
typedef NamedDecl **decl_iterator;
/// BasePaths - Construct a new BasePaths structure to record the
@@ -175,8 +176,10 @@ public:
~CXXBasePaths() { delete [] DeclsFound; }
- paths_iterator begin() const { return Paths.begin(); }
- paths_iterator end() const { return Paths.end(); }
+ paths_iterator begin() { return Paths.begin(); }
+ paths_iterator end() { return Paths.end(); }
+ const_paths_iterator begin() const { return Paths.begin(); }
+ const_paths_iterator end() const { return Paths.end(); }
CXXBasePath& front() { return Paths.front(); }
const CXXBasePath& front() const { return Paths.front(); }
@@ -206,7 +209,7 @@ public:
const RecordType* getDetectedVirtual() const {
return DetectedVirtual;
}
-
+
/// \brief Retrieve the type from which this base-paths search
/// began
CXXRecordDecl *getOrigin() const { return Origin; }
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 6d52b2b2bc91..07442896dc4b 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -19,6 +19,7 @@
#include "clang/AST/Redeclarable.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/Linkage.h"
namespace clang {
class CXXTemporary;
@@ -75,8 +76,9 @@ public:
static TranslationUnitDecl *Create(ASTContext &C);
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TranslationUnitDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == TranslationUnit; }
static DeclContext *castToDeclContext(const TranslationUnitDecl *D) {
return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D));
}
@@ -194,23 +196,6 @@ public:
return DC->isRecord();
}
- /// \brief Describes the different kinds of linkage
- /// (C++ [basic.link], C99 6.2.2) that an entity may have.
- enum Linkage {
- /// \brief No linkage, which means that the entity is unique and
- /// can only be referred to from within its scope.
- NoLinkage = 0,
-
- /// \brief Internal linkage, which indicates that the entity can
- /// be referred to from within the translation unit (but not other
- /// translation units).
- InternalLinkage,
-
- /// \brief External linkage, which indicates that the entity can
- /// be referred to from other translation units.
- ExternalLinkage
- };
-
/// \brief Determine what kind of linkage this entity has.
Linkage getLinkage() const;
@@ -221,10 +206,9 @@ public:
return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
}
- static bool classof(const Decl *D) {
- return D->getKind() >= NamedFirst && D->getKind() <= NamedLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamedDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K >= NamedFirst && K <= NamedLast; }
};
/// NamespaceDecl - Represent a C++ namespace.
@@ -301,8 +285,9 @@ public:
void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == Namespace; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamespaceDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Namespace; }
static DeclContext *castToDeclContext(const NamespaceDecl *D) {
return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D));
}
@@ -326,10 +311,9 @@ public:
void setType(QualType newType) { DeclType = newType; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= ValueFirst && D->getKind() <= ValueLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ValueDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K >= ValueFirst && K <= ValueLast; }
};
/// \brief Represents a ValueDecl that came out of a declarator.
@@ -349,10 +333,11 @@ public:
SourceLocation getTypeSpecStartLoc() const;
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= DeclaratorFirst && D->getKind() <= DeclaratorLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const DeclaratorDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= DeclaratorFirst && K <= DeclaratorLast;
+ }
};
/// \brief Structure used to store a statement, the constant value to
@@ -474,14 +459,142 @@ public:
SourceLocation L, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, StorageClass S);
- virtual ~VarDecl();
virtual void Destroy(ASTContext& C);
+ virtual ~VarDecl();
+
+ virtual SourceRange getSourceRange() const;
StorageClass getStorageClass() const { return (StorageClass)SClass; }
void setStorageClass(StorageClass SC) { SClass = SC; }
- virtual SourceRange getSourceRange() const;
+ void setThreadSpecified(bool T) { ThreadSpecified = T; }
+ bool isThreadSpecified() const {
+ return ThreadSpecified;
+ }
+
+ /// hasLocalStorage - Returns true if a variable with function scope
+ /// is a non-static local variable.
+ bool hasLocalStorage() const {
+ if (getStorageClass() == None)
+ return !isFileVarDecl();
+
+ // Return true for: Auto, Register.
+ // Return false for: Extern, Static, PrivateExtern.
+
+ return getStorageClass() <= Register;
+ }
+
+ /// hasExternStorage - Returns true if a variable has extern or
+ /// __private_extern__ storage.
+ bool hasExternalStorage() const {
+ return getStorageClass() == Extern || getStorageClass() == PrivateExtern;
+ }
+
+ /// hasGlobalStorage - Returns true for all variables that do not
+ /// have local storage. This includs all global variables as well
+ /// as static variables declared within a function.
+ bool hasGlobalStorage() const { return !hasLocalStorage(); }
+
+ /// \brief Determines whether this variable is a variable with
+ /// external, C linkage.
+ bool isExternC() const;
+
+ /// isBlockVarDecl - Returns true for local variable declarations. Note that
+ /// this includes static variables inside of functions.
+ ///
+ /// void foo() { int x; static int y; extern int z; }
+ ///
+ bool isBlockVarDecl() const {
+ if (getKind() != Decl::Var)
+ return false;
+ if (const DeclContext *DC = getDeclContext())
+ return DC->getLookupContext()->isFunctionOrMethod();
+ return false;
+ }
+
+ /// \brief Determines whether this is a static data member.
+ ///
+ /// This will only be true in C++, and applies to, e.g., the
+ /// variable 'x' in:
+ /// \code
+ /// struct S {
+ /// static int x;
+ /// };
+ /// \endcode
+ bool isStaticDataMember() const {
+ // If it wasn't static, it would be a FieldDecl.
+ return getDeclContext()->isRecord();
+ }
+
+ virtual VarDecl *getCanonicalDecl();
+ const VarDecl *getCanonicalDecl() const {
+ return const_cast<VarDecl*>(this)->getCanonicalDecl();
+ }
+
+ enum DefinitionKind {
+ DeclarationOnly, ///< This declaration is only a declaration.
+ TentativeDefinition, ///< This declaration is a tentative definition.
+ Definition ///< This declaration is definitely a definition.
+ };
+
+ /// \brief Check whether this declaration is a definition. If this could be
+ /// a tentative definition (in C), don't check whether there's an overriding
+ /// definition.
+ DefinitionKind isThisDeclarationADefinition() const;
+
+ /// \brief Get the tentative definition that acts as the real definition in
+ /// a TU. Returns null if there is a proper definition available.
+ VarDecl *getActingDefinition();
+ const VarDecl *getActingDefinition() const {
+ return const_cast<VarDecl*>(this)->getActingDefinition();
+ }
+
+ /// \brief Determine whether this is a tentative definition of a
+ /// variable in C.
+ bool isTentativeDefinitionNow() const;
+
+ /// \brief Get the real (not just tentative) definition for this declaration.
+ VarDecl *getDefinition();
+ const VarDecl *getDefinition() const {
+ return const_cast<VarDecl*>(this)->getDefinition();
+ }
+
+ /// \brief Determine whether this is or was instantiated from an out-of-line
+ /// definition of a static data member.
+ bool isOutOfLine() const;
+
+ /// \brief If this is a static data member, find its out-of-line definition.
+ VarDecl *getOutOfLineDefinition();
+
+ /// isFileVarDecl - Returns true for file scoped variable declaration.
+ bool isFileVarDecl() const {
+ if (getKind() != Decl::Var)
+ return false;
+ if (const DeclContext *Ctx = getDeclContext()) {
+ Ctx = Ctx->getLookupContext();
+ if (isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx) )
+ return true;
+ }
+ if (isStaticDataMember())
+ return true;
+
+ return false;
+ }
+
+ /// getAnyInitializer - Get the initializer for this variable, no matter which
+ /// declaration it is attached to.
+ const Expr *getAnyInitializer() const {
+ const VarDecl *D;
+ return getAnyInitializer(D);
+ }
+ /// getAnyInitializer - Get the initializer for this variable, no matter which
+ /// declaration it is attached to. Also get that declaration.
+ const Expr *getAnyInitializer(const VarDecl *&D) const;
+
+ bool hasInit() const {
+ return !Init.isNull();
+ }
const Expr *getInit() const {
if (Init.isNull())
return 0;
@@ -521,7 +634,7 @@ public:
return StmtPtr;
}
- void setInit(ASTContext &C, Expr *I);
+ void setInit(Expr *I);
EvaluatedStmt *EnsureEvaluatedStmt() const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
@@ -614,17 +727,6 @@ public:
Eval->IsICE = IsICE;
}
- /// \brief Retrieve the definition of this variable, which may come
- /// from a previous declaration. Def will be set to the VarDecl that
- /// contains the initializer, and the result will be that
- /// initializer.
- const Expr *getDefinition(const VarDecl *&Def) const;
-
- void setThreadSpecified(bool T) { ThreadSpecified = T; }
- bool isThreadSpecified() const {
- return ThreadSpecified;
- }
-
void setCXXDirectInitializer(bool T) { HasCXXDirectInit = T; }
/// hasCXXDirectInitializer - If true, the initializer was a direct
@@ -648,67 +750,6 @@ public:
void setDeclaredInCondition(bool InCondition) {
DeclaredInCondition = InCondition;
}
-
- virtual VarDecl *getCanonicalDecl();
- const VarDecl *getCanonicalDecl() const {
- return const_cast<VarDecl*>(this)->getCanonicalDecl();
- }
-
- /// hasLocalStorage - Returns true if a variable with function scope
- /// is a non-static local variable.
- bool hasLocalStorage() const {
- if (getStorageClass() == None)
- return !isFileVarDecl();
-
- // Return true for: Auto, Register.
- // Return false for: Extern, Static, PrivateExtern.
-
- return getStorageClass() <= Register;
- }
-
- /// hasExternStorage - Returns true if a variable has extern or
- /// __private_extern__ storage.
- bool hasExternalStorage() const {
- return getStorageClass() == Extern || getStorageClass() == PrivateExtern;
- }
-
- /// hasGlobalStorage - Returns true for all variables that do not
- /// have local storage. This includs all global variables as well
- /// as static variables declared within a function.
- bool hasGlobalStorage() const { return !hasLocalStorage(); }
-
- /// isBlockVarDecl - Returns true for local variable declarations. Note that
- /// this includes static variables inside of functions.
- ///
- /// void foo() { int x; static int y; extern int z; }
- ///
- bool isBlockVarDecl() const {
- if (getKind() != Decl::Var)
- return false;
- if (const DeclContext *DC = getDeclContext())
- return DC->getLookupContext()->isFunctionOrMethod();
- return false;
- }
-
- /// \brief Determines whether this is a static data member.
- ///
- /// This will only be true in C++, and applies to, e.g., the
- /// variable 'x' in:
- /// \code
- /// struct S {
- /// static int x;
- /// };
- /// \endcode
- bool isStaticDataMember() const {
- return getDeclContext()->isRecord();
- }
-
- /// \brief Determine whether this is or was instantiated from an out-of-line
- /// definition of a static data member.
- bool isOutOfLine() const;
-
- /// \brief If this is a static data member, find its out-of-line definition.
- VarDecl *getOutOfLineDefinition();
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
@@ -728,35 +769,11 @@ public:
/// data member of a class template, set the template specialiation kind.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation = SourceLocation());
-
- /// isFileVarDecl - Returns true for file scoped variable declaration.
- bool isFileVarDecl() const {
- if (getKind() != Decl::Var)
- return false;
- if (const DeclContext *Ctx = getDeclContext()) {
- Ctx = Ctx->getLookupContext();
- if (isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx) )
- return true;
- }
- if (isStaticDataMember())
- return true;
-
- return false;
- }
-
- /// \brief Determine whether this is a tentative definition of a
- /// variable in C.
- bool isTentativeDefinition(ASTContext &Context) const;
-
- /// \brief Determines whether this variable is a variable with
- /// external, C linkage.
- bool isExternC() const;
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= VarFirst && D->getKind() <= VarLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const VarDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K >= VarFirst && K <= VarLast; }
};
class ImplicitParamDecl : public VarDecl {
@@ -770,7 +787,8 @@ public:
QualType T);
// Implement isa/cast/dyncast/etc.
static bool classof(const ImplicitParamDecl *D) { return true; }
- static bool classof(const Decl *D) { return D->getKind() == ImplicitParam; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == ImplicitParam; }
};
/// ParmVarDecl - Represent a parameter to a function.
@@ -876,10 +894,9 @@ public:
void setOwningFunction(DeclContext *FD) { setDeclContext(FD); }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return (D->getKind() == ParmVar);
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ParmVarDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ParmVar; }
};
/// FunctionDecl - An instance of this class is created to represent a
@@ -1096,8 +1113,6 @@ public:
unsigned getBuiltinID() const;
- unsigned getNumParmVarDeclsFromType() const;
-
// Iterator access to formal parameters.
unsigned param_size() const { return getNumParams(); }
typedef ParmVarDecl **param_iterator;
@@ -1110,7 +1125,7 @@ public:
param_const_iterator param_end() const { return ParamInfo+param_size(); }
/// getNumParams - Return the number of parameters this function must have
- /// based on its functiontype. This is the length of the PararmInfo array
+ /// based on its FunctionType. This is the length of the ParamInfo array
/// after it has been created.
unsigned getNumParams() const;
@@ -1122,7 +1137,7 @@ public:
assert(i < getNumParams() && "Illegal param #");
return ParamInfo[i];
}
- void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams);
+ void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
/// getMinRequiredArguments - Returns the minimum number of arguments
/// needed to call this function. This may be fewer than the number of
@@ -1267,8 +1282,7 @@ public:
/// be inserted.
///
/// \param TSK the kind of template specialization this is.
- void setFunctionTemplateSpecialization(ASTContext &Context,
- FunctionTemplateDecl *Template,
+ void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK = TSK_ImplicitInstantiation);
@@ -1295,10 +1309,11 @@ public:
bool isOutOfLine() const;
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FunctionDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= FunctionFirst && K <= FunctionLast;
+ }
static DeclContext *castToDeclContext(const FunctionDecl *D) {
return static_cast<DeclContext *>(const_cast<FunctionDecl*>(D));
}
@@ -1347,11 +1362,20 @@ public:
Expr *getBitWidth() const { return BitWidth; }
void setBitWidth(Expr *BW) { BitWidth = BW; }
- // Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= FieldFirst && D->getKind() <= FieldLast;
+ /// getParent - Returns the parent of this field declaration, which
+ /// is the struct in which this method is defined.
+ const RecordDecl *getParent() const {
+ return cast<RecordDecl>(getDeclContext());
}
+
+ RecordDecl *getParent() {
+ return cast<RecordDecl>(getDeclContext());
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FieldDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K >= FieldFirst && K <= FieldLast; }
};
/// EnumConstantDecl - An instance of this object exists for each enum constant
@@ -1385,8 +1409,9 @@ public:
void setInitVal(const llvm::APSInt &V) { Val = V; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == EnumConstant; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumConstantDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == EnumConstant; }
friend class StmtIteratorBase;
};
@@ -1418,10 +1443,9 @@ public:
void setTypeForDecl(Type *TD) { TypeForDecl = TD; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= TypeFirst && D->getKind() <= TypeLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TypeDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K >= TypeFirst && K <= TypeLast; }
};
@@ -1460,8 +1484,9 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == Typedef; }
+ 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;
@@ -1486,6 +1511,11 @@ private:
/// it is a declaration ("struct foo;").
bool IsDefinition : 1;
+ /// IsEmbeddedInDeclarator - True if this tag declaration is
+ /// "embedded" (i.e., defined or declared for the very first time)
+ /// in the syntax of a declarator,
+ bool IsEmbeddedInDeclarator : 1;
+
/// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef,
/// this points to the TypedefDecl. Used for mangling.
TypedefDecl *TypedefForAnonDecl;
@@ -1502,6 +1532,7 @@ protected:
assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum");
TagDeclKind = TK;
IsDefinition = false;
+ IsEmbeddedInDeclarator = false;
setPreviousDeclaration(PrevDecl);
}
@@ -1535,6 +1566,13 @@ public:
return IsDefinition;
}
+ bool isEmbeddedInDeclarator() const {
+ return IsEmbeddedInDeclarator;
+ }
+ void setEmbeddedInDeclarator(bool isInDeclarator) {
+ IsEmbeddedInDeclarator = isInDeclarator;
+ }
+
/// \brief Whether this declaration declares a type that is
/// dependent, i.e., a type that somehow depends on template
/// parameters.
@@ -1557,7 +1595,9 @@ public:
/// specific TagDecl is defining declaration, not whether or not the
/// struct/union/class/enum type is defined. This method returns NULL if
/// there is no TagDecl that defines the struct/union/class/enum.
- TagDecl* getDefinition(ASTContext& C) const;
+ TagDecl* getDefinition() const;
+
+ void setDefinition(bool V) { IsDefinition = V; }
const char *getKindName() const {
return ElaboratedType::getNameForTagKind(getTagKind());
@@ -1583,10 +1623,9 @@ public:
void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= TagFirst && D->getKind() <= TagLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TagDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K >= TagFirst && K <= TagLast; }
static DeclContext *castToDeclContext(const TagDecl *D) {
return static_cast<DeclContext *>(const_cast<TagDecl*>(D));
@@ -1594,8 +1633,6 @@ public:
static TagDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<TagDecl *>(const_cast<DeclContext*>(DC));
}
-
- void setDefinition(bool V) { IsDefinition = V; }
};
/// EnumDecl - Represents an enum. As an extension, we allow forward-declared
@@ -1641,7 +1678,7 @@ public:
/// declaration as being defined; it's enumerators have already been
/// added (via DeclContext::addDecl). NewType is the new underlying
/// type of the enumeration type.
- void completeDefinition(ASTContext &C, QualType NewType,
+ void completeDefinition(QualType NewType,
QualType PromotionType);
// enumerator_iterator - Iterates through the enumerators of this
@@ -1679,8 +1716,9 @@ public:
void setInstantiationOfMemberEnum(EnumDecl *IF) { InstantiatedFrom = IF; }
- static bool classof(const Decl *D) { return D->getKind() == Enum; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Enum; }
};
@@ -1763,8 +1801,8 @@ public:
/// RecordDecl is defining declaration, not whether or not the record
/// type is defined. This method returns NULL if there is no RecordDecl
/// that defines the struct/union/tag.
- RecordDecl* getDefinition(ASTContext& C) const {
- return cast_or_null<RecordDecl>(TagDecl::getDefinition(C));
+ RecordDecl* getDefinition() const {
+ return cast_or_null<RecordDecl>(TagDecl::getDefinition());
}
// Iterator access to field members. The field iterator only visits
@@ -1787,12 +1825,13 @@ public:
/// completeDefinition - Notes that the definition of this type is
/// now complete.
- void completeDefinition(ASTContext& C);
+ void completeDefinition();
- static bool classof(const Decl *D) {
- return D->getKind() >= RecordFirst && D->getKind() <= RecordLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const RecordDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= RecordFirst && K <= RecordLast;
+ }
};
class FileScopeAsmDecl : public Decl {
@@ -1807,10 +1846,9 @@ public:
StringLiteral *getAsmString() { return AsmString; }
void setAsmString(StringLiteral *Asm) { AsmString = Asm; }
- static bool classof(const Decl *D) {
- return D->getKind() == FileScopeAsm;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FileScopeAsmDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == FileScopeAsm; }
};
/// BlockDecl - This represents a block literal declaration, which is like an
@@ -1869,11 +1907,12 @@ public:
assert(i < getNumParams() && "Illegal param #");
return ParamInfo[i];
}
- void setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams);
+ void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == Block; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const BlockDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Block; }
static DeclContext *castToDeclContext(const BlockDecl *D) {
return static_cast<DeclContext *>(const_cast<BlockDecl*>(D));
}
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 775bce2a15fc..a407a1627747 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -480,6 +480,7 @@ public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *) { return true; }
+ static bool classofKind(Kind K) { return true; }
static DeclContext *castToDeclContext(const Decl *);
static Decl *castFromDeclContext(const DeclContext *);
@@ -1020,17 +1021,43 @@ inline bool Decl::isTemplateParameter() const {
getKind() == TemplateTemplateParm;
}
+
+// Specialization selected when ToTy is not a known subclass of DeclContext.
+template <class ToTy,
+ bool IsKnownSubtype = ::llvm::is_base_of< DeclContext, ToTy>::value>
+struct cast_convert_decl_context {
+ static const ToTy *doit(const DeclContext *Val) {
+ return static_cast<const ToTy*>(Decl::castFromDeclContext(Val));
+ }
+
+ static ToTy *doit(DeclContext *Val) {
+ return static_cast<ToTy*>(Decl::castFromDeclContext(Val));
+ }
+};
+
+// Specialization selected when ToTy is a known subclass of DeclContext.
+template <class ToTy>
+struct cast_convert_decl_context<ToTy, true> {
+ static const ToTy *doit(const DeclContext *Val) {
+ return static_cast<const ToTy*>(Val);
+ }
+
+ static ToTy *doit(DeclContext *Val) {
+ return static_cast<ToTy*>(Val);
+ }
+};
+
+
} // end clang.
namespace llvm {
-/// Implement a isa_impl_wrap specialization to check whether a DeclContext is
-/// a specific Decl.
+/// isa<T>(DeclContext*)
template<class ToTy>
struct isa_impl_wrap<ToTy,
const ::clang::DeclContext,const ::clang::DeclContext> {
static bool doit(const ::clang::DeclContext &Val) {
- return ToTy::classof(::clang::Decl::castFromDeclContext(&Val));
+ return ToTy::classofKind(Val.getDeclKind());
}
};
template<class ToTy>
@@ -1038,6 +1065,34 @@ struct isa_impl_wrap<ToTy, ::clang::DeclContext, ::clang::DeclContext>
: public isa_impl_wrap<ToTy,
const ::clang::DeclContext,const ::clang::DeclContext> {};
+/// cast<T>(DeclContext*)
+template<class ToTy>
+struct cast_convert_val<ToTy,
+ const ::clang::DeclContext,const ::clang::DeclContext> {
+ static const ToTy &doit(const ::clang::DeclContext &Val) {
+ return *::clang::cast_convert_decl_context<ToTy>::doit(&Val);
+ }
+};
+template<class ToTy>
+struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext> {
+ static ToTy &doit(::clang::DeclContext &Val) {
+ return *::clang::cast_convert_decl_context<ToTy>::doit(&Val);
+ }
+};
+template<class ToTy>
+struct cast_convert_val<ToTy,
+ const ::clang::DeclContext*, const ::clang::DeclContext*> {
+ static const ToTy *doit(const ::clang::DeclContext *Val) {
+ return ::clang::cast_convert_decl_context<ToTy>::doit(Val);
+ }
+};
+template<class ToTy>
+struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*> {
+ static ToTy *doit(::clang::DeclContext *Val) {
+ return ::clang::cast_convert_decl_context<ToTy>::doit(Val);
+ }
+};
+
/// Implement cast_convert_val for Decl -> DeclContext conversions.
template<class FromTy>
struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> {
@@ -1067,31 +1122,6 @@ struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> {
}
};
-/// Implement cast_convert_val for DeclContext -> Decl conversions.
-template<class ToTy>
-struct cast_convert_val<ToTy,
- const ::clang::DeclContext,const ::clang::DeclContext> {
- static ToTy &doit(const ::clang::DeclContext &Val) {
- return *reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(&Val));
- }
-};
-template<class ToTy>
-struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext>
- : public cast_convert_val<ToTy,
- const ::clang::DeclContext,const ::clang::DeclContext> {};
-
-template<class ToTy>
-struct cast_convert_val<ToTy,
- const ::clang::DeclContext*, const ::clang::DeclContext*> {
- static ToTy *doit(const ::clang::DeclContext *Val) {
- return reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(Val));
- }
-};
-template<class ToTy>
-struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*>
- : public cast_convert_val<ToTy,
- const ::clang::DeclContext*,const ::clang::DeclContext*> {};
-
} // end namespace llvm
#endif
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 73ebf52d383b..0978c6da9d66 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -145,6 +145,10 @@ public:
/// class (or not).
bool isVirtual() const { return Virtual; }
+ /// \brief Determine whether this base class if a base of a class declared
+ /// with the 'class' keyword (vs. one declared with the 'struct' keyword).
+ bool isBaseOfClass() const { return BaseOfClass; }
+
/// getAccessSpecifier - Returns the access specifier for this base
/// specifier. This is the actual base specifier as used for
/// semantic analysis, so the result can never be AS_none. To
@@ -174,115 +178,137 @@ public:
/// FIXME: This class will disappear once we've properly taught RecordDecl
/// to deal with C++-specific things.
class CXXRecordDecl : public RecordDecl {
- /// UserDeclaredConstructor - True when this class has a
- /// user-declared constructor.
- bool UserDeclaredConstructor : 1;
- /// UserDeclaredCopyConstructor - True when this class has a
- /// user-declared copy constructor.
- bool UserDeclaredCopyConstructor : 1;
+ friend void TagDecl::startDefinition();
+
+ struct DefinitionData {
+ DefinitionData(CXXRecordDecl *D);
+
+ /// UserDeclaredConstructor - True when this class has a
+ /// user-declared constructor.
+ bool UserDeclaredConstructor : 1;
+
+ /// UserDeclaredCopyConstructor - True when this class has a
+ /// user-declared copy constructor.
+ bool UserDeclaredCopyConstructor : 1;
+
+ /// UserDeclaredCopyAssignment - True when this class has a
+ /// user-declared copy assignment operator.
+ bool UserDeclaredCopyAssignment : 1;
+
+ /// UserDeclaredDestructor - True when this class has a
+ /// user-declared destructor.
+ bool UserDeclaredDestructor : 1;
+
+ /// Aggregate - True when this class is an aggregate.
+ bool Aggregate : 1;
+
+ /// PlainOldData - True when this class is a POD-type.
+ bool PlainOldData : 1;
+
+ /// Empty - true when this class is empty for traits purposes,
+ /// i.e. has no data members other than 0-width bit-fields, has no
+ /// virtual function/base, and doesn't inherit from a non-empty
+ /// class. Doesn't take union-ness into account.
+ bool Empty : 1;
+
+ /// Polymorphic - True when this class is polymorphic, i.e. has at
+ /// least one virtual member or derives from a polymorphic class.
+ bool Polymorphic : 1;
+
+ /// Abstract - True when this class is abstract, i.e. has at least
+ /// one pure virtual function, (that can come from a base class).
+ bool Abstract : 1;
+
+ /// HasTrivialConstructor - True when this class has a trivial constructor.
+ ///
+ /// C++ [class.ctor]p5. A constructor is trivial if it is an
+ /// implicitly-declared default constructor and if:
+ /// * its class has no virtual functions and no virtual base classes, and
+ /// * all the direct base classes of its class have trivial constructors, and
+ /// * for all the nonstatic data members of its class that are of class type
+ /// (or array thereof), each such class has a trivial constructor.
+ bool HasTrivialConstructor : 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.
+ bool HasTrivialCopyConstructor : 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.
+ bool HasTrivialCopyAssignment : 1;
+
+ /// HasTrivialDestructor - True when this class has a trivial destructor.
+ ///
+ /// C++ [class.dtor]p3. A destructor is trivial if it is an
+ /// implicitly-declared destructor and if:
+ /// * all of the direct base classes of its class have trivial destructors
+ /// and
+ /// * for all of the non-static data members of its class that are of class
+ /// type (or array thereof), each such class has a trivial destructor.
+ bool HasTrivialDestructor : 1;
+
+ /// ComputedVisibleConversions - True when visible conversion functions are
+ /// already computed and are available.
+ bool ComputedVisibleConversions : 1;
+
+ /// Bases - Base classes of this class.
+ /// FIXME: This is wasted space for a union.
+ CXXBaseSpecifier *Bases;
- /// UserDeclaredCopyAssignment - True when this class has a
- /// user-declared copy assignment operator.
- bool UserDeclaredCopyAssignment : 1;
+ /// NumBases - The number of base class specifiers in Bases.
+ unsigned NumBases;
- /// UserDeclaredDestructor - True when this class has a
- /// user-declared destructor.
- bool UserDeclaredDestructor : 1;
+ /// VBases - direct and indirect virtual base classes of this class.
+ CXXBaseSpecifier *VBases;
- /// Aggregate - True when this class is an aggregate.
- bool Aggregate : 1;
+ /// NumVBases - The number of virtual base class specifiers in VBases.
+ unsigned NumVBases;
- /// PlainOldData - True when this class is a POD-type.
- bool PlainOldData : 1;
+ /// Conversions - Overload set containing the conversion functions
+ /// of this C++ class (but not its inherited conversion
+ /// functions). Each of the entries in this overload set is a
+ /// CXXConversionDecl.
+ UnresolvedSet<4> Conversions;
- /// Empty - true when this class is empty for traits purposes, i.e. has no
- /// data members other than 0-width bit-fields, has no virtual function/base,
- /// and doesn't inherit from a non-empty class. Doesn't take union-ness into
- /// account.
- bool Empty : 1;
+ /// VisibleConversions - Overload set containing the conversion
+ /// functions of this C++ class and all those inherited conversion
+ /// functions that are visible in this class. Each of the entries
+ /// in this overload set is a CXXConversionDecl or a
+ /// FunctionTemplateDecl.
+ UnresolvedSet<4> VisibleConversions;
- /// Polymorphic - True when this class is polymorphic, i.e. has at least one
- /// virtual member or derives from a polymorphic class.
- bool Polymorphic : 1;
+ /// Definition - The declaration which defines this record.
+ CXXRecordDecl *Definition;
- /// Abstract - True when this class is abstract, i.e. has at least one
- /// pure virtual function, (that can come from a base class).
- bool Abstract : 1;
+ } *DefinitionData;
- /// HasTrivialConstructor - True when this class has a trivial constructor.
- ///
- /// C++ [class.ctor]p5. A constructor is trivial if it is an
- /// implicitly-declared default constructor and if:
- /// * its class has no virtual functions and no virtual base classes, and
- /// * all the direct base classes of its class have trivial constructors, and
- /// * for all the nonstatic data members of its class that are of class type
- /// (or array thereof), each such class has a trivial constructor.
- bool HasTrivialConstructor : 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.
- bool HasTrivialCopyConstructor : 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.
- bool HasTrivialCopyAssignment : 1;
-
- /// HasTrivialDestructor - True when this class has a trivial destructor.
- ///
- /// C++ [class.dtor]p3. A destructor is trivial if it is an
- /// implicitly-declared destructor and if:
- /// * all of the direct base classes of its class have trivial destructors
- /// and
- /// * for all of the non-static data members of its class that are of class
- /// type (or array thereof), each such class has a trivial destructor.
- bool HasTrivialDestructor : 1;
-
- /// ComputedVisibleConversions - True when visible conversion functions are
- /// already computed and are available.
- bool ComputedVisibleConversions : 1;
-
- /// Bases - Base classes of this class.
- /// FIXME: This is wasted space for a union.
- CXXBaseSpecifier *Bases;
-
- /// NumBases - The number of base class specifiers in Bases.
- unsigned NumBases;
-
- /// VBases - direct and indirect virtual base classes of this class.
- CXXBaseSpecifier *VBases;
-
- /// NumVBases - The number of virtual base class specifiers in VBases.
- unsigned NumVBases;
-
- /// Conversions - Overload set containing the conversion functions
- /// of this C++ class (but not its inherited conversion
- /// functions). Each of the entries in this overload set is a
- /// CXXConversionDecl.
- UnresolvedSet<4> Conversions;
-
- /// VisibleConversions - Overload set containing the conversion functions
- /// of this C++ class and all those inherited conversion functions that
- /// are visible in this class. Each of the entries in this overload set is
- /// a CXXConversionDecl or a FunctionTemplateDecl.
- UnresolvedSet<4> VisibleConversions;
+ struct DefinitionData &data() {
+ assert(DefinitionData && "queried property of class with no definition");
+ return *DefinitionData;
+ }
+
+ const struct DefinitionData &data() const {
+ assert(DefinitionData && "queried property of class with no definition");
+ return *DefinitionData;
+ }
/// \brief The template or declaration that this declaration
/// describes or was instantiated from, respectively.
@@ -336,6 +362,13 @@ public:
return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl());
}
+ CXXRecordDecl *getDefinition() const {
+ if (!DefinitionData) return 0;
+ return data().Definition;
+ }
+
+ bool hasDefinition() const { return DefinitionData != 0; }
+
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
SourceLocation TKL = SourceLocation(),
@@ -345,21 +378,22 @@ public:
virtual void Destroy(ASTContext& C);
bool isDynamicClass() const {
- return Polymorphic || NumVBases != 0;
+ return data().Polymorphic || data().NumVBases != 0;
}
/// setBases - Sets the base classes of this struct or class.
- void setBases(ASTContext &C,
- CXXBaseSpecifier const * const *Bases, unsigned NumBases);
+ void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
/// getNumBases - Retrieves the number of base classes of this
/// class.
- unsigned getNumBases() const { return NumBases; }
+ unsigned getNumBases() const { return data().NumBases; }
- base_class_iterator bases_begin() { return Bases; }
- base_class_const_iterator bases_begin() const { return Bases; }
- base_class_iterator bases_end() { return Bases + NumBases; }
- base_class_const_iterator bases_end() const { return Bases + NumBases; }
+ base_class_iterator bases_begin() { return data().Bases; }
+ base_class_const_iterator bases_begin() const { return data().Bases; }
+ base_class_iterator bases_end() { return bases_begin() + data().NumBases; }
+ base_class_const_iterator bases_end() const {
+ return bases_begin() + data().NumBases;
+ }
reverse_base_class_iterator bases_rbegin() {
return reverse_base_class_iterator(bases_end());
}
@@ -375,12 +409,14 @@ public:
/// getNumVBases - Retrieves the number of virtual base classes of this
/// class.
- unsigned getNumVBases() const { return NumVBases; }
+ unsigned getNumVBases() const { return data().NumVBases; }
- base_class_iterator vbases_begin() { return VBases; }
- base_class_const_iterator vbases_begin() const { return VBases; }
- base_class_iterator vbases_end() { return VBases + NumVBases; }
- base_class_const_iterator vbases_end() const { return VBases + NumVBases; }
+ base_class_iterator vbases_begin() { return data().VBases; }
+ base_class_const_iterator vbases_begin() const { return data().VBases; }
+ base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; }
+ base_class_const_iterator vbases_end() const {
+ return vbases_begin() + data().NumVBases;
+ }
reverse_base_class_iterator vbases_rbegin() {
return reverse_base_class_iterator(vbases_end());
}
@@ -445,17 +481,14 @@ public:
/// user-declared constructors. When true, a default constructor
/// will not be implicitly declared.
bool hasUserDeclaredConstructor() const {
- assert((isDefinition() ||
- cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
- "Incomplete record decl!");
- return UserDeclaredConstructor;
+ return data().UserDeclaredConstructor;
}
/// hasUserDeclaredCopyConstructor - Whether this class has a
/// user-declared copy constructor. When false, a copy constructor
/// will be implicitly declared.
bool hasUserDeclaredCopyConstructor() const {
- return UserDeclaredCopyConstructor;
+ return data().UserDeclaredCopyConstructor;
}
/// addedAssignmentOperator - Notify the class that another assignment
@@ -467,45 +500,45 @@ public:
/// user-declared copy assignment operator. When false, a copy
/// assigment operator will be implicitly declared.
bool hasUserDeclaredCopyAssignment() const {
- return UserDeclaredCopyAssignment;
+ return data().UserDeclaredCopyAssignment;
}
/// hasUserDeclaredDestructor - Whether this class has a
/// user-declared destructor. When false, a destructor will be
/// implicitly declared.
- bool hasUserDeclaredDestructor() const { return UserDeclaredDestructor; }
+ bool hasUserDeclaredDestructor() const {
+ return data().UserDeclaredDestructor;
+ }
/// setUserDeclaredDestructor - Set whether this class has a
/// user-declared destructor. If not set by the time the class is
/// fully defined, a destructor will be implicitly declared.
void setUserDeclaredDestructor(bool UCD) {
- UserDeclaredDestructor = UCD;
+ data().UserDeclaredDestructor = UCD;
}
/// getConversions - Retrieve the overload set containing all of the
/// conversion functions in this class.
UnresolvedSetImpl *getConversionFunctions() {
- assert((this->isDefinition() ||
- cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
- "getConversionFunctions() called on incomplete type");
- return &Conversions;
+ return &data().Conversions;
}
const UnresolvedSetImpl *getConversionFunctions() const {
- assert((this->isDefinition() ||
- cast<RecordType>(getTypeForDecl())->isBeingDefined()) &&
- "getConversionFunctions() called on incomplete type");
- return &Conversions;
+ return &data().Conversions;
}
typedef UnresolvedSetImpl::iterator conversion_iterator;
- conversion_iterator conversion_begin() const { return Conversions.begin(); }
- conversion_iterator conversion_end() const { return Conversions.end(); }
+ conversion_iterator conversion_begin() const {
+ return getConversionFunctions()->begin();
+ }
+ conversion_iterator conversion_end() const {
+ return getConversionFunctions()->end();
+ }
/// Replaces a conversion function with a new declaration.
///
/// Returns true if the old conversion was found.
bool replaceConversion(const NamedDecl* Old, NamedDecl *New) {
- return Conversions.replace(Old, New);
+ return getConversionFunctions()->replace(Old, New);
}
/// getVisibleConversionFunctions - get all conversion functions visible
@@ -532,11 +565,11 @@ public:
/// [dcl.init.aggr]), which is a class with no user-declared
/// constructors, no private or protected non-static data members,
/// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1).
- bool isAggregate() const { return Aggregate; }
+ bool isAggregate() const { return data().Aggregate; }
/// setAggregate - Set whether this class is an aggregate (C++
/// [dcl.init.aggr]).
- void setAggregate(bool Agg) { Aggregate = Agg; }
+ void setAggregate(bool Agg) { data().Aggregate = Agg; }
/// setMethodAsVirtual - Make input method virtual and set the necesssary
/// special function bits and other bits accordingly.
@@ -546,66 +579,74 @@ public:
/// that is an aggregate that has no non-static non-POD data members, no
/// reference data members, no user-defined copy assignment operator and no
/// user-defined destructor.
- bool isPOD() const { return PlainOldData; }
+ bool isPOD() const { return data().PlainOldData; }
/// setPOD - Set whether this class is a POD-type (C++ [class]p4).
- void setPOD(bool POD) { PlainOldData = POD; }
+ void setPOD(bool POD) { data().PlainOldData = POD; }
/// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which
/// means it has a virtual function, virtual base, data member (other than
/// 0-width bit-field) or inherits from a non-empty class. Does NOT include
/// a check for union-ness.
- bool isEmpty() const { return Empty; }
+ bool isEmpty() const { return data().Empty; }
/// Set whether this class is empty (C++0x [meta.unary.prop])
- void setEmpty(bool Emp) { Empty = Emp; }
+ void setEmpty(bool Emp) { data().Empty = Emp; }
/// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
/// which means that the class contains or inherits a virtual function.
- bool isPolymorphic() const { return Polymorphic; }
+ bool isPolymorphic() const { return data().Polymorphic; }
/// setPolymorphic - Set whether this class is polymorphic (C++
/// [class.virtual]).
- void setPolymorphic(bool Poly) { Polymorphic = Poly; }
+ void setPolymorphic(bool Poly) { data().Polymorphic = Poly; }
/// isAbstract - Whether this class is abstract (C++ [class.abstract]),
/// which means that the class contains or inherits a pure virtual function.
- bool isAbstract() const { return Abstract; }
+ bool isAbstract() const { return data().Abstract; }
/// setAbstract - Set whether this class is abstract (C++ [class.abstract])
- void setAbstract(bool Abs) { Abstract = Abs; }
+ void setAbstract(bool Abs) { data().Abstract = Abs; }
// hasTrivialConstructor - Whether this class has a trivial constructor
// (C++ [class.ctor]p5)
- bool hasTrivialConstructor() const { return HasTrivialConstructor; }
+ bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
// setHasTrivialConstructor - Set whether this class has a trivial constructor
// (C++ [class.ctor]p5)
- void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; }
+ void setHasTrivialConstructor(bool TC) { data().HasTrivialConstructor = TC; }
// hasTrivialCopyConstructor - Whether this class has a trivial copy
// constructor (C++ [class.copy]p6)
- bool hasTrivialCopyConstructor() const { return HasTrivialCopyConstructor; }
+ bool hasTrivialCopyConstructor() const {
+ return data().HasTrivialCopyConstructor;
+ }
// setHasTrivialCopyConstructor - Set whether this class has a trivial
// copy constructor (C++ [class.copy]p6)
- void setHasTrivialCopyConstructor(bool TC) { HasTrivialCopyConstructor = TC; }
+ void setHasTrivialCopyConstructor(bool TC) {
+ data().HasTrivialCopyConstructor = TC;
+ }
// hasTrivialCopyAssignment - Whether this class has a trivial copy
// assignment operator (C++ [class.copy]p11)
- bool hasTrivialCopyAssignment() const { return HasTrivialCopyAssignment; }
+ bool hasTrivialCopyAssignment() const {
+ return data().HasTrivialCopyAssignment;
+ }
// setHasTrivialCopyAssignment - Set whether this class has a
// trivial copy assignment operator (C++ [class.copy]p11)
- void setHasTrivialCopyAssignment(bool TC) { HasTrivialCopyAssignment = TC; }
+ void setHasTrivialCopyAssignment(bool TC) {
+ data().HasTrivialCopyAssignment = TC;
+ }
// hasTrivialDestructor - Whether this class has a trivial destructor
// (C++ [class.dtor]p3)
- bool hasTrivialDestructor() const { return HasTrivialDestructor; }
+ bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
// setHasTrivialDestructor - Set whether this class has a trivial destructor
// (C++ [class.dtor]p3)
- void setHasTrivialDestructor(bool TC) { HasTrivialDestructor = TC; }
+ void setHasTrivialDestructor(bool TC) { data().HasTrivialDestructor = TC; }
/// \brief If this record is an instantiation of a member class,
/// retrieves the member class from which it was instantiated.
@@ -826,10 +867,11 @@ public:
return (PathAccess > DeclAccess ? PathAccess : DeclAccess);
}
- static bool classof(const Decl *D) {
- return D->getKind() == CXXRecord ||
- D->getKind() == ClassTemplateSpecialization ||
- D->getKind() == ClassTemplatePartialSpecialization;
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) {
+ return K == CXXRecord ||
+ K == ClassTemplateSpecialization ||
+ K == ClassTemplatePartialSpecialization;
}
static bool classof(const CXXRecordDecl *D) { return true; }
static bool classof(const ClassTemplateSpecializationDecl *D) {
@@ -911,10 +953,11 @@ public:
bool hasInlineBody() const;
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXMethodDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= CXXMethod && K <= CXXConversion;
+ }
};
/// CXXBaseOrMemberInitializer - Represents a C++ base or member
@@ -939,9 +982,9 @@ class CXXBaseOrMemberInitializer {
/// \brief The source location for the field name.
SourceLocation MemberLocation;
- /// Args - The arguments used to initialize the base or member.
- Stmt **Args;
- unsigned NumArgs;
+ /// \brief The argument used to initialize the base or member, which may
+ /// end up constructing an object (when multiple arguments are involved).
+ Stmt *Init;
/// \brief Stores either the constructor to call to initialize this base or
/// member (a CXXConstructorDecl pointer), or stores the anonymous union of
@@ -961,7 +1004,7 @@ class CXXBaseOrMemberInitializer {
/// @endcode
/// In above example, BaseOrMember holds the field decl. for anonymous union
/// and AnonUnionMember holds field decl for au_i1.
- llvm::PointerUnion<CXXConstructorDecl *, FieldDecl *> CtorOrAnonUnion;
+ FieldDecl *AnonUnionMember;
/// LParenLoc - Location of the left paren of the ctor-initializer.
SourceLocation LParenLoc;
@@ -973,30 +1016,22 @@ public:
/// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
explicit
CXXBaseOrMemberInitializer(ASTContext &Context,
- TypeSourceInfo *TInfo, CXXConstructorDecl *C,
+ TypeSourceInfo *TInfo,
SourceLocation L,
- Expr **Args, unsigned NumArgs,
+ Expr *Init,
SourceLocation R);
/// CXXBaseOrMemberInitializer - Creates a new member initializer.
explicit
CXXBaseOrMemberInitializer(ASTContext &Context,
FieldDecl *Member, SourceLocation MemberLoc,
- CXXConstructorDecl *C, SourceLocation L,
- Expr **Args, unsigned NumArgs,
+ SourceLocation L,
+ Expr *Init,
SourceLocation R);
/// \brief Destroy the base or member initializer.
void Destroy(ASTContext &Context);
- /// arg_iterator - Iterates through the member initialization
- /// arguments.
- typedef ExprIterator arg_iterator;
-
- /// arg_const_iterator - Iterates through the member initialization
- /// arguments.
- typedef ConstExprIterator const_arg_iterator;
-
/// isBaseInitializer - Returns true when this initializer is
/// initializing a base class.
bool isBaseInitializer() const { return BaseOrMember.is<TypeSourceInfo*>(); }
@@ -1046,32 +1081,16 @@ public:
SourceRange getSourceRange() const;
FieldDecl *getAnonUnionMember() const {
- return CtorOrAnonUnion.dyn_cast<FieldDecl *>();
+ return AnonUnionMember;
}
void setAnonUnionMember(FieldDecl *anonMember) {
- CtorOrAnonUnion = anonMember;
- }
-
- const CXXConstructorDecl *getConstructor() const {
- return CtorOrAnonUnion.dyn_cast<CXXConstructorDecl *>();
+ AnonUnionMember = anonMember;
}
SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
- /// arg_begin() - Retrieve an iterator to the first initializer argument.
- arg_iterator arg_begin() { return Args; }
- /// arg_begin() - Retrieve an iterator to the first initializer argument.
- const_arg_iterator const_arg_begin() const { return Args; }
-
- /// arg_end() - Retrieve an iterator past the last initializer argument.
- arg_iterator arg_end() { return Args + NumArgs; }
- /// arg_end() - Retrieve an iterator past the last initializer argument.
- const_arg_iterator const_arg_end() const { return Args + NumArgs; }
-
- /// getNumArgs - Determine the number of arguments used to
- /// initialize the member or base.
- unsigned getNumArgs() const { return NumArgs; }
+ Expr *getInit() { return static_cast<Expr *>(Init); }
};
/// CXXConstructorDecl - Represents a C++ constructor within a
@@ -1084,8 +1103,9 @@ public:
/// };
/// @endcode
class CXXConstructorDecl : public CXXMethodDecl {
- /// Explicit - Whether this constructor is explicit.
- bool Explicit : 1;
+ /// IsExplicitSpecified - Whether this constructor declaration has the
+ /// 'explicit' keyword specified.
+ bool IsExplicitSpecified : 1;
/// ImplicitlyDefined - Whether this constructor was implicitly
/// defined by the compiler. When false, the constructor was defined
@@ -1103,9 +1123,10 @@ class CXXConstructorDecl : public CXXMethodDecl {
CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L,
DeclarationName N, QualType T, TypeSourceInfo *TInfo,
- bool isExplicit, bool isInline, bool isImplicitlyDeclared)
+ bool isExplicitSpecified, bool isInline,
+ bool isImplicitlyDeclared)
: CXXMethodDecl(CXXConstructor, RD, L, N, T, TInfo, false, isInline),
- Explicit(isExplicit), ImplicitlyDefined(false),
+ IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -1118,8 +1139,15 @@ public:
bool isExplicit,
bool isInline, bool isImplicitlyDeclared);
+ /// isExplicitSpecified - Whether this constructor declaration has the
+ /// 'explicit' keyword specified.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
/// isExplicit - Whether this constructor was marked "explicit" or not.
- bool isExplicit() const { return Explicit; }
+ bool isExplicit() const {
+ return cast<CXXConstructorDecl>(getFirstDeclaration())
+ ->isExplicitSpecified();
+ }
/// isImplicitlyDefined - Whether this constructor was implicitly
/// defined. If false, then this constructor was defined by the
@@ -1212,10 +1240,9 @@ public:
bool isCopyConstructorLikeSpecialization() const;
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == CXXConstructor;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXConstructorDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == CXXConstructor; }
};
/// CXXDestructorDecl - Represents a C++ destructor within a
@@ -1274,10 +1301,9 @@ public:
const FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == CXXDestructor;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXDestructorDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == CXXDestructor; }
};
/// CXXConversionDecl - Represents a C++ conversion function within a
@@ -1290,16 +1316,16 @@ public:
/// };
/// @endcode
class CXXConversionDecl : public CXXMethodDecl {
- /// Explicit - Whether this conversion function is marked
- /// "explicit", meaning that it can only be applied when the user
+ /// IsExplicitSpecified - Whether this conversion function declaration is
+ /// marked "explicit", meaning that it can only be applied when the user
/// explicitly wrote a cast. This is a C++0x feature.
- bool Explicit : 1;
+ bool IsExplicitSpecified : 1;
CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L,
DeclarationName N, QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicit)
+ bool isInline, bool isExplicitSpecified)
: CXXMethodDecl(CXXConversion, RD, L, N, T, TInfo, false, isInline),
- Explicit(isExplicit) { }
+ IsExplicitSpecified(isExplicitSpecified) { }
public:
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
@@ -1307,10 +1333,18 @@ public:
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicit);
+ /// IsExplicitSpecified - Whether this conversion function declaration is
+ /// marked "explicit", meaning that it can only be applied when the user
+ /// explicitly wrote a cast. This is a C++0x feature.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
/// isExplicit - Whether this is an explicit conversion operator
/// (C++0x only). Explicit conversion operators are only considered
/// when the user has explicitly written a cast.
- bool isExplicit() const { return Explicit; }
+ bool isExplicit() const {
+ return cast<CXXConversionDecl>(getFirstDeclaration())
+ ->isExplicitSpecified();
+ }
/// getConversionType - Returns the type that this conversion
/// function is converting to.
@@ -1319,10 +1353,9 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == CXXConversion;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXConversionDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == CXXConversion; }
};
/// FriendDecl - Represents the declaration of a friend entity,
@@ -1391,10 +1424,9 @@ public:
void setSpecialization(bool WS) { WasSpecialization = WS; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::Friend;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FriendDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::Friend; }
};
/// LinkageSpecDecl - This represents a linkage specification. For example:
@@ -1432,10 +1464,9 @@ public:
/// braces in its syntactic form.
bool hasBraces() const { return HadBraces; }
- static bool classof(const Decl *D) {
- return D->getKind() == LinkageSpec;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const LinkageSpecDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == LinkageSpec; }
static DeclContext *castToDeclContext(const LinkageSpecDecl *D) {
return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D));
}
@@ -1537,10 +1568,9 @@ public:
NamedDecl *Nominated,
DeclContext *CommonAncestor);
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::UsingDirective;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingDirectiveDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::UsingDirective; }
// Friend for getUsingDirectiveName.
friend class DeclContext;
@@ -1598,6 +1628,16 @@ public:
return const_cast<NamespaceAliasDecl*>(this)->getNamespace();
}
+ /// Returns the location of the alias name, i.e. 'foo' in
+ /// "namespace foo = ns::bar;".
+ SourceLocation getAliasLoc() const { return AliasLoc; }
+
+ /// Returns the location of the 'namespace' keyword.
+ SourceLocation getNamespaceLoc() const { return getLocation(); }
+
+ /// Returns the location of the identifier in the named namespace.
+ SourceLocation getTargetNameLoc() const { return IdentLoc; }
+
/// \brief Retrieve the namespace that this alias refers to, which
/// may either be a NamespaceDecl or a NamespaceAliasDecl.
NamedDecl *getAliasedNamespace() const { return Namespace; }
@@ -1610,10 +1650,9 @@ public:
SourceLocation IdentLoc,
NamedDecl *Namespace);
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::NamespaceAlias;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamespaceAliasDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::NamespaceAlias; }
};
/// UsingShadowDecl - Represents a shadow declaration introduced into
@@ -1660,10 +1699,9 @@ public:
return Using;
}
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::UsingShadow;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingShadowDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::UsingShadow; }
};
/// UsingDecl - Represents a C++ using-declaration. For example:
@@ -1732,10 +1770,9 @@ public:
SourceLocation IdentL, SourceRange NNR, SourceLocation UsingL,
NestedNameSpecifier* TargetNNS, DeclarationName Name, bool IsTypeNameArg);
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::Using;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::Using; }
};
/// UnresolvedUsingValueDecl - Represents a dependent using
@@ -1784,10 +1821,9 @@ public:
SourceRange TargetNNR, NestedNameSpecifier *TargetNNS,
SourceLocation TargetNameLoc, DeclarationName TargetName);
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::UnresolvedUsingValue;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UnresolvedUsingValueDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::UnresolvedUsingValue; }
};
/// UnresolvedUsingTypenameDecl - Represents a dependent using
@@ -1843,10 +1879,9 @@ public:
SourceRange TargetNNR, NestedNameSpecifier *TargetNNS,
SourceLocation TargetNameLoc, DeclarationName TargetName);
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::UnresolvedUsingTypename;
- }
+ 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 == Decl::UnresolvedUsingTypename; }
};
/// StaticAssertDecl - Represents a C++0x static_assert declaration.
@@ -1872,10 +1907,9 @@ public:
virtual ~StaticAssertDecl();
virtual void Destroy(ASTContext& C);
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::StaticAssert;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(StaticAssertDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Decl::StaticAssert; }
};
/// Insertion operator for diagnostics. This allows sending AccessSpecifier's
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 0fb0db13bb57..e562d352e070 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -193,6 +193,9 @@ public:
ImplementationControl impControl = None);
virtual ObjCMethodDecl *getCanonicalDecl();
+ const ObjCMethodDecl *getCanonicalDecl() const {
+ return const_cast<ObjCMethodDecl*>(this)->getCanonicalDecl();
+ }
ObjCDeclQualifier getObjCDeclQualifier() const {
return ObjCDeclQualifier(objcDeclQualifier);
@@ -277,8 +280,9 @@ public:
bool isThisDeclarationADefinition() const { return Body; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == ObjCMethod; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCMethodDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCMethod; }
static DeclContext *castToDeclContext(const ObjCMethodDecl *D) {
return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D));
}
@@ -383,11 +387,12 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= ObjCContainerFirst &&
- D->getKind() <= ObjCContainerLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCContainerDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= ObjCContainerFirst &&
+ K <= ObjCContainerLast;
+ }
static DeclContext *castToDeclContext(const ObjCContainerDecl *D) {
return static_cast<DeclContext *>(const_cast<ObjCContainerDecl*>(D));
@@ -584,8 +589,9 @@ public:
Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(Type *TD) const { TypeForDecl = TD; }
- static bool classof(const Decl *D) { return D->getKind() == ObjCInterface; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCInterfaceDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCInterface; }
};
/// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC
@@ -630,8 +636,9 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == ObjCIvar; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCIvarDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCIvar; }
private:
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
unsigned DeclAccess : 3;
@@ -657,8 +664,9 @@ public:
virtual void Destroy(ASTContext& C);
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) { return D->getKind() == ObjCAtDefsField; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCAtDefsFieldDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCAtDefsField; }
};
/// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols
@@ -749,8 +757,9 @@ public:
SourceLocation getLocEnd() const { return EndLoc; }
void setLocEnd(SourceLocation LE) { EndLoc = LE; }
- static bool classof(const Decl *D) { return D->getKind() == ObjCProtocol; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCProtocolDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCProtocol; }
};
/// ObjCClassDecl - Specifies a list of forward class declarations. For example:
@@ -796,8 +805,9 @@ public:
void setClassList(ASTContext &C, ObjCInterfaceDecl*const*List,
const SourceLocation *Locs, unsigned Num);
- static bool classof(const Decl *D) { return D->getKind() == ObjCClass; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCClassDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCClass; }
};
/// ObjCForwardProtocolDecl - Specifies a list of forward protocol declarations.
@@ -846,10 +856,9 @@ public:
const SourceLocation *Locs, ASTContext &C) {
ReferencedProtocols.set(List, Num, Locs, C);
}
- static bool classof(const Decl *D) {
- return D->getKind() == ObjCForwardProtocol;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCForwardProtocolDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCForwardProtocol; }
};
/// ObjCCategoryDecl - Represents a category declaration. A category allows
@@ -940,6 +949,8 @@ public:
ClassInterface->setCategoryList(this);
}
+ bool IsClassExtension() const { return getIdentifier() == 0; }
+
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation At) { AtLoc = At; }
@@ -950,8 +961,9 @@ public:
return SourceRange(AtLoc, getAtEndRange().getEnd());
}
- static bool classof(const Decl *D) { return D->getKind() == ObjCCategory; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCategoryDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCCategory; }
};
class ObjCImplDecl : public ObjCContainerDecl {
@@ -997,10 +1009,11 @@ public:
return propimpl_iterator(decls_end());
}
- static bool classof(const Decl *D) {
- return D->getKind() >= ObjCImplFirst && D->getKind() <= ObjCImplLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCImplDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= ObjCImplFirst && K <= ObjCImplLast;
+ }
};
/// ObjCCategoryImplDecl - An object of this class encapsulates a category
@@ -1068,8 +1081,9 @@ public:
return getName();
}
- static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;}
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCategoryImplDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
};
/// ObjCImplementationDecl - Represents a class definition - this is where
@@ -1152,10 +1166,9 @@ public:
return ivar_begin() == ivar_end();
}
- static bool classof(const Decl *D) {
- return D->getKind() == ObjCImplementation;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCImplementationDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCImplementation; }
};
/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
@@ -1176,10 +1189,9 @@ public:
ObjCInterfaceDecl *getClassInterface() { return AliasedClass; }
void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; }
- static bool classof(const Decl *D) {
- return D->getKind() == ObjCCompatibleAlias;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCompatibleAliasDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; }
};
@@ -1294,10 +1306,9 @@ public:
return PropertyIvarDecl;
}
- static bool classof(const Decl *D) {
- return D->getKind() == ObjCProperty;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCPropertyDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCProperty; }
};
/// ObjCPropertyImplDecl - Represents implementation declaration of a property
@@ -1354,10 +1365,9 @@ public:
}
void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; }
- static bool classof(const Decl *D) {
- return D->getKind() == ObjCPropertyImpl;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCPropertyImplDecl *D) { return true; }
+ static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
};
} // end namespace clang
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index d8b004a049ce..ced174716c7a 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -247,13 +247,14 @@ public:
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() >= TemplateFirst && D->getKind() <= TemplateLast;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TemplateDecl *D) { return true; }
static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classof(const ClassTemplateDecl *D) { return true; }
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
+ static bool classofKind(Kind K) {
+ return K >= TemplateFirst && K <= TemplateLast;
+ }
protected:
NamedDecl *TemplatedDecl;
@@ -510,10 +511,9 @@ public:
NamedDecl *Decl);
// Implement isa/cast/dyncast support
- static bool classof(const Decl *D)
- { return D->getKind() == FunctionTemplate; }
- static bool classof(const FunctionTemplateDecl *D)
- { return true; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const FunctionTemplateDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == FunctionTemplate; }
};
//===----------------------------------------------------------------------===//
@@ -634,10 +634,9 @@ public:
bool isParameterPack() const { return ParameterPack; }
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == TemplateTypeParm;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TemplateTypeParmDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == TemplateTypeParm; }
};
/// NonTypeTemplateParmDecl - Declares a non-type template parameter,
@@ -682,10 +681,9 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == NonTypeTemplateParm;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == NonTypeTemplateParm; }
};
/// TemplateTemplateParmDecl - Declares a template template parameter,
@@ -735,10 +733,9 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == TemplateTemplateParm;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == TemplateTemplateParm; }
};
/// \brief Represents a class template specialization, which refers to
@@ -903,9 +900,10 @@ public:
TemplateArgs[Arg].Profile(ID, Context);
}
- static bool classof(const Decl *D) {
- return D->getKind() == ClassTemplateSpecialization ||
- D->getKind() == ClassTemplatePartialSpecialization;
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) {
+ return K == ClassTemplateSpecialization ||
+ K == ClassTemplatePartialSpecialization;
}
static bool classof(const ClassTemplateSpecializationDecl *) {
@@ -1039,8 +1037,9 @@ public:
// FIXME: Add Profile support!
- static bool classof(const Decl *D) {
- return D->getKind() == ClassTemplatePartialSpecialization;
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) {
+ return K == ClassTemplatePartialSpecialization;
}
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
@@ -1212,10 +1211,9 @@ public:
}
// Implement isa/cast/dyncast support
- static bool classof(const Decl *D)
- { return D->getKind() == ClassTemplate; }
- static bool classof(const ClassTemplateDecl *D)
- { return true; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const ClassTemplateDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ClassTemplate; }
virtual void Destroy(ASTContext& C);
};
@@ -1293,9 +1291,8 @@ public:
}
// Implement isa/cast/dyncast/etc.
- static bool classof(const Decl *D) {
- return D->getKind() == Decl::FriendTemplate;
- }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == Decl::FriendTemplate; }
static bool classof(const FriendTemplateDecl *D) { return true; }
};
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 59d7e439e570..2254724410d0 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -274,30 +274,34 @@ public:
static DeclarationName getTombstoneMarker() {
return DeclarationName(uintptr_t(-2));
}
+
+ static int compare(DeclarationName LHS, DeclarationName RHS);
void dump() const;
};
/// Ordering on two declaration names. If both names are identifiers,
/// this provides a lexicographical ordering.
-bool operator<(DeclarationName LHS, DeclarationName RHS);
+inline bool operator<(DeclarationName LHS, DeclarationName RHS) {
+ return DeclarationName::compare(LHS, RHS) < 0;
+}
/// Ordering on two declaration names. If both names are identifiers,
/// this provides a lexicographical ordering.
inline bool operator>(DeclarationName LHS, DeclarationName RHS) {
- return RHS < LHS;
+ return DeclarationName::compare(LHS, RHS) > 0;
}
/// Ordering on two declaration names. If both names are identifiers,
/// this provides a lexicographical ordering.
inline bool operator<=(DeclarationName LHS, DeclarationName RHS) {
- return !(RHS < LHS);
+ return DeclarationName::compare(LHS, RHS) <= 0;
}
/// Ordering on two declaration names. If both names are identifiers,
/// this provides a lexicographical ordering.
inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
- return !(LHS < RHS);
+ return DeclarationName::compare(LHS, RHS) >= 0;
}
/// DeclarationNameTable - Used to store and retrieve DeclarationName
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 252781767169..114a19800f50 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -149,7 +149,8 @@ public:
LV_DuplicateVectorComponents,
LV_InvalidExpression,
LV_MemberFunction,
- LV_SubObjCPropertySetting
+ LV_SubObjCPropertySetting,
+ LV_SubObjCPropertyGetterSetting
};
isLvalueResult isLvalue(ASTContext &Ctx) const;
@@ -179,7 +180,8 @@ public:
MLV_ReadonlyProperty,
MLV_NoSetterProperty,
MLV_MemberFunction,
- MLV_SubObjCPropertySetting
+ MLV_SubObjCPropertySetting,
+ MLV_SubObjCPropertyGetterSetting
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
SourceLocation *Loc = 0) const;
@@ -192,6 +194,9 @@ public:
return const_cast<Expr*>(this)->getBitField();
}
+ /// \brief Returns whether this expression refers to a vector element.
+ bool refersToVectorElement() const;
+
/// isIntegerConstantExpr - Return true if this expression is a valid integer
/// constant expression, and, if so, return its value in Result. If not a
/// valid i-c-e, return false and fill in Loc (if specified) with the location
@@ -563,7 +568,10 @@ public:
enum IdentType {
Func,
Function,
- PrettyFunction
+ PrettyFunction,
+ /// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
+ /// 'virtual' keyword is omitted for virtual member functions.
+ PrettyFunctionNoVirtual
};
private:
@@ -584,8 +592,7 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- static std::string ComputeName(ASTContext &Context, IdentType IT,
- const Decl *CurrentDecl);
+ static std::string ComputeName(IdentType IT, const Decl *CurrentDecl);
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
@@ -1745,7 +1752,7 @@ public:
static bool classof(const Stmt *T) {
StmtClass SC = T->getStmtClass();
- if (SC >= ExplicitCastExprClass && SC <= CStyleCastExprClass)
+ if (SC >= CStyleCastExprClass && SC <= CStyleCastExprClass)
return true;
if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
return true;
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 6ce95ac5227f..e4bc4b746439 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -241,10 +241,17 @@ public:
CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) :
Expr(CXXBoolLiteralExprClass, Ty, false, false), Value(val), Loc(l) {}
+ explicit CXXBoolLiteralExpr(EmptyShell Empty)
+ : Expr(CXXBoolLiteralExprClass, Empty) { }
+
bool getValue() const { return Value; }
+ void setValue(bool V) { Value = V; }
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXBoolLiteralExprClass;
}
@@ -262,8 +269,14 @@ public:
CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) :
Expr(CXXNullPtrLiteralExprClass, Ty, false, false), Loc(l) {}
+ explicit CXXNullPtrLiteralExpr(EmptyShell Empty)
+ : Expr(CXXNullPtrLiteralExprClass, Empty) { }
+
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNullPtrLiteralExprClass;
}
@@ -544,6 +557,68 @@ public:
virtual child_iterator child_end();
};
+/// CXXBindReferenceExpr - Represents binding an expression to a reference.
+/// In the example:
+///
+/// const int &i = 10;
+///
+/// a bind reference expression is inserted to indicate that 10 is bound to
+/// a reference. (Ans also that a temporary needs to be created to hold the
+/// value).
+class CXXBindReferenceExpr : public Expr {
+ // SubExpr - The expression being bound.
+ Stmt *SubExpr;
+
+ // ExtendsLifetime - Whether binding this reference extends the lifetime of
+ // the expression being bound. FIXME: Add C++ reference.
+ bool ExtendsLifetime;
+
+ /// RequiresTemporaryCopy - Whether binding the subexpression requires a
+ /// temporary copy.
+ bool RequiresTemporaryCopy;
+
+ CXXBindReferenceExpr(Expr *subexpr, bool ExtendsLifetime,
+ bool RequiresTemporaryCopy)
+ : Expr(CXXBindReferenceExprClass, subexpr->getType(), false, false),
+ SubExpr(subexpr), ExtendsLifetime(ExtendsLifetime),
+ RequiresTemporaryCopy(RequiresTemporaryCopy) { }
+ ~CXXBindReferenceExpr() { }
+
+protected:
+ virtual void DoDestroy(ASTContext &C);
+
+public:
+ static CXXBindReferenceExpr *Create(ASTContext &C, Expr *SubExpr,
+ bool ExtendsLifetime,
+ bool RequiresTemporaryCopy);
+
+ const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+ Expr *getSubExpr() { return cast<Expr>(SubExpr); }
+ void setSubExpr(Expr *E) { SubExpr = E; }
+
+ virtual SourceRange getSourceRange() const {
+ return SubExpr->getSourceRange();
+ }
+
+ /// requiresTemporaryCopy - Whether binding the subexpression requires a
+ /// temporary copy.
+ bool requiresTemporaryCopy() const { return RequiresTemporaryCopy; }
+
+ // extendsLifetime - Whether binding this reference extends the lifetime of
+ // the expression being bound. FIXME: Add C++ reference.
+ bool extendsLifetime() { return ExtendsLifetime; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXBindReferenceExprClass;
+ }
+ static bool classof(const CXXBindReferenceExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
/// CXXConstructExpr - Represents a call to a C++ constructor.
class CXXConstructExpr : public Expr {
CXXConstructorDecl *Constructor;
@@ -551,6 +626,7 @@ class CXXConstructExpr : public Expr {
SourceLocation Loc;
bool Elidable : 1;
bool ZeroInitialization : 1;
+ bool BaseInitialization : 1;
Stmt **Args;
unsigned NumArgs;
@@ -559,7 +635,8 @@ protected:
SourceLocation Loc,
CXXConstructorDecl *d, bool elidable,
Expr **args, unsigned numargs,
- bool ZeroInitialization = false);
+ bool ZeroInitialization = false,
+ bool BaseInitialization = false);
~CXXConstructExpr() { }
virtual void DoDestroy(ASTContext &C);
@@ -573,7 +650,8 @@ public:
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
- bool ZeroInitialization = false);
+ bool ZeroInitialization = false,
+ bool BaseInitialization = false);
CXXConstructorDecl* getConstructor() const { return Constructor; }
@@ -593,6 +671,11 @@ public:
ZeroInitialization = ZeroInit;
}
+ /// \brief Determines whether this constructor is actually constructing
+ /// a base class (rather than a complete object).
+ bool isBaseInitialization() const { return BaseInitialization; }
+ void setBaseInitialization(bool BI) { BaseInitialization = BI; }
+
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
@@ -779,15 +862,14 @@ class CXXNewExpr : public Expr {
SourceLocation EndLoc;
public:
- CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs,
- unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize,
- CXXConstructorDecl *constructor, bool initializer,
+ CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
+ Expr **placementArgs, unsigned numPlaceArgs, bool ParenTypeId,
+ Expr *arraySize, CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
FunctionDecl *operatorDelete, QualType ty,
SourceLocation startLoc, SourceLocation endLoc);
- ~CXXNewExpr() {
- delete[] SubExprs;
- }
+
+ virtual void DoDestroy(ASTContext &C);
QualType getAllocatedType() const {
assert(getType()->isPointerType());
@@ -1059,33 +1141,123 @@ public:
virtual child_iterator child_end();
};
-/// \brief A reference to a name which we were able to look up during
-/// parsing but could not resolve to a specific declaration. This
-/// arises in several ways:
-/// * we might be waiting for argument-dependent lookup
-/// * the name might resolve to an overloaded function
-/// and eventually:
-/// * the lookup might have included a function template
-/// These never include UnresolvedUsingValueDecls, which are always
-/// class members and therefore appear only in
-/// UnresolvedMemberLookupExprs.
-class UnresolvedLookupExpr : public Expr {
+/// \brief A reference to an overloaded function set, either an
+/// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr.
+class OverloadExpr : public Expr {
/// The results. These are undesugared, which is to say, they may
- /// include UsingShadowDecls.
+ /// include UsingShadowDecls. Access is relative to the naming
+ /// class.
UnresolvedSet<4> Results;
- /// The name declared.
+ /// The common name of these declarations.
DeclarationName Name;
- /// The qualifier given, if any.
+ /// The scope specifier, if any.
NestedNameSpecifier *Qualifier;
-
- /// The source range of the nested name specifier.
+
+ /// The source range of the scope specifier.
SourceRange QualifierRange;
/// The location of the name.
SourceLocation NameLoc;
+ /// True if the name was a template-id.
+ bool HasExplicitTemplateArgs;
+
+protected:
+ OverloadExpr(StmtClass K, QualType T, bool Dependent,
+ NestedNameSpecifier *Qualifier, SourceRange QRange,
+ DeclarationName Name, SourceLocation NameLoc,
+ bool HasTemplateArgs)
+ : Expr(K, T, Dependent, Dependent),
+ Name(Name), Qualifier(Qualifier), QualifierRange(QRange),
+ NameLoc(NameLoc), HasExplicitTemplateArgs(HasTemplateArgs)
+ {}
+
+public:
+ /// Computes whether an unresolved lookup on the given declarations
+ /// and optional template arguments is type- and value-dependent.
+ static bool ComputeDependence(UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End,
+ const TemplateArgumentListInfo *Args);
+
+ /// Finds the overloaded expression in the given expression of
+ /// OverloadTy.
+ ///
+ /// \return the expression (which must be there) and true if it is
+ /// within an address-of operator.
+ static llvm::PointerIntPair<OverloadExpr*,1> find(Expr *E) {
+ assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload));
+
+ bool op = false;
+ E = E->IgnoreParens();
+ if (isa<UnaryOperator>(E))
+ op = true, E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
+ return llvm::PointerIntPair<OverloadExpr*,1>(cast<OverloadExpr>(E), op);
+ }
+
+ void addDecls(UnresolvedSetIterator Begin, UnresolvedSetIterator End) {
+ Results.append(Begin, End);
+ }
+
+ typedef UnresolvedSetImpl::iterator decls_iterator;
+ decls_iterator decls_begin() const { return Results.begin(); }
+ decls_iterator decls_end() const { return Results.end(); }
+
+ /// Gets the decls as an unresolved set.
+ const UnresolvedSetImpl &getDecls() { return Results; }
+
+ /// Gets the number of declarations in the unresolved set.
+ unsigned getNumDecls() const { return Results.size(); }
+
+ /// Gets the name looked up.
+ DeclarationName getName() const { return Name; }
+ void setName(DeclarationName N) { Name = N; }
+
+ /// Gets the location of the name.
+ SourceLocation getNameLoc() const { return NameLoc; }
+ void setNameLoc(SourceLocation Loc) { NameLoc = Loc; }
+
+ /// Fetches the nested-name qualifier, if one was given.
+ NestedNameSpecifier *getQualifier() const { return Qualifier; }
+
+ /// Fetches the range of the nested-name qualifier.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief Determines whether this expression had an explicit
+ /// template argument list, e.g. f<int>.
+ bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
+
+ ExplicitTemplateArgumentList &getExplicitTemplateArgs(); // defined far below
+
+ const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ return const_cast<OverloadExpr*>(this)->getExplicitTemplateArgs();
+ }
+
+ ExplicitTemplateArgumentList *getOptionalExplicitTemplateArgs() {
+ if (hasExplicitTemplateArgs())
+ return &getExplicitTemplateArgs();
+ return 0;
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == UnresolvedLookupExprClass ||
+ T->getStmtClass() == UnresolvedMemberExprClass;
+ }
+ static bool classof(const OverloadExpr *) { return true; }
+};
+
+/// \brief A reference to a name which we were able to look up during
+/// parsing but could not resolve to a specific declaration. This
+/// arises in several ways:
+/// * we might be waiting for argument-dependent lookup
+/// * the name might resolve to an overloaded function
+/// and eventually:
+/// * the lookup might have included a function template
+/// These never include UnresolvedUsingValueDecls, which are always
+/// class members and therefore appear only in
+/// UnresolvedMemberLookupExprs.
+class UnresolvedLookupExpr : public OverloadExpr {
/// True if these lookup results should be extended by
/// argument-dependent lookup if this is the operand of a function
/// call.
@@ -1095,35 +1267,40 @@ class UnresolvedLookupExpr : public Expr {
/// trivially rederivable if we urgently need to kill this field.
bool Overloaded;
- /// True if the name looked up had explicit template arguments.
- /// This requires all the results to be function templates.
- bool HasExplicitTemplateArgs;
+ /// The naming class (C++ [class.access.base]p5) of the lookup, if
+ /// any. This can generally be recalculated from the context chain,
+ /// but that can be fairly expensive for unqualified lookups. If we
+ /// want to improve memory use here, this could go in a union
+ /// against the qualified-lookup bits.
+ CXXRecordDecl *NamingClass;
- UnresolvedLookupExpr(QualType T, bool Dependent,
+ UnresolvedLookupExpr(QualType T, bool Dependent, CXXRecordDecl *NamingClass,
NestedNameSpecifier *Qualifier, SourceRange QRange,
DeclarationName Name, SourceLocation NameLoc,
bool RequiresADL, bool Overloaded, bool HasTemplateArgs)
- : Expr(UnresolvedLookupExprClass, T, Dependent, Dependent),
- Name(Name), Qualifier(Qualifier), QualifierRange(QRange),
- NameLoc(NameLoc), RequiresADL(RequiresADL), Overloaded(Overloaded),
- HasExplicitTemplateArgs(HasTemplateArgs)
+ : OverloadExpr(UnresolvedLookupExprClass, T, Dependent, Qualifier, QRange,
+ Name, NameLoc, HasTemplateArgs),
+ RequiresADL(RequiresADL), Overloaded(Overloaded), NamingClass(NamingClass)
{}
public:
static UnresolvedLookupExpr *Create(ASTContext &C,
bool Dependent,
+ CXXRecordDecl *NamingClass,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
DeclarationName Name,
SourceLocation NameLoc,
bool ADL, bool Overloaded) {
return new(C) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy,
- Dependent, Qualifier, QualifierRange,
+ Dependent, NamingClass,
+ Qualifier, QualifierRange,
Name, NameLoc, ADL, Overloaded, false);
}
static UnresolvedLookupExpr *Create(ASTContext &C,
bool Dependent,
+ CXXRecordDecl *NamingClass,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
DeclarationName Name,
@@ -1131,20 +1308,6 @@ public:
bool ADL,
const TemplateArgumentListInfo &Args);
- /// Computes whether an unresolved lookup on the given declarations
- /// and optional template arguments is type- and value-dependent.
- static bool ComputeDependence(UnresolvedSetImpl::const_iterator Begin,
- UnresolvedSetImpl::const_iterator End,
- const TemplateArgumentListInfo *Args);
-
- void addDecl(NamedDecl *Decl) {
- Results.addDecl(Decl);
- }
-
- typedef UnresolvedSetImpl::iterator decls_iterator;
- decls_iterator decls_begin() const { return Results.begin(); }
- decls_iterator decls_end() const { return Results.end(); }
-
/// True if this declaration should be extended by
/// argument-dependent lookup.
bool requiresADL() const { return RequiresADL; }
@@ -1152,25 +1315,20 @@ public:
/// True if this lookup is overloaded.
bool isOverloaded() const { return Overloaded; }
- /// Fetches the name looked up.
- DeclarationName getName() const { return Name; }
-
- /// Gets the location of the name.
- SourceLocation getNameLoc() const { return NameLoc; }
-
- /// Fetches the nested-name qualifier, if one was given.
- NestedNameSpecifier *getQualifier() const { return Qualifier; }
-
- /// Fetches the range of the nested-name qualifier.
- SourceRange getQualifierRange() const { return QualifierRange; }
-
- /// Determines whether this lookup had explicit template arguments.
- bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
+ /// 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; }
// Note that, inconsistently with the explicit-template-argument AST
// nodes, users are *forbidden* from calling these methods on objects
// without explicit template arguments.
+ ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ assert(hasExplicitTemplateArgs());
+ return *reinterpret_cast<ExplicitTemplateArgumentList*>(this + 1);
+ }
+
/// Gets a reference to the explicit template argument list.
const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
assert(hasExplicitTemplateArgs());
@@ -1200,8 +1358,8 @@ public:
}
virtual SourceRange getSourceRange() const {
- SourceRange Range(NameLoc);
- if (Qualifier) Range.setBegin(QualifierRange.getBegin());
+ SourceRange Range(getNameLoc());
+ if (getQualifier()) Range.setBegin(getQualifierRange().getBegin());
if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc());
return Range;
}
@@ -1456,11 +1614,24 @@ public:
arg_iterator arg_begin() { return reinterpret_cast<Expr**>(this + 1); }
arg_iterator arg_end() { return arg_begin() + NumArgs; }
+ typedef const Expr* const * const_arg_iterator;
+ const_arg_iterator arg_begin() const {
+ return reinterpret_cast<const Expr* const *>(this + 1);
+ }
+ const_arg_iterator arg_end() const {
+ return arg_begin() + NumArgs;
+ }
+
Expr *getArg(unsigned I) {
assert(I < NumArgs && "Argument index out-of-range");
return *(arg_begin() + I);
}
+ const Expr *getArg(unsigned I) const {
+ assert(I < NumArgs && "Argument index out-of-range");
+ return *(arg_begin() + I);
+ }
+
virtual SourceRange getSourceRange() const {
return SourceRange(TyBeginLoc, RParenLoc);
}
@@ -1713,19 +1884,7 @@ public:
/// In the final AST, an explicit access always becomes a MemberExpr.
/// An implicit access may become either a MemberExpr or a
/// DeclRefExpr, depending on whether the member is static.
-class UnresolvedMemberExpr : public Expr {
- /// The results. These are undesugared, which is to say, they may
- /// include UsingShadowDecls.
- UnresolvedSet<4> Results;
-
- /// \brief The expression for the base pointer or class reference,
- /// e.g., the \c x in x.f. This can be null if this is an 'unbased'
- /// member expression
- Stmt *Base;
-
- /// \brief The type of the base expression; never null.
- QualType BaseType;
-
+class UnresolvedMemberExpr : public OverloadExpr {
/// \brief Whether this member expression used the '->' operator or
/// the '.' operator.
bool IsArrow : 1;
@@ -1734,39 +1893,17 @@ class UnresolvedMemberExpr : public Expr {
/// declaration.
bool HasUnresolvedUsing : 1;
- /// \brief Whether this member expression has explicitly-specified template
- /// arguments.
- bool HasExplicitTemplateArgs : 1;
+ /// \brief The expression for the base pointer or class reference,
+ /// e.g., the \c x in x.f. This can be null if this is an 'unbased'
+ /// member expression
+ Stmt *Base;
+
+ /// \brief The type of the base expression; never null.
+ QualType BaseType;
/// \brief The location of the '->' or '.' operator.
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;
-
- /// \brief The member to which this member expression refers, which
- /// can be a name or an overloaded operator.
- DeclarationName MemberName;
-
- /// \brief The location of the member name.
- SourceLocation MemberLoc;
-
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name.
- ExplicitTemplateArgumentList *getExplicitTemplateArgs() {
- assert(HasExplicitTemplateArgs);
- return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
- }
-
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name, if any.
- const ExplicitTemplateArgumentList *getExplicitTemplateArgs() const {
- return const_cast<UnresolvedMemberExpr*>(this)->getExplicitTemplateArgs();
- }
-
UnresolvedMemberExpr(QualType T, bool Dependent,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
@@ -1788,19 +1925,6 @@ public:
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs);
- /// Adds a declaration to the unresolved set. By assumption, all of
- /// these happen at initialization time and properties like
- /// 'Dependent' and 'HasUnresolvedUsing' take them into account.
- void addDecl(NamedDecl *Decl) {
- Results.addDecl(Decl);
- }
-
- typedef UnresolvedSetImpl::iterator decls_iterator;
- decls_iterator decls_begin() const { return Results.begin(); }
- decls_iterator decls_end() const { return Results.end(); }
-
- unsigned getNumDecls() const { return Results.size(); }
-
/// \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.
@@ -1812,6 +1936,10 @@ public:
assert(!isImplicitAccess());
return cast<Expr>(Base);
}
+ const Expr *getBase() const {
+ assert(!isImplicitAccess());
+ return cast<Expr>(Base);
+ }
void setBase(Expr *E) { Base = E; }
QualType getBaseType() const { return BaseType; }
@@ -1825,57 +1953,60 @@ public:
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; }
-
- /// \brief Retrieve the source range covering the nested-name-specifier
- /// that qualifies the member name.
- SourceRange getQualifierRange() const { return QualifierRange; }
+ /// \brief Retrieves the naming class of this lookup.
+ CXXRecordDecl *getNamingClass() const;
/// \brief Retrieve the name of the member that this expression
/// refers to.
- DeclarationName getMemberName() const { return MemberName; }
- void setMemberName(DeclarationName N) { MemberName = N; }
+ 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 MemberLoc; }
- void setMemberLoc(SourceLocation L) { MemberLoc = L; }
+ SourceLocation getMemberLoc() const { return getNameLoc(); }
+ void setMemberLoc(SourceLocation L) { setNameLoc(L); }
- /// \brief Determines whether this member expression actually had a C++
- /// template argument list explicitly specified, e.g., x.f<int>.
- bool hasExplicitTemplateArgs() const {
- return HasExplicitTemplateArgs;
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name.
+ ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
+ assert(hasExplicitTemplateArgs());
+ return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+ }
+
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name, if any.
+ const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ assert(hasExplicitTemplateArgs());
+ return *reinterpret_cast<const ExplicitTemplateArgumentList *>(this + 1);
}
/// \brief Copies the template arguments into the given structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
- getExplicitTemplateArgs()->copyInto(List);
+ getExplicitTemplateArgs().copyInto(List);
}
/// \brief Retrieve the location of the left angle bracket following
/// the member name ('<').
SourceLocation getLAngleLoc() const {
- return getExplicitTemplateArgs()->LAngleLoc;
+ return getExplicitTemplateArgs().LAngleLoc;
}
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
- return getExplicitTemplateArgs()->getTemplateArgs();
+ return getExplicitTemplateArgs().getTemplateArgs();
}
/// \brief Retrieve the number of template arguments provided as
/// part of this template-id.
unsigned getNumTemplateArgs() const {
- return getExplicitTemplateArgs()->NumTemplateArgs;
+ return getExplicitTemplateArgs().NumTemplateArgs;
}
/// \brief Retrieve the location of the right angle bracket
/// following the template arguments ('>').
SourceLocation getRAngleLoc() const {
- return getExplicitTemplateArgs()->RAngleLoc;
+ return getExplicitTemplateArgs().RAngleLoc;
}
virtual SourceRange getSourceRange() const {
@@ -1885,12 +2016,12 @@ public:
else if (getQualifier())
Range.setBegin(getQualifierRange().getBegin());
else
- Range.setBegin(MemberLoc);
+ Range.setBegin(getMemberLoc());
if (hasExplicitTemplateArgs())
Range.setEnd(getRAngleLoc());
else
- Range.setEnd(MemberLoc);
+ Range.setEnd(getMemberLoc());
return Range;
}
@@ -1904,6 +2035,13 @@ public:
virtual child_iterator child_end();
};
+inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() {
+ if (isa<UnresolvedLookupExpr>(this))
+ return cast<UnresolvedLookupExpr>(this)->getExplicitTemplateArgs();
+ else
+ return cast<UnresolvedMemberExpr>(this)->getExplicitTemplateArgs();
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 0b0cd64ad721..df39b535eb3e 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -367,7 +367,7 @@ class ObjCMessageExpr : public Expr {
public:
/// This constructor is used to represent class messages where the
/// ObjCInterfaceDecl* of the receiver is not known.
- ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
+ ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, Selector selInfo,
QualType retType, ObjCMethodDecl *methDecl,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned NumArgs);
@@ -375,13 +375,13 @@ public:
/// This constructor is used to represent class messages where the
/// ObjCInterfaceDecl* of the receiver is known.
// FIXME: clsName should be typed to ObjCInterfaceType
- ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
+ ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, Selector selInfo,
QualType retType, ObjCMethodDecl *methDecl,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned NumArgs);
// constructor for instance messages.
- ObjCMessageExpr(Expr *receiver, Selector selInfo,
+ ObjCMessageExpr(ASTContext &C, Expr *receiver, Selector selInfo,
QualType retType, ObjCMethodDecl *methDecl,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned NumArgs);
@@ -389,9 +389,7 @@ public:
explicit ObjCMessageExpr(EmptyShell Empty)
: Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {}
- ~ObjCMessageExpr() {
- delete [] SubExprs;
- }
+ virtual void DoDestroy(ASTContext &C);
/// getReceiver - Returns the receiver of the message expression.
/// This can be NULL if the message is for class methods. For
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index d058f838a008..94caa6faad66 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -102,6 +102,7 @@ public:
#define LAST_STMT(CLASS) lastStmtConstant = CLASS##Class,
#define FIRST_EXPR(CLASS) firstExprConstant = CLASS##Class,
#define LAST_EXPR(CLASS) lastExprConstant = CLASS##Class
+#define ABSTRACT_EXPR(CLASS, PARENT)
#include "clang/AST/StmtNodes.def"
};
private:
@@ -1120,21 +1121,27 @@ class AsmStmt : public Stmt {
unsigned NumOutputs;
unsigned NumInputs;
+ unsigned NumClobbers;
- llvm::SmallVector<std::string, 4> Names;
- llvm::SmallVector<StringLiteral*, 4> Constraints;
- llvm::SmallVector<Stmt*, 4> Exprs;
+ // FIXME: If we wanted to, we could allocate all of these in one big array.
+ IdentifierInfo **Names;
+ StringLiteral **Constraints;
+ Stmt **Exprs;
+ StringLiteral **Clobbers;
- llvm::SmallVector<StringLiteral*, 4> Clobbers;
+protected:
+ virtual void DoDestroy(ASTContext &Ctx);
+
public:
- AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, bool msasm,
- unsigned numoutputs, unsigned numinputs,
- std::string *names, StringLiteral **constraints,
+ AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
+ bool msasm, unsigned numoutputs, unsigned numinputs,
+ IdentifierInfo **names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc);
/// \brief Build an empty inline-assembly statement.
- explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty) { }
+ explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
+ Names(0), Constraints(0), Exprs(0), Clobbers(0) { }
SourceLocation getAsmLoc() const { return AsmLoc; }
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
@@ -1208,14 +1215,21 @@ public:
unsigned getNumOutputs() const { return NumOutputs; }
- const std::string &getOutputName(unsigned i) const {
+ IdentifierInfo *getOutputIdentifier(unsigned i) const {
return Names[i];
}
+ llvm::StringRef getOutputName(unsigned i) const {
+ if (IdentifierInfo *II = getOutputIdentifier(i))
+ return II->getName();
+
+ return llvm::StringRef();
+ }
+
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
- std::string getOutputConstraint(unsigned i) const;
+ llvm::StringRef getOutputConstraint(unsigned i) const;
const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
return Constraints[i];
@@ -1224,7 +1238,6 @@ public:
return Constraints[i];
}
-
Expr *getOutputExpr(unsigned i);
const Expr *getOutputExpr(unsigned i) const {
@@ -1246,13 +1259,20 @@ public:
unsigned getNumInputs() const { return NumInputs; }
- const std::string &getInputName(unsigned i) const {
+ IdentifierInfo *getInputIdentifier(unsigned i) const {
return Names[i + NumOutputs];
}
+ llvm::StringRef getInputName(unsigned i) const {
+ if (IdentifierInfo *II = getInputIdentifier(i))
+ return II->getName();
+
+ return llvm::StringRef();
+ }
+
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
- std::string getInputConstraint(unsigned i) const;
+ llvm::StringRef getInputConstraint(unsigned i) const;
const StringLiteral *getInputConstraintLiteral(unsigned i) const {
return Constraints[i + NumOutputs];
@@ -1261,32 +1281,31 @@ public:
return Constraints[i + NumOutputs];
}
-
Expr *getInputExpr(unsigned i);
const Expr *getInputExpr(unsigned i) const {
return const_cast<AsmStmt*>(this)->getInputExpr(i);
}
- void setOutputsAndInputs(unsigned NumOutputs,
- unsigned NumInputs,
- const std::string *Names,
- StringLiteral **Constraints,
- Stmt **Exprs);
+ void setOutputsAndInputsAndClobbers(ASTContext &C,
+ IdentifierInfo **Names,
+ StringLiteral **Constraints,
+ Stmt **Exprs,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ StringLiteral **Clobbers,
+ unsigned NumClobbers);
//===--- Other ---===//
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
- int getNamedOperand(const std::string &SymbolicName) const;
-
+ int getNamedOperand(llvm::StringRef SymbolicName) const;
-
- unsigned getNumClobbers() const { return Clobbers.size(); }
+ unsigned getNumClobbers() const { return NumClobbers; }
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
- void setClobbers(StringLiteral **Clobbers, unsigned NumClobbers);
virtual SourceRange getSourceRange() const {
return SourceRange(AsmLoc, RParenLoc);
@@ -1301,19 +1320,19 @@ public:
typedef ConstExprIterator const_inputs_iterator;
inputs_iterator begin_inputs() {
- return Exprs.data() + NumOutputs;
+ return &Exprs[0] + NumOutputs;
}
inputs_iterator end_inputs() {
- return Exprs.data() + NumOutputs + NumInputs;
+ return &Exprs[0] + NumOutputs + NumInputs;
}
const_inputs_iterator begin_inputs() const {
- return Exprs.data() + NumOutputs;
+ return &Exprs[0] + NumOutputs;
}
const_inputs_iterator end_inputs() const {
- return Exprs.data() + NumOutputs + NumInputs;
+ return &Exprs[0] + NumOutputs + NumInputs;
}
// Output expr iterators.
@@ -1322,27 +1341,17 @@ public:
typedef ConstExprIterator const_outputs_iterator;
outputs_iterator begin_outputs() {
- return Exprs.data();
+ return &Exprs[0];
}
outputs_iterator end_outputs() {
- return Exprs.data() + NumOutputs;
+ return &Exprs[0] + NumOutputs;
}
const_outputs_iterator begin_outputs() const {
- return Exprs.data();
+ return &Exprs[0];
}
const_outputs_iterator end_outputs() const {
- return Exprs.data() + NumOutputs;
- }
-
- // Input name iterator.
-
- const std::string *begin_output_names() const {
- return &Names[0];
- }
-
- const std::string *end_output_names() const {
- return &Names[0] + NumOutputs;
+ return &Exprs[0] + NumOutputs;
}
// Child iterators
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 09ea4ca2101b..4e87c2701c26 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -59,31 +59,42 @@ public:
///
class CXXTryStmt : public Stmt {
SourceLocation TryLoc;
- // First place is the guarded CompoundStatement. Subsequent are the handlers.
- // More than three handlers should be rare.
- llvm::SmallVector<Stmt*, 4> Stmts;
+ unsigned NumHandlers;
+
+ CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, Stmt **handlers,
+ unsigned numHandlers);
public:
- CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
- Stmt **handlers, unsigned numHandlers);
+ static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc,
+ Stmt *tryBlock, Stmt **handlers,
+ unsigned numHandlers);
virtual SourceRange getSourceRange() const {
return SourceRange(getTryLoc(), getEndLoc());
}
SourceLocation getTryLoc() const { return TryLoc; }
- SourceLocation getEndLoc() const { return Stmts.back()->getLocEnd(); }
+ SourceLocation getEndLoc() const {
+ Stmt const * const*Stmts = reinterpret_cast<Stmt const * const*>(this + 1);
+ return Stmts[NumHandlers]->getLocEnd();
+ }
- CompoundStmt *getTryBlock() { return llvm::cast<CompoundStmt>(Stmts[0]); }
+ CompoundStmt *getTryBlock() {
+ Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
+ return llvm::cast<CompoundStmt>(Stmts[0]);
+ }
const CompoundStmt *getTryBlock() const {
+ Stmt const * const*Stmts = reinterpret_cast<Stmt const * const*>(this + 1);
return llvm::cast<CompoundStmt>(Stmts[0]);
}
- unsigned getNumHandlers() const { return Stmts.size() - 1; }
+ unsigned getNumHandlers() const { return NumHandlers; }
CXXCatchStmt *getHandler(unsigned i) {
+ Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
return llvm::cast<CXXCatchStmt>(Stmts[i + 1]);
}
const CXXCatchStmt *getHandler(unsigned i) const {
+ Stmt const * const*Stmts = reinterpret_cast<Stmt const * const*>(this + 1);
return llvm::cast<CXXCatchStmt>(Stmts[i + 1]);
}
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index 7102336180cf..ec6149e55f11 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -68,8 +68,7 @@ STMT(CXXTryStmt , Stmt)
LAST_STMT(CXXTryStmt)
// Expressions.
-ABSTRACT_EXPR(Expr , Stmt)
-FIRST_EXPR(Expr)
+ABSTRACT_EXPR(Expr , Stmt)
EXPR(PredefinedExpr , Expr)
EXPR(DeclRefExpr , Expr)
EXPR(IntegerLiteral , Expr)
@@ -83,12 +82,12 @@ EXPR(SizeOfAlignOfExpr , Expr)
EXPR(ArraySubscriptExpr , Expr)
EXPR(CallExpr , Expr)
EXPR(MemberExpr , Expr)
-EXPR(CastExpr , Expr)
+ABSTRACT_EXPR(CastExpr , Expr)
EXPR(BinaryOperator , Expr)
EXPR(CompoundAssignOperator, BinaryOperator)
EXPR(ConditionalOperator , Expr)
EXPR(ImplicitCastExpr , CastExpr)
-EXPR(ExplicitCastExpr , CastExpr)
+ABSTRACT_EXPR(ExplicitCastExpr, CastExpr)
EXPR(CStyleCastExpr , ExplicitCastExpr)
EXPR(CompoundLiteralExpr , Expr)
EXPR(ExtVectorElementExpr , Expr)
@@ -129,6 +128,7 @@ EXPR(UnaryTypeTraitExpr , Expr)
EXPR(DependentScopeDeclRefExpr , Expr)
EXPR(CXXConstructExpr , Expr)
EXPR(CXXBindTemporaryExpr , Expr)
+EXPR(CXXBindReferenceExpr , Expr)
EXPR(CXXExprWithTemporaries , Expr)
EXPR(CXXTemporaryObjectExpr , CXXConstructExpr)
EXPR(CXXUnresolvedConstructExpr, Expr)
@@ -152,6 +152,7 @@ EXPR(ShuffleVectorExpr , Expr)
EXPR(BlockExpr , Expr)
EXPR(BlockDeclRefExpr , Expr)
+FIRST_EXPR(PredefinedExpr)
LAST_EXPR(BlockDeclRefExpr)
#undef ABSTRACT_EXPR
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index 3a525507dad3..4986f08ac124 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -105,6 +105,7 @@ public:
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
switch (S->getStmtClass()) {
default: assert(0 && "Unknown stmt kind!");
+#define ABSTRACT_EXPR(CLASS, PARENT)
#define STMT(CLASS, PARENT) \
case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
#include "clang/AST/StmtNodes.def"
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index b7b60df5acb4..40e50988e6d2 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -16,6 +16,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Linkage.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/Casting.h"
@@ -750,24 +751,22 @@ class Type {
public:
enum TypeClass {
#define TYPE(Class, Base) Class,
+#define LAST_TYPE(Class) TypeLast = Class,
#define ABSTRACT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
TagFirst = Record, TagLast = Enum
};
-protected:
- enum { TypeClassBitSize = 6 };
-
private:
QualType CanonicalType;
- /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]).
- bool Dependent : 1;
-
/// TypeClass bitfield - Enum that specifies what subclass this belongs to.
+ unsigned TC : 8;
+
+ /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]).
/// Note that this should stay at the end of the ivars for Type so that
/// subclasses can pack their bitfields into the same word.
- unsigned TC : TypeClassBitSize;
+ bool Dependent : 1;
Type(const Type&); // DO NOT IMPLEMENT.
void operator=(const Type&); // DO NOT IMPLEMENT.
@@ -776,7 +775,7 @@ protected:
Type *this_() { return this; }
Type(TypeClass tc, QualType Canonical, bool dependent)
: CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical),
- Dependent(dependent), TC(tc) {}
+ TC(tc), Dependent(dependent) {}
virtual ~Type() {}
virtual void Destroy(ASTContext& C);
friend class ASTContext;
@@ -974,6 +973,9 @@ public:
const char *getTypeClassName() const;
+ /// \brief Determine the linkage of this type.
+ virtual Linkage getLinkage() const;
+
QualType getCanonicalTypeInternal() const { return CanonicalType; }
void dump() const;
static bool classof(const Type *) { return true; }
@@ -1062,6 +1064,8 @@ public:
return TypeKind >= Float && TypeKind <= LongDouble;
}
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
static bool classof(const BuiltinType *) { return true; }
};
@@ -1089,6 +1093,8 @@ public:
ID.AddPointer(Element.getAsOpaquePtr());
}
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
static bool classof(const ComplexType *) { return true; }
};
@@ -1116,6 +1122,8 @@ public:
ID.AddPointer(Pointee.getAsOpaquePtr());
}
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
static bool classof(const PointerType *) { return true; }
};
@@ -1146,6 +1154,8 @@ public:
ID.AddPointer(Pointee.getAsOpaquePtr());
}
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == BlockPointer;
}
@@ -1183,7 +1193,8 @@ protected:
}
public:
bool isSpelledAsLValue() const { return SpelledAsLValue; }
-
+ bool isInnerRef() const { return InnerRef; }
+
QualType getPointeeTypeAsWritten() const { return PointeeType; }
QualType getPointeeType() const {
// FIXME: this might strip inner qualifiers; okay?
@@ -1203,6 +1214,8 @@ public:
ID.AddBoolean(SpelledAsLValue);
}
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == LValueReference ||
T->getTypeClass() == RValueReference;
@@ -1277,6 +1290,8 @@ public:
ID.AddPointer(Class);
}
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == MemberPointer;
}
@@ -1328,6 +1343,8 @@ public:
}
unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; }
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray ||
T->getTypeClass() == VariableArray ||
@@ -1576,7 +1593,8 @@ public:
/// VectorType - GCC generic vector type. This type is created using
/// __attribute__((vector_size(n)), where "n" specifies the vector size in
-/// bytes. Since the constructor takes the number of vector elements, the
+/// bytes; or from an Altivec __vector or vector declaration.
+/// Since the constructor takes the number of vector elements, the
/// client is responsible for converting the size into the number of elements.
class VectorType : public Type, public llvm::FoldingSetNode {
protected:
@@ -1586,13 +1604,21 @@ protected:
/// NumElements - The number of elements in the vector.
unsigned NumElements;
- VectorType(QualType vecType, unsigned nElements, QualType canonType) :
+ /// AltiVec - True if this is for an Altivec vector.
+ bool AltiVec;
+
+ /// Pixel - True if this is for an Altivec vector pixel.
+ bool Pixel;
+
+ VectorType(QualType vecType, unsigned nElements, QualType canonType,
+ bool isAltiVec, bool isPixel) :
Type(Vector, canonType, vecType->isDependentType()),
- ElementType(vecType), NumElements(nElements) {}
+ ElementType(vecType), NumElements(nElements),
+ AltiVec(isAltiVec), Pixel(isPixel) {}
VectorType(TypeClass tc, QualType vecType, unsigned nElements,
- QualType canonType)
+ QualType canonType, bool isAltiVec, bool isPixel)
: Type(tc, canonType, vecType->isDependentType()), ElementType(vecType),
- NumElements(nElements) {}
+ NumElements(nElements), AltiVec(isAltiVec), Pixel(isPixel) {}
friend class ASTContext; // ASTContext creates these.
public:
@@ -1602,15 +1628,26 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
+ bool isAltiVec() const { return AltiVec; }
+
+ bool isPixel() const { return Pixel; }
+
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), getNumElements(), getTypeClass());
+ Profile(ID, getElementType(), getNumElements(), getTypeClass(),
+ AltiVec, Pixel);
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType,
- unsigned NumElements, TypeClass TypeClass) {
+ unsigned NumElements, TypeClass TypeClass,
+ bool isAltiVec, bool isPixel) {
ID.AddPointer(ElementType.getAsOpaquePtr());
ID.AddInteger(NumElements);
ID.AddInteger(TypeClass);
+ ID.AddBoolean(isAltiVec);
+ ID.AddBoolean(isPixel);
}
+
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
}
@@ -1624,7 +1661,7 @@ public:
/// points, colors, and textures (modeled after OpenGL Shading Language).
class ExtVectorType : public VectorType {
ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) :
- VectorType(ExtVector, vecType, nElements, canonType) {}
+ VectorType(ExtVector, vecType, nElements, canonType, false, false) {}
friend class ASTContext; // ASTContext creates these.
public:
static int getPointAccessorIdx(char c) {
@@ -1723,6 +1760,8 @@ public:
bool getNoReturnAttr() const { return NoReturn; }
CallingConv getCallConv() const { return (CallingConv)CallConv; }
+ static llvm::StringRef getNameForCallConv(CallingConv CC);
+
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto ||
T->getTypeClass() == FunctionProto;
@@ -1745,14 +1784,17 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getResultType(), getNoReturnAttr());
+ Profile(ID, getResultType(), getNoReturnAttr(), getCallConv());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
- bool NoReturn) {
+ bool NoReturn, CallingConv CallConv) {
+ ID.AddInteger(CallConv);
ID.AddInteger(NoReturn);
ID.AddPointer(ResultType.getAsOpaquePtr());
}
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto;
}
@@ -1856,6 +1898,8 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionProto;
}
@@ -1867,7 +1911,7 @@ public:
bool isVariadic, unsigned TypeQuals,
bool hasExceptionSpec, bool anyExceptionSpec,
unsigned NumExceptions, exception_iterator Exs,
- bool NoReturn);
+ bool NoReturn, CallingConv CallConv);
};
@@ -1878,8 +1922,9 @@ public:
class UnresolvedUsingType : public Type {
UnresolvedUsingTypenameDecl *Decl;
- UnresolvedUsingType(UnresolvedUsingTypenameDecl *D)
- : Type(UnresolvedUsing, QualType(), true), Decl(D) {}
+ UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D)
+ : Type(UnresolvedUsing, QualType(), true),
+ Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {}
friend class ASTContext; // ASTContext creates these.
public:
@@ -1906,8 +1951,9 @@ public:
class TypedefType : public Type {
TypedefDecl *Decl;
protected:
- TypedefType(TypeClass tc, TypedefDecl *D, QualType can)
- : Type(tc, can, can->isDependentType()), Decl(D) {
+ TypedefType(TypeClass tc, const TypedefDecl *D, QualType can)
+ : Type(tc, can, can->isDependentType()),
+ Decl(const_cast<TypedefDecl*>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
friend class ASTContext; // ASTContext creates these.
@@ -1950,8 +1996,12 @@ public:
static bool classof(const TypeOfExprType *) { return true; }
};
-/// Subclass of TypeOfExprType that is used for canonical, dependent
+/// \brief Internal representation of canonical, dependent
/// typeof(expr) types.
+///
+/// This class is used internally by the ASTContext to manage
+/// canonical, dependent types, only. Clients will only see instances
+/// of this class via TypeOfExprType nodes.
class DependentTypeOfExprType
: public TypeOfExprType, public llvm::FoldingSetNode {
ASTContext &Context;
@@ -2018,8 +2068,12 @@ public:
static bool classof(const DecltypeType *) { return true; }
};
-/// Subclass of DecltypeType that is used for canonical, dependent
-/// C++0x decltype types.
+/// \brief Internal representation of canonical, dependent
+/// decltype(expr) types.
+///
+/// This class is used internally by the ASTContext to manage
+/// canonical, dependent types, only. Clients will only see instances
+/// of this class via DecltypeType nodes.
class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
ASTContext &Context;
@@ -2048,7 +2102,7 @@ class TagType : public Type {
friend class TagDecl;
protected:
- TagType(TypeClass TC, TagDecl *D, QualType can);
+ TagType(TypeClass TC, const TagDecl *D, QualType can);
public:
TagDecl *getDecl() const { return decl.getPointer(); }
@@ -2058,6 +2112,8 @@ public:
bool isBeingDefined() const { return decl.getInt(); }
void setBeingDefined(bool Def) const { decl.setInt(Def? 1 : 0); }
+ virtual Linkage getLinkage() const;
+
static bool classof(const Type *T) {
return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
}
@@ -2070,10 +2126,10 @@ public:
/// to detect TagType objects of structs/unions/classes.
class RecordType : public TagType {
protected:
- explicit RecordType(RecordDecl *D)
- : TagType(Record, reinterpret_cast<TagDecl*>(D), QualType()) { }
+ explicit RecordType(const RecordDecl *D)
+ : TagType(Record, reinterpret_cast<const TagDecl*>(D), QualType()) { }
explicit RecordType(TypeClass TC, RecordDecl *D)
- : TagType(TC, reinterpret_cast<TagDecl*>(D), QualType()) { }
+ : TagType(TC, reinterpret_cast<const TagDecl*>(D), QualType()) { }
friend class ASTContext; // ASTContext creates these.
public:
@@ -2103,8 +2159,8 @@ public:
/// EnumType - This is a helper class that allows the use of isa/cast/dyncast
/// to detect TagType objects of enums.
class EnumType : public TagType {
- explicit EnumType(EnumDecl *D)
- : TagType(Enum, reinterpret_cast<TagDecl*>(D), QualType()) { }
+ explicit EnumType(const EnumDecl *D)
+ : TagType(Enum, reinterpret_cast<const TagDecl*>(D), QualType()) { }
friend class ASTContext; // ASTContext creates these.
public:
@@ -2512,12 +2568,12 @@ public:
class ObjCInterfaceType : public Type, public llvm::FoldingSetNode {
ObjCInterfaceDecl *Decl;
- // List of protocols for this protocol conforming object type
- // List is sorted on protocol name. No protocol is enterred more than once.
- ObjCProtocolDecl **Protocols;
+ /// \brief The number of protocols stored after the ObjCInterfaceType node.
+ /// The list of protocols is sorted on protocol name. No protocol is enterred
+ /// more than once.
unsigned NumProtocols;
- ObjCInterfaceType(ASTContext &Ctx, QualType Canonical, ObjCInterfaceDecl *D,
+ ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D,
ObjCProtocolDecl **Protos, unsigned NumP);
friend class ASTContext; // ASTContext creates these.
public:
@@ -2529,14 +2585,20 @@ public:
/// interface type, or 0 if there are none.
unsigned getNumProtocols() const { return NumProtocols; }
+ /// \brief Retrieve the Ith protocol.
+ ObjCProtocolDecl *getProtocol(unsigned I) const {
+ assert(I < getNumProtocols() && "Out-of-range protocol access");
+ return qual_begin()[I];
+ }
+
/// qual_iterator and friends: this provides access to the (potentially empty)
/// list of protocols qualifying this interface.
typedef ObjCProtocolDecl* const * qual_iterator;
qual_iterator qual_begin() const {
- return Protocols;
+ return reinterpret_cast<qual_iterator>(this + 1);
}
qual_iterator qual_end() const {
- return Protocols ? Protocols + NumProtocols : 0;
+ return qual_begin() + NumProtocols;
}
bool qual_empty() const { return NumProtocols == 0; }
@@ -2546,7 +2608,10 @@ public:
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **protocols, unsigned NumProtocols);
+ ObjCProtocolDecl * const *protocols,
+ unsigned NumProtocols);
+
+ virtual Linkage getLinkage() const;
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCInterface;
@@ -2562,12 +2627,14 @@ public:
class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
QualType PointeeType; // A builtin or interface type.
- // List of protocols for this protocol conforming object type
- // List is sorted on protocol name. No protocol is entered more than once.
- ObjCProtocolDecl **Protocols;
+ /// \brief The number of protocols stored after the ObjCObjectPointerType
+ /// node.
+ ///
+ /// The list of protocols is sorted on protocol name. No protocol is enterred
+ /// more than once.
unsigned NumProtocols;
- ObjCObjectPointerType(ASTContext &Ctx, QualType Canonical, QualType T,
+ ObjCObjectPointerType(QualType Canonical, QualType T,
ObjCProtocolDecl **Protos, unsigned NumP);
friend class ASTContext; // ASTContext creates these.
@@ -2614,10 +2681,10 @@ public:
typedef ObjCProtocolDecl* const * qual_iterator;
qual_iterator qual_begin() const {
- return Protocols;
+ return reinterpret_cast<qual_iterator> (this + 1);
}
qual_iterator qual_end() const {
- return Protocols ? Protocols + NumProtocols : NULL;
+ return qual_begin() + NumProtocols;
}
bool qual_empty() const { return NumProtocols == 0; }
@@ -2625,12 +2692,21 @@ public:
/// interface type, or 0 if there are none.
unsigned getNumProtocols() const { return NumProtocols; }
+ /// \brief Retrieve the Ith protocol.
+ ObjCProtocolDecl *getProtocol(unsigned I) const {
+ assert(I < getNumProtocols() && "Out-of-range protocol access");
+ return qual_begin()[I];
+ }
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
+ virtual Linkage getLinkage() const;
+
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID, QualType T,
- ObjCProtocolDecl **protocols, unsigned NumProtocols);
+ ObjCProtocolDecl *const *protocols,
+ unsigned NumProtocols);
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCObjectPointer;
}
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 575011a8724c..9cf2cb7bd773 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -87,6 +87,11 @@ DEPENDENT_TYPE(Typename, Type)
TYPE(ObjCInterface, Type)
TYPE(ObjCObjectPointer, Type)
+#ifdef LAST_TYPE
+LAST_TYPE(ObjCObjectPointer)
+#undef LAST_TYPE
+#endif
+
// These types are always leaves in the type hierarchy.
#ifdef LEAF_TYPE
LEAF_TYPE(Enum)
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index 055d15264674..9c59229e3134 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -16,7 +16,6 @@
#define LLVM_CLANG_AST_UNRESOLVEDSET_H
#include <iterator>
-#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/Specifiers.h"
@@ -24,12 +23,58 @@ namespace clang {
class NamedDecl;
+/// A POD class for pairing a NamedDecl* with an access specifier.
+/// Can be put into unions.
+class DeclAccessPair {
+ NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
+
+ enum { Mask = 0x3 };
+
+public:
+ static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
+ DeclAccessPair p;
+ p.set(D, AS);
+ return p;
+ }
+
+ NamedDecl *getDecl() const {
+ return (NamedDecl*) (~Mask & (uintptr_t) Ptr);
+ }
+ AccessSpecifier getAccess() const {
+ return AccessSpecifier(Mask & (uintptr_t) Ptr);
+ }
+
+ void setDecl(NamedDecl *D) {
+ set(D, getAccess());
+ }
+ void setAccess(AccessSpecifier AS) {
+ set(getDecl(), AS);
+ }
+ void set(NamedDecl *D, AccessSpecifier AS) {
+ Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) |
+ reinterpret_cast<uintptr_t>(D));
+ }
+
+ operator NamedDecl*() const { return getDecl(); }
+ NamedDecl *operator->() const { return getDecl(); }
+};
+}
+
+// Take a moment to tell SmallVector that this is POD.
+namespace llvm {
+template<typename> struct isPodLike;
+template<> struct isPodLike<clang::DeclAccessPair> {
+ static const bool value = true;
+};
+}
+
+namespace clang {
+
/// The iterator over UnresolvedSets. Serves as both the const and
/// non-const iterator.
class UnresolvedSetIterator {
-
- typedef llvm::PointerIntPair<NamedDecl*, 2> DeclEntry;
- typedef llvm::SmallVectorImpl<DeclEntry> DeclsTy;
+private:
+ typedef llvm::SmallVectorImpl<DeclAccessPair> DeclsTy;
typedef DeclsTy::iterator IteratorTy;
IteratorTy ir;
@@ -47,8 +92,8 @@ public:
typedef NamedDecl *reference;
typedef std::iterator_traits<IteratorTy>::iterator_category iterator_category;
- NamedDecl *getDecl() const { return ir->getPointer(); }
- AccessSpecifier getAccess() const { return AccessSpecifier(ir->getInt()); }
+ NamedDecl *getDecl() const { return ir->getDecl(); }
+ AccessSpecifier getAccess() const { return ir->getAccess(); }
NamedDecl *operator*() const { return getDecl(); }
@@ -87,7 +132,6 @@ public:
/// in a lot of places, but isn't really worth breaking into its own
/// header right now.
class UnresolvedSetImpl {
- typedef UnresolvedSetIterator::DeclEntry DeclEntry;
typedef UnresolvedSetIterator::DeclsTy DeclsTy;
// Don't allow direct construction, and only permit subclassing by
@@ -114,7 +158,7 @@ public:
}
void addDecl(NamedDecl *D, AccessSpecifier AS) {
- decls().push_back(DeclEntry(D, AS));
+ decls().push_back(DeclAccessPair::make(D, AS));
}
/// Replaces the given declaration with the new one, once.
@@ -122,19 +166,24 @@ public:
/// \return true if the set changed
bool replace(const NamedDecl* Old, NamedDecl *New) {
for (DeclsTy::iterator I = decls().begin(), E = decls().end(); I != E; ++I)
- if (I->getPointer() == Old)
- return (I->setPointer(New), true);
+ if (I->getDecl() == Old)
+ return (I->setDecl(New), true);
return false;
}
/// Replaces the declaration at the given iterator with the new one,
/// preserving the original access bits.
void replace(iterator I, NamedDecl *New) {
- I.ir->setPointer(New);
+ I.ir->setDecl(New);
}
void replace(iterator I, NamedDecl *New, AccessSpecifier AS) {
- *I.ir = DeclEntry(New, AS);
+ I.ir->set(New, AS);
+ }
+
+ void erase(unsigned I) {
+ decls()[I] = decls().back();
+ decls().pop_back();
}
void erase(iterator I) {
@@ -142,6 +191,10 @@ public:
decls().pop_back();
}
+ void setAccess(iterator I, AccessSpecifier AS) {
+ I.ir->setAccess(AS);
+ }
+
void clear() { decls().clear(); }
void set_size(unsigned N) { decls().set_size(N); }
@@ -152,41 +205,8 @@ public:
decls().append(I.ir, E.ir);
}
- /// A proxy reference for implementing operator[].
- class Proxy {
- DeclEntry &Ref;
-
- friend class UnresolvedSetImpl;
- Proxy(DeclEntry &Ref) : Ref(Ref) {}
-
- public:
- NamedDecl *getDecl() const { return Ref.getPointer(); }
- void setDecl(NamedDecl *D) { Ref.setPointer(D); }
-
- AccessSpecifier getAccess() const { return AccessSpecifier(Ref.getInt()); }
- void setAccess(AccessSpecifier AS) const { Ref.setInt(AS); }
-
- NamedDecl* operator->() const { return getDecl(); }
- operator NamedDecl*() const { return getDecl(); }
- Proxy &operator=(const Proxy &D) { Ref = D.Ref; return *this; }
- };
- Proxy operator[](unsigned I) { return Proxy(decls()[I]); }
-
- /// A proxy reference for implementing operator[] const.
- class ConstProxy {
- const DeclEntry &Ref;
-
- friend class UnresolvedSetImpl;
- ConstProxy(const DeclEntry &Ref) : Ref(Ref) {}
-
- public:
- NamedDecl *getDecl() const { return Ref.getPointer(); }
- AccessSpecifier getAccess() const { return AccessSpecifier(Ref.getInt()); }
-
- NamedDecl *operator->() const { return getDecl(); }
- operator NamedDecl*() const { return getDecl(); }
- };
- ConstProxy operator[](unsigned I) const { return ConstProxy(decls()[I]); }
+ DeclAccessPair &operator[](unsigned I) { return decls()[I]; }
+ const DeclAccessPair &operator[](unsigned I) const { return decls()[I]; }
private:
// These work because the only permitted subclass is UnresolvedSetImpl
@@ -202,7 +222,7 @@ private:
/// A set of unresolved declarations
template <unsigned InlineCapacity> class UnresolvedSet :
public UnresolvedSetImpl {
- llvm::SmallVector<UnresolvedSetImpl::DeclEntry, InlineCapacity> Decls;
+ llvm::SmallVector<DeclAccessPair, InlineCapacity> Decls;
};
diff --git a/include/clang/Analysis/Analyses/PrintfFormatString.h b/include/clang/Analysis/Analyses/PrintfFormatString.h
new file mode 100644
index 000000000000..a4ad0b703708
--- /dev/null
+++ b/include/clang/Analysis/Analyses/PrintfFormatString.h
@@ -0,0 +1,279 @@
+//==- PrintfFormatStrings.h - Analysis of printf format strings --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handling of format string in printf and friends. The structure of format
+// strings for fprintf() are described in C99 7.19.6.1.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FPRINTF_FORMAT_H
+#define LLVM_CLANG_FPRINTF_FORMAT_H
+
+#include "clang/AST/CanonicalType.h"
+
+namespace clang {
+
+class ASTContext;
+
+namespace analyze_printf {
+
+class ArgTypeResult {
+public:
+ enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CStrTy,
+ WCStrTy };
+private:
+ const Kind K;
+ QualType T;
+ ArgTypeResult(bool) : K(InvalidTy) {}
+public:
+ ArgTypeResult(Kind k = UnknownTy) : K(k) {}
+ ArgTypeResult(QualType t) : K(SpecificTy), T(t) {}
+ ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {}
+
+ static ArgTypeResult Invalid() { return ArgTypeResult(true); }
+
+ bool isValid() const { return K != InvalidTy; }
+
+ const QualType *getSpecificType() const {
+ return K == SpecificTy ? &T : 0;
+ }
+
+ bool matchesType(ASTContext &C, QualType argTy) const;
+
+ bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
+
+ QualType getRepresentativeType(ASTContext &C) const;
+};
+
+class ConversionSpecifier {
+public:
+ enum Kind {
+ InvalidSpecifier = 0,
+ // C99 conversion specifiers.
+ dArg, // 'd'
+ iArg, // 'i',
+ oArg, // 'o',
+ uArg, // 'u',
+ xArg, // 'x',
+ XArg, // 'X',
+ fArg, // 'f',
+ FArg, // 'F',
+ eArg, // 'e',
+ EArg, // 'E',
+ gArg, // 'g',
+ GArg, // 'G',
+ aArg, // 'a',
+ AArg, // 'A',
+ IntAsCharArg, // 'c'
+ CStrArg, // 's'
+ VoidPtrArg, // 'p'
+ OutIntPtrArg, // 'n'
+ PercentArg, // '%'
+ // Objective-C specific specifiers.
+ ObjCObjArg, // '@'
+ // GlibC specific specifiers.
+ PrintErrno, // 'm'
+ // Specifier ranges.
+ IntArgBeg = dArg,
+ IntArgEnd = iArg,
+ UIntArgBeg = oArg,
+ UIntArgEnd = XArg,
+ DoubleArgBeg = fArg,
+ DoubleArgEnd = AArg,
+ C99Beg = IntArgBeg,
+ C99End = DoubleArgEnd,
+ ObjCBeg = ObjCObjArg,
+ ObjCEnd = ObjCObjArg
+ };
+
+ ConversionSpecifier()
+ : Position(0), kind(InvalidSpecifier) {}
+
+ ConversionSpecifier(const char *pos, Kind k)
+ : Position(pos), kind(k) {}
+
+ const char *getStart() const {
+ return Position;
+ }
+
+ llvm::StringRef getCharacters() const {
+ return llvm::StringRef(getStart(), getLength());
+ }
+
+ bool consumesDataArgument() const {
+ switch (kind) {
+ case PercentArg:
+ case PrintErrno:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
+ bool isIntArg() const { return kind >= dArg && kind <= iArg; }
+ bool isUIntArg() const { return kind >= oArg && kind <= XArg; }
+ bool isDoubleArg() const { return kind >= fArg && kind <= AArg; }
+ Kind getKind() const { return kind; }
+ unsigned getLength() const {
+ // Conversion specifiers currently only are represented by
+ // single characters, but we be flexible.
+ return 1;
+ }
+
+private:
+ const char *Position;
+ Kind kind;
+};
+
+enum LengthModifier {
+ None,
+ AsChar, // 'hh'
+ AsShort, // 'h'
+ AsLong, // 'l'
+ AsLongLong, // 'll', 'q' (BSD, deprecated)
+ AsIntMax, // 'j'
+ AsSizeT, // 'z'
+ AsPtrDiff, // 't'
+ AsLongDouble, // 'L'
+ AsWideChar = AsLong // for '%ls'
+};
+
+class OptionalAmount {
+public:
+ enum HowSpecified { NotSpecified, Constant, Arg };
+
+ OptionalAmount(HowSpecified h, const char *st)
+ : start(st), hs(h), amt(0) {}
+
+ OptionalAmount()
+ : start(0), hs(NotSpecified), amt(0) {}
+
+ OptionalAmount(unsigned i, const char *st)
+ : start(st), hs(Constant), amt(i) {}
+
+ HowSpecified getHowSpecified() const { return hs; }
+ bool hasDataArgument() const { return hs == Arg; }
+
+ unsigned getConstantAmount() const {
+ assert(hs == Constant);
+ return amt;
+ }
+
+ const char *getStart() const {
+ return start;
+ }
+
+ ArgTypeResult getArgType(ASTContext &Ctx) const;
+
+private:
+ const char *start;
+ HowSpecified hs;
+ unsigned amt;
+};
+
+class FormatSpecifier {
+ LengthModifier LM;
+ unsigned IsLeftJustified : 1;
+ unsigned HasPlusPrefix : 1;
+ unsigned HasSpacePrefix : 1;
+ unsigned HasAlternativeForm : 1;
+ unsigned HasLeadingZeroes : 1;
+ unsigned flags : 5;
+ ConversionSpecifier CS;
+ OptionalAmount FieldWidth;
+ OptionalAmount Precision;
+public:
+ FormatSpecifier() : LM(None),
+ IsLeftJustified(0), HasPlusPrefix(0), HasSpacePrefix(0),
+ HasAlternativeForm(0), HasLeadingZeroes(0) {}
+
+ static FormatSpecifier Parse(const char *beg, const char *end);
+
+ // Methods for incrementally constructing the FormatSpecifier.
+ void setConversionSpecifier(const ConversionSpecifier &cs) {
+ CS = cs;
+ }
+ void setLengthModifier(LengthModifier lm) {
+ LM = lm;
+ }
+ void setIsLeftJustified() { IsLeftJustified = 1; }
+ void setHasPlusPrefix() { HasPlusPrefix = 1; }
+ void setHasSpacePrefix() { HasSpacePrefix = 1; }
+ void setHasAlternativeForm() { HasAlternativeForm = 1; }
+ void setHasLeadingZeros() { HasLeadingZeroes = 1; }
+
+ // Methods for querying the format specifier.
+
+ const ConversionSpecifier &getConversionSpecifier() const {
+ return CS;
+ }
+
+ LengthModifier getLengthModifier() const {
+ return LM;
+ }
+
+ const OptionalAmount &getFieldWidth() const {
+ return FieldWidth;
+ }
+
+ void setFieldWidth(const OptionalAmount &Amt) {
+ FieldWidth = Amt;
+ }
+
+ void setPrecision(const OptionalAmount &Amt) {
+ Precision = Amt;
+ }
+
+ const OptionalAmount &getPrecision() const {
+ return Precision;
+ }
+
+ /// \brief Returns the builtin type that a data argument
+ /// paired with this format specifier should have. This method
+ /// will return null if the format specifier does not have
+ /// a matching data argument or the matching argument matches
+ /// more than one type.
+ ArgTypeResult getArgType(ASTContext &Ctx) const;
+
+ bool isLeftJustified() const { return (bool) IsLeftJustified; }
+ bool hasPlusPrefix() const { return (bool) HasPlusPrefix; }
+ bool hasAlternativeForm() const { return (bool) HasAlternativeForm; }
+ bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; }
+ bool hasSpacePrefix() const { return (bool) HasSpacePrefix; }
+};
+
+class FormatStringHandler {
+public:
+ FormatStringHandler() {}
+ virtual ~FormatStringHandler();
+
+ virtual void HandleIncompleteFormatSpecifier(const char *startSpecifier,
+ unsigned specifierLen) {}
+
+ virtual void HandleNullChar(const char *nullCharacter) {}
+
+ virtual void
+ HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {}
+
+ virtual bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ return true;
+ }
+};
+
+bool ParseFormatString(FormatStringHandler &H,
+ const char *beg, const char *end);
+
+} // end printf namespace
+} // end clang namespace
+#endif
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index 2b367b7e37f6..cd771acb06a5 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -70,5 +70,8 @@ public:
void InitializeValues(const CFG& cfg);
};
+
+void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
+ bool FullUninitTaint=false);
} // end namespace clang
#endif
diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index c82bb962fd18..ea4f5b20669c 100644
--- a/include/clang/Analysis/PathSensitive/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -32,7 +32,6 @@ class LiveVariables;
class ParentMap;
class ImplicitParamDecl;
class LocationContextManager;
-class BlockDataRegion;
class StackFrameContext;
/// AnalysisContext contains the context data for the function or method under
@@ -207,35 +206,23 @@ public:
};
class BlockInvocationContext : public LocationContext {
- llvm::PointerUnion<const BlockDataRegion *, const BlockDecl *> Data;
+ // FIXME: Add back context-sensivity (we don't want libAnalysis to know
+ // about MemRegion).
+ const BlockDecl *BD;
friend class LocationContextManager;
BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent,
- const BlockDataRegion *br)
- : LocationContext(Block, ctx, parent), Data(br) {}
-
- BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent,
const BlockDecl *bd)
- : LocationContext(Block, ctx, parent), Data(bd) {}
+ : LocationContext(Block, ctx, parent), BD(bd) {}
public:
~BlockInvocationContext() {}
-
- const BlockDataRegion *getBlockRegion() const {
- return Data.is<const BlockDataRegion*>() ?
- Data.get<const BlockDataRegion*>() : 0;
- }
-
- const BlockDecl *getBlockDecl() const;
-
+
+ const BlockDecl *getBlockDecl() const { return BD; }
+
void Profile(llvm::FoldingSetNodeID &ID);
-
- static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
- const LocationContext *parent, const BlockDataRegion *br){
- ProfileCommon(ID, Block, ctx, parent, br);
- }
-
+
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
const LocationContext *parent, const BlockDecl *bd) {
ProfileCommon(ID, Block, ctx, parent, bd);
@@ -260,10 +247,6 @@ public:
const LocationContext *parent,
const Stmt *s);
- const BlockInvocationContext *
- getBlockInvocation(AnalysisContext *ctx, const LocationContext *parent,
- const BlockDataRegion *BR);
-
/// Discard all previously created LocationContext objects.
void clear();
private:
diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h
index 40f38be020a9..a4e6d519a04f 100644
--- a/include/clang/Analysis/Support/Optional.h
+++ b/include/clang/Analysis/Support/Optional.h
@@ -20,19 +20,27 @@ namespace clang {
template<typename T>
class Optional {
- const T x;
+ T x;
unsigned hasVal : 1;
public:
- explicit Optional() : hasVal(false) {}
+ explicit Optional() : x(), hasVal(false) {}
Optional(const T &y) : x(y), hasVal(true) {}
static inline Optional create(const T* y) {
return y ? Optional(*y) : Optional();
}
+ Optional &operator=(const T &y) {
+ x = y;
+ hasVal = true;
+ return *this;
+ }
+
const T* getPointer() const { assert(hasVal); return &x; }
+ const T& getValue() const { assert(hasVal); return x; }
operator bool() const { return hasVal; }
+ bool hasValue() const { return hasVal; }
const T* operator->() const { return getPointer(); }
const T& operator*() const { assert(hasVal); return x; }
};
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 08945635e6c9..3251ec4b1f97 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -12,9 +12,6 @@
//
//===----------------------------------------------------------------------===//
-// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
-// adding stuff on demand.
-//
// FIXME: This should really be a .td file, but that requires modifying tblgen.
// Perhaps tblgen should have plugins.
@@ -52,6 +49,7 @@
// * -> pointer
// & -> reference
// C -> const
+// D -> volatile
// The third value provided to the macro specifies information about attributes
// of the function. These must be kept in sync with the predicates in the
@@ -235,7 +233,7 @@ BUILTIN(__builtin_islessgreater , "i.", "nc")
BUILTIN(__builtin_isunordered , "i.", "nc")
// Unary FP classification
-// BUILTIN(__builtin_fpclassify, "iiiii.", "nc")
+BUILTIN(__builtin_fpclassify, "iiiii.", "nc")
BUILTIN(__builtin_isfinite, "i.", "nc")
BUILTIN(__builtin_isinf, "i.", "nc")
BUILTIN(__builtin_isinf_sign, "i.", "nc")
@@ -277,7 +275,7 @@ BUILTIN(__builtin_va_copy, "vAA", "n")
BUILTIN(__builtin_stdarg_start, "vA.", "n")
BUILTIN(__builtin_bcmp, "iv*v*z", "n")
BUILTIN(__builtin_bcopy, "vv*v*z", "n")
-BUILTIN(__builtin_bzero, "vv*z", "n")
+BUILTIN(__builtin_bzero, "vv*z", "nF")
BUILTIN(__builtin_memchr, "v*vC*iz", "nF")
BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF")
BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF")
@@ -308,11 +306,19 @@ BUILTIN(__builtin_extract_return_addr, "v*v*", "n")
BUILTIN(__builtin_frame_address, "v*Ui", "n")
BUILTIN(__builtin_flt_rounds, "i", "nc")
BUILTIN(__builtin_setjmp, "iv**", "")
-BUILTIN(__builtin_longjmp, "vv**i", "")
+BUILTIN(__builtin_longjmp, "vv**i", "r")
BUILTIN(__builtin_unwind_init, "v", "")
BUILTIN(__builtin_eh_return_data_regno, "ii", "nc")
BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
+// GCC exception builtins
+BUILTIN(__builtin_eh_return, "vzv*", "") // FIXME: Takes intptr_t, not size_t!
+BUILTIN(__builtin_frob_return_addr, "v*v*", "n")
+BUILTIN(__builtin_dwarf_cfa, "v*", "n")
+BUILTIN(__builtin_init_dwarf_reg_size_table, "vv*", "n")
+BUILTIN(__builtin_dwarf_sp_column, "Ui", "n")
+BUILTIN(__builtin_extend_pointer, "iv*", "n")
+
// GCC Object size checking builtins
BUILTIN(__builtin_object_size, "zv*i", "n")
BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF")
@@ -438,18 +444,18 @@ BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n")
BUILTIN(__sync_bool_compare_and_swap, "v.", "")
-BUILTIN(__sync_bool_compare_and_swap_1, "bc*cc.", "n")
-BUILTIN(__sync_bool_compare_and_swap_2, "bs*ss.", "n")
-BUILTIN(__sync_bool_compare_and_swap_4, "bi*ii.", "n")
-BUILTIN(__sync_bool_compare_and_swap_8, "bLLi*LLi.", "n")
-BUILTIN(__sync_bool_compare_and_swap_16, "bLLLi*LLLiLLLi.", "n")
+BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "n")
+BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "n")
+BUILTIN(__sync_bool_compare_and_swap_4, "biD*ii.", "n")
+BUILTIN(__sync_bool_compare_and_swap_8, "bLLiD*LLiLLi.", "n")
+BUILTIN(__sync_bool_compare_and_swap_16, "bLLLiD*LLLiLLLi.", "n")
BUILTIN(__sync_val_compare_and_swap, "v.", "")
-BUILTIN(__sync_val_compare_and_swap_1, "cc*cc.", "n")
-BUILTIN(__sync_val_compare_and_swap_2, "ss*ss.", "n")
-BUILTIN(__sync_val_compare_and_swap_4, "ii*ii.", "n")
-BUILTIN(__sync_val_compare_and_swap_8, "LLiLLi*LLi.", "n")
-BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLi*LLLiLLLi.", "n")
+BUILTIN(__sync_val_compare_and_swap_1, "ccD*cc.", "n")
+BUILTIN(__sync_val_compare_and_swap_2, "ssD*ss.", "n")
+BUILTIN(__sync_val_compare_and_swap_4, "iiD*ii.", "n")
+BUILTIN(__sync_val_compare_and_swap_8, "LLiLLiD*LLiLLi.", "n")
+BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLiD*LLLiLLLi.", "n")
BUILTIN(__sync_lock_test_and_set, "v.", "")
BUILTIN(__sync_lock_test_and_set_1, "cc*c.", "n")
@@ -527,6 +533,7 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h")
// POSIX strings.h
LIBBUILTIN(index, "c*cC*i", "f", "strings.h")
LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h")
+LIBBUILTIN(bzero, "vv*z", "f", "strings.h")
// POSIX unistd.h
LIBBUILTIN(_exit, "vi", "fr", "unistd.h")
// POSIX setjmp.h
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index c5d6d7c71316..d2516f8695b8 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -23,16 +23,19 @@
namespace llvm {
template <typename T> class SmallVectorImpl;
+ class raw_ostream;
}
namespace clang {
class DeclContext;
class DiagnosticBuilder;
class DiagnosticClient;
+ class FileManager;
class IdentifierInfo;
class LangOptions;
class PartialDiagnostic;
class Preprocessor;
+ class SourceManager;
class SourceRange;
// Import the diagnostic enums themselves.
@@ -400,6 +403,13 @@ public:
/// \brief Clear out the current diagnostic.
void Clear() { CurDiagID = ~0U; }
+ /// Deserialize - Deserialize the first diagnostic within the memory
+ /// [Memory, MemoryEnd), producing a new diagnostic builder describing the
+ /// deserialized diagnostic. If the memory does not contain a
+ /// diagnostic, returns a diagnostic builder with no diagnostic ID.
+ DiagnosticBuilder Deserialize(FileManager &FM, SourceManager &SM,
+ const char *&Memory, const char *MemoryEnd);
+
private:
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
/// specified builtin diagnostic. This returns the high bit encoding, or zero
@@ -472,7 +482,7 @@ private:
/// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed.
- const SourceRange *DiagRanges[10];
+ SourceRange DiagRanges[10];
enum { MaxCodeModificationHints = 3 };
@@ -568,6 +578,9 @@ public:
/// been emitted.
~DiagnosticBuilder() { Emit(); }
+ /// isActive - Determine whether this diagnostic is still active.
+ bool isActive() const { return DiagObj != 0; }
+
/// Operator bool: conversion of DiagnosticBuilder to bool always returns
/// true. This allows is to be used in boolean error contexts like:
/// return Diag(...);
@@ -596,7 +609,7 @@ public:
sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) &&
"Too many arguments to diagnostic!");
if (DiagObj)
- DiagObj->DiagRanges[NumRanges++] = &R;
+ DiagObj->DiagRanges[NumRanges++] = R;
}
void AddCodeModificationHint(const CodeModificationHint &Hint) const {
@@ -759,9 +772,9 @@ public:
return DiagObj->NumDiagRanges;
}
- const SourceRange &getRange(unsigned Idx) const {
+ SourceRange getRange(unsigned Idx) const {
assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!");
- return *DiagObj->DiagRanges[Idx];
+ return DiagObj->DiagRanges[Idx];
}
unsigned getNumCodeModificationHints() const {
@@ -786,6 +799,12 @@ public:
/// output buffer using the arguments stored in this diagnostic.
void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
llvm::SmallVectorImpl<char> &OutStr) const;
+
+ /// Serialize - Serialize the given diagnostic (with its diagnostic
+ /// level) to the given stream. Serialization is a lossy operation,
+ /// since the specific diagnostic ID and any macro-instantiation
+ /// information is lost.
+ void Serialize(Diagnostic::Level DiagLevel, llvm::raw_ostream &OS) const;
};
/// DiagnosticClient - This is an abstract interface implemented by clients of
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index f075aaaf422f..b6c2b13895d6 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -26,4 +26,33 @@ def err_asm_empty_symbolic_operand_name : Error<
def err_asm_invalid_operand_number : Error<
"invalid operand number in inline asm string">;
+// Importing ASTs
+def err_odr_variable_type_inconsistent : Error<
+ "external variable %0 declared with incompatible types in different "
+ "translation units (%1 vs. %2)">;
+def err_odr_variable_multiple_def : Error<
+ "external variable %0 defined in multiple translation units">;
+def note_odr_value_here : Note<"declared here with type %0">;
+def note_odr_defined_here : Note<"also defined here">;
+def err_odr_function_type_inconsistent : Error<
+ "external function %0 declared with incompatible types in different "
+ "translation units (%1 vs. %2)">;
+def warn_odr_tag_type_inconsistent : Warning<
+ "type %0 has incompatible definitions in different translation units">;
+def note_odr_tag_kind_here: Note<
+ "%0 is a %select{struct|union|class|enum}1 here">;
+def note_odr_field : Note<"field %0 has type %1 here">;
+def note_odr_missing_field : Note<"no corresponding field here">;
+def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;
+def note_odr_not_bit_field : Note<"field %0 is not a bit-field">;
+def note_odr_base : Note<"class has base type %0">;
+def note_odr_virtual_base : Note<
+ "%select{non-virtual|virtual}0 derivation here">;
+def note_odr_missing_base : Note<"no corresponding base class here">;
+def note_odr_number_of_bases : Note<
+ "class has %0 base %plural{1:class|:classes}0">;
+def note_odr_enumerator : Note<"enumerator %0 with value %1 here">;
+def note_odr_missing_enumerator : Note<"no corresponding enumerator here">;
+
+def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
}
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 7e14a329dcab..66f84dbbbabe 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -31,6 +31,9 @@ def note_also_found : Note<"also found">;
// Parse && Lex
def err_expected_colon : Error<"expected ':'">;
+def err_expected_colon_after_setter_name : Error<
+ "method name referenced in property setter attribute "
+ "must end with ':'">;
// Parse && Sema
def err_no_declarators : Error<"declaration does not declare anything">;
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 8cdf85082b16..dc5ccfdf5202 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -62,6 +62,8 @@ def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">;
def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">;
def err_drv_invalid_remap_file : Error<
"invalid option '%0' not of the form <from-file>;<to-file>">;
+def err_drv_invalid_gcc_output_type : Error<
+ "invalid output type '%0' for use with gcc tool">;
def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused when '%2' is present">;
@@ -85,5 +87,7 @@ def warn_ignoring_ftabstop_value : Warning<
"ignoring invalid -ftabstop value '%0', using default value %1">;
def warn_drv_missing_resource_library : Warning<
"missing resource library '%0', link may fail">;
+def warn_drv_conflicting_deployment_targets : Warning<
+ "conflicting deployment targets, both MACOSX_DEPLOYMENT_TARGET '%0' and IPHONEOS_DEPLOYMENT_TARGET '%1' are present in environment">;
}
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 66a841a8afae..79147eac5f32 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -19,6 +19,8 @@ def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
DefaultFatal;
+def err_fe_stderr_binary : Error<"unable to change standard error to binary">,
+ DefaultFatal;
def err_fe_dependency_file_requires_MT : Error<
"-dependency-file requires at least one -MT option">;
def err_fe_incompatible_options : Error<
@@ -80,6 +82,8 @@ def note_fixit_main_file_unchanged : Note<
def warn_fixit_no_changes : Note<
"FIX-IT detected errors it could not fix; no output will be generated">;
+def err_fe_clang : Error<"error invoking%s: %s">, DefaultFatal;
+
// PCH reader
def err_relocatable_without_without_isysroot : Error<
"must specify system root with -isysroot when building a relocatable "
@@ -105,6 +109,10 @@ def warn_pch_objective_c2 : Error<
def warn_pch_nonfragile_abi : Error<
"PCH file was compiled with the %select{32-bit|non-fragile}0 Objective-C "
"ABI but the %select{32-bit|non-fragile}1 Objective-C ABI is selected">;
+def warn_pch_nonfragile_abi2 : Error<
+ "PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 "
+ "Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 "
+ "Objective-C ABI is selected">;
def warn_pch_extensions : Error<
"extensions were %select{enabled|disabled}0 in PCH file but are "
"currently %select{enabled|disabled}1">;
@@ -132,6 +140,9 @@ def warn_pch_elide_constructors : Error<
def warn_pch_exceptions : Error<
"exceptions were %select{disabled|enabled}0 in PCH file but "
"are currently %select{disabled|enabled}1">;
+def warn_pch_sjlj_exceptions : Error<
+ "sjlj-exceptions were %select{disabled|enabled}0 in PCH file but "
+ "are currently %select{disabled|enabled}1">;
def warn_pch_objc_runtime : Error<
"PCH file was compiled with the %select{NeXT|GNU}0 runtime but the "
"%select{NeXT|GNU}1 runtime is selected">;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 03aad8606352..82f9eca12960 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -96,7 +96,8 @@ def : DiagGroup<"strict-overflow">;
def InvalidOffsetof : DiagGroup<"invalid-offsetof">;
def : DiagGroup<"strict-prototypes">;
def : DiagGroup<"strict-selector-match">;
-def Switch : DiagGroup<"switch">;
+def SwitchEnum : DiagGroup<"switch-enum">;
+def Switch : DiagGroup<"switch", [SwitchEnum]>;
def Trigraphs : DiagGroup<"trigraphs">;
def : DiagGroup<"type-limits">;
@@ -118,6 +119,7 @@ def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def : DiagGroup<"write-strings">;
def CharSubscript : DiagGroup<"char-subscripts">;
+def ForceAlignArgPointer : DiagGroup<"force-align-arg-pointer">;
// Aggregation warning settings.
@@ -178,4 +180,4 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
// A warning group for warnings that we want to have on by default in clang,
// but which aren't on by default in GCC.
def NonGCC : DiagGroup<"non-gcc",
- [SignCompare, Conversion]>;
+ [SignCompare, Conversion, ForceAlignArgPointer]>;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index c6d060525285..bc26c3b0dad9 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -14,6 +14,8 @@
let Component = "Parse" in {
def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">;
+def warn_file_asm_volatile : Warning<
+ "meaningless 'volatile' on asm outside function">;
def ext_empty_source_file : Extension<"ISO C forbids an empty source file">;
def ext_top_level_semi : Extension<
@@ -158,12 +160,20 @@ def err_typename_invalid_functionspec : Error<
"type name does not allow function specifier to be specified">;
def err_invalid_decl_spec_combination : Error<
"cannot combine with previous '%0' declaration specifier">;
+def err_invalid_vector_decl_spec_combination : Error<
+ "cannot combine with previous '%0' declaration specifier. \"__vector\" must be first">;
+def err_invalid_pixel_decl_spec_combination : Error<
+ "\"__pixel\" must be preceded by \"__vector\". '%0' declaration specifier not allowed here">;
+def err_invalid_vector_double_decl_spec_combination : Error<
+ "cannot use \"double\" with \"__vector\"">;
+def warn_vector_long_decl_spec_combination : Warning<
+ "Use of \"long\" with \"__vector\" is deprecated">;
def err_friend_invalid_in_context : Error<
"'friend' used outside of class">;
def err_unknown_typename : Error<
"unknown type name %0">;
def err_use_of_tag_name_without_tag : Error<
- "use of tagged type %0 without '%1' tag">;
+ "must use '%1' tag to refer to type %0%select{| in this scope}2">;
def err_expected_ident_in_using : Error<
"expected an identifier in using directive">;
def err_unexected_colon_in_nested_name_spec : Error<
@@ -303,6 +313,9 @@ def err_out_of_line_type_names_constructor : Error<
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
+def err_expected_semi_after_tagdecl : Error<
+ "expected ';' after %0">;
+
def err_typename_refers_to_non_type_template : Error<
"typename specifier refers to a non-template">;
def err_expected_type_name_after_typename : Error<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 8d75d2e25722..19b242e86b69 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -85,7 +85,11 @@ def warn_unused_variable : Warning<"unused variable %0">,
InGroup<UnusedVariable>, DefaultIgnore;
def warn_decl_in_param_list : Warning<
"declaration of %0 will not be visible outside of this function">;
-
+def err_array_star_in_function_definition : Error<
+ "variable length array must be bound in function definition">;
+def warn_unused_function : Warning<"unused function %0">,
+ InGroup<UnusedFunction>, DefaultIgnore;
+
def warn_implicit_function_decl : Warning<
"implicit declaration of function %0">,
InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
@@ -388,6 +392,11 @@ def err_deleted_non_function : Error<
def err_deleted_decl_not_first : Error<
"deleted definition must be first declaration">;
+def warn_weak_vtable : Warning<
+ "%0 has no out-of-line virtual method definitions; its vtable will be "
+ "emitted in every translation unit">,
+ InGroup<DiagGroup<"weak-vtables">>, DefaultIgnore;
+
// C++ exception specifications
def err_exception_spec_in_typedef : Error<
"exception specifications are not allowed in typedefs">;
@@ -410,17 +419,20 @@ def err_deep_exception_specs_differ : Error<
// C++ access checking
def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
+def err_access_private : Error<"%0 is a private member of %1">;
+def err_access_ctor_private : Error<"calling a private constructor of %0">;
+// Say something about the context for these?
+def err_access_protected : Error<"%0 is a protected member of %1">;
+def err_access_ctor_protected : Error<"calling a protected constructor of %0">;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
def err_access_outside_class : Error<
"access to %select{private|protected}0 member outside any class context">;
-def note_access_natural : Note<"declared %select{private|protected}0 here">;
+def note_access_natural : Note<
+ "%select{|implicitly }1declared %select{private|protected}0 here">;
def note_access_constrained_by_path : Note<
- "access to decl constrained by %select{private|protected}0 inheritance">;
-def err_access_protected : Error<
- "access to protected member of %0 from %1, which is not a subclass">;
-def err_access_private : Error<
- "access to private member of %0 from %1">;
+ "constrained by %select{|implicitly }1%select{private|protected}0"
+ " inheritance here">;
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
@@ -446,10 +458,14 @@ def err_mutable_nonmember : Error<
"'mutable' can only be applied to member variables">;
def err_virtual_non_function : Error<
"'virtual' can only appear on non-static member functions">;
-def err_explicit_non_function : Error<
- "'explicit' can only appear on non-static member functions">;
def err_virtual_out_of_class : Error<
"'virtual' can only be specified inside the class definition">;
+def err_explicit_non_function : Error<
+ "'explicit' can only appear on non-static member functions">;
+def err_explicit_out_of_class : Error<
+ "'explicit' can only be specified inside the class definition">;
+def err_explicit_non_ctor_or_conv_function : Error<
+ "'explicit' can only be applied to a constructor or conversion function">;
def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">;
def err_static_out_of_line : Error<
"'static' can only be specified inside the class definition">;
@@ -498,9 +514,8 @@ def note_overridden_virtual_function : Note<
"overridden virtual function is here">;
def err_covariant_return_inaccessible_base : Error<
- "return type of virtual function %2 is not covariant with the return type "
- "of the function it overrides "
- "(conversion from %0 to inaccessible base class %1)">, NoSFINAE;
+ "invalid covariant return for virtual function: %1 is a "
+ "%select{private|protected}2 base class of %0">, NoSFINAE;
def err_covariant_return_ambiguous_derived_to_base_conv : Error<
"return type of virtual function %3 is not covariant with the return type of "
"the function it overrides (ambiguous conversion from derived class "
@@ -547,7 +562,7 @@ def err_destructor_name : Error<
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|an array element}0 of type %1 with an %select{rvalue|lvalue}2 of "
+ "base class|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 cannot bind to lvalue">;
@@ -556,14 +571,14 @@ def err_invalid_initialization : Error<
def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lvalue "
"due to multiple conversion functions">;
def err_not_reference_to_const_init : Error<
- "non-const lvalue reference to type %0 cannot be initialized "
- "with a %select{value|temporary}1 of type %2">;
+ "%select{non-const|volatile}0 lvalue reference to type %1 cannot be "
+ "initialized with a %select{value|temporary}2 of type %3">;
def err_lvalue_reference_bind_to_temporary : Error<
- "non-const lvalue reference to type %0 cannot bind to a temporary of type "
- "%1">;
+ "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a "
+ "temporary of type %2">;
def err_lvalue_reference_bind_to_unrelated : Error<
- "non-const lvalue reference to type %0 cannot bind to a value of unrelated "
- "type %1">;
+ "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a "
+ "value of unrelated type %2">;
def err_reference_bind_drops_quals : Error<
"binding of reference to type %0 to a value of type %1 drops qualifiers">;
def err_reference_bind_failed : Error<
@@ -580,10 +595,14 @@ def err_reference_init_drops_quals : Error<
"qualifiers">;
def err_reference_bind_to_bitfield : Error<
"%select{non-const|volatile}0 reference cannot bind to bit-field %1">;
+def err_reference_bind_to_vector_element : Error<
+ "%select{non-const|volatile}0 reference cannot bind to vector element">;
def err_reference_var_requires_init : Error<
"declaration of reference variable %0 requires an initializer">;
def err_const_var_requires_init : Error<
"declaration of const variable '%0' requires an initializer">;
+def err_reference_without_init : Error<
+ "reference to type %0 requires an initializer">;
def err_reference_has_multiple_inits : Error<
"reference cannot be initialized with multiple values">;
def err_init_non_aggr_init_list : Error<
@@ -597,13 +616,16 @@ def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
def err_temp_copy_no_viable : Error<
"no viable copy constructor %select{copying variable|copying parameter|"
- "returning object|throwing object}0 of type %1">;
+ "returning object|throwing object|copying member subobject|copying array "
+ "element}0 of type %1">;
def err_temp_copy_ambiguous : Error<
"ambiguous copy constructor call when %select{copying variable|copying "
- "parameter|returning object|throwing object}0 of type %1">;
+ "parameter|returning object|throwing object|copying member subobject|copying "
+ "array element}0 of type %1">;
def err_temp_copy_deleted : Error<
"%select{copying variable|copying parameter|returning object|throwing "
- "object}0 of type %1 invokes deleted copy constructor">;
+ "object|copying member subobject|copying array element}0 of type %1 invokes "
+ "deleted copy constructor">;
// C++0x decltype
def err_cannot_determine_declared_type_of_overloaded_function : Error<
@@ -702,6 +724,9 @@ def err_attribute_aligned_not_power_of_two : Error<
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
"'%0' redeclared without %1 attribute: previous %1 ignored">;
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
+def warn_faap_attribute_ignored : Warning<
+ "force_align_arg_pointer used on function pointer; attribute ignored">,
+ InGroup<ForceAlignArgPointer>;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">;
def warn_attribute_void_function : Warning<
@@ -728,13 +753,18 @@ def err_attribute_wrong_decl_type : Error<
"parameter or Objective-C method |function, method or block|"
"virtual method or class|function, method, or parameter|class|virtual method"
"|member}1 types">;
+def warn_function_attribute_wrong_type : Warning<
+ "%0 only applies to function types; type here is %1">;
def warn_gnu_inline_attribute_requires_inline : Warning<
"'gnu_inline' attribute requires function to be marked 'inline',"
" attribute ignored">;
+def err_cconv_change : Error<
+ "function declared '%0' here was previously declared "
+ "%select{'%2'|without calling convention}1">;
def err_cconv_knr : Error<
- "function with no prototype cannot use '%0' calling convention">;
+ "function with no prototype cannot use %0 calling convention">;
def err_cconv_varargs : Error<
- "variadic function cannot use '%0' calling convention">;
+ "variadic function cannot use %0 calling convention">;
def warn_impcast_vector_scalar : Warning<
"implicit cast turns vector to scalar: %0 to %1">,
@@ -873,10 +903,7 @@ def err_uninitialized_member_for_assign : Error<
"assignment operator">;
def note_first_required_here : Note<
"synthesized method is first required here">;
-def err_null_intialized_reference_member : Error<
- "cannot initialize the member to null in default constructor because "
- "reference member %0 cannot be null-initialized">;
-def err_unintialized_member_in_ctor : Error<
+def err_uninitialized_member_in_ctor : Error<
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{reference|const}2 member %3">;
@@ -915,6 +942,12 @@ def note_ovl_candidate : Note<"candidate "
"is the implicit default constructor|"
"is the implicit copy constructor|"
"is the implicit copy assignment operator}0%1">;
+
+def note_ovl_candidate_bad_deduction : Note<
+ "candidate template ignored: failed template argument deduction">;
+def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
+ "couldn't infer template argument %0">;
+
// Note that we don't treat templates differently for this diagnostic.
def note_ovl_candidate_arity : Note<"candidate "
"%select{function|function|constructor|function|function|constructor|"
@@ -941,6 +974,13 @@ def note_ovl_candidate_bad_conv_incomplete : Note<"candidate "
"constructor (the implicit copy constructor)|"
"function (the implicit copy assignment operator)}0%1 "
"not viable: cannot convert argument of incomplete type %2 to %3">;
+def note_ovl_candidate_bad_overload : 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)}0%1"
+ " not viable: no overload of %3 matching %2 for %ordinal4 argument">;
def note_ovl_candidate_bad_conv : Note<"candidate "
"%select{function|function|constructor|"
"function |function |constructor |"
@@ -1068,9 +1108,6 @@ def err_template_tag_noparams : Error<
def err_template_decl_ref : Error<
"cannot refer to class template %0 without a template argument list">;
-def err_typedef_in_def_scope : Error<
- "cannot use typedef %0 in scope specifier for out-of-line declaration">;
-
// C++ Template Argument Lists
def err_template_arg_list_different_arity : Error<
"%select{too few|too many}0 template arguments for "
@@ -1122,6 +1159,8 @@ def err_template_arg_no_ref_bind : Error<
def err_template_arg_ref_bind_ignores_quals : Error<
"reference binding of non-type template parameter of type %0 to template "
"argument of type %1 ignores qualifiers">;
+def err_template_arg_not_decl_ref : Error<
+ "non-type template argument does not refer to any declaration">;
def err_template_arg_not_object_or_func_form : Error<
"non-type template argument does not directly refer to an object or "
"function">;
@@ -1236,6 +1275,8 @@ def err_partial_spec_redeclared : Error<
"class template partial specialization %0 cannot be redeclared">;
def note_prev_partial_spec_here : Note<
"previous declaration of class template partial specialization %0 is here">;
+def err_partial_spec_fully_specialized : Error<
+ "partial specialization of %0 does not use any of its template parameters">;
// C++ Function template specializations
def err_function_template_spec_no_match : Error<
@@ -1442,9 +1483,13 @@ def err_forward_ref_enum : Error<
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
def ext_enum_value_not_int : Extension<
- "ISO C restricts enumerator values to range of 'int' (%0 is too large)">;
+ "ISO C restricts enumerator values to range of 'int' (%0 is too "
+ "%select{small|large}1)">;
def warn_enum_too_large : Warning<
"enumeration values exceed range of largest integer">;
+def warn_enumerator_too_large : Warning<
+ "enumerator value %0 is not representable in the largest integer type">;
+
def warn_illegal_constant_array_size : Extension<
"size of static array must be an integer constant expression">;
def err_vla_decl_in_file_scope : Error<
@@ -1677,6 +1722,8 @@ 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_redeclared : Error<"class member cannot be redeclared">;
+def err_member_def_undefined_record : Error<
+ "out-of-line definition of %0 from class %1 without definition">;
def err_member_def_does_not_match : Error<
"out-of-line definition of %0 does not match any declaration in %1">;
def err_nonstatic_member_out_of_line : Error<
@@ -1824,7 +1871,11 @@ def ext_integer_complement_complex : Extension<
def error_nosetter_property_assignment : Error<
"setter method is needed to assign to object using property" " assignment syntax">;
def error_no_subobject_property_setting : Error<
- "cannot assign to a sub-structure of an ivar using property" " assignment syntax">;
+ "cannot assign to a sub-structure of an ivar using property"
+ " assignment syntax">;
+def error_no_subobject_property_getter_setting : Error<
+ "cannot assign to a sub-structure returned via a getter using property"
+ " assignment syntax">;
def ext_freestanding_complex : Extension<
"complex numbers are an extension in a freestanding C99 implementation">;
@@ -1915,7 +1966,9 @@ def err_ambiguous_base_to_derived_cast : Error<
def err_static_downcast_via_virtual : Error<
"cannot cast %0 to %1 via virtual base %2">;
def err_downcast_from_inaccessible_base : Error<
- "cannot cast %1 to %0 due to inaccessible conversion path">;
+ "cannot cast %select{private|protected}2 base class %1 to %0">;
+def err_upcast_to_inaccessible_base : Error<
+ "cannot cast %0 to its %select{private|protected}2 base class %1">;
def err_bad_dynamic_cast_not_ref_or_ptr : Error<
"%0 is not a reference or pointer">;
def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">;
@@ -1942,7 +1995,8 @@ def err_new_paren_array_nonconst : Error<
def err_array_size_not_integral : Error<
"array size expression must have integral or enumerated type, not %0">;
def err_default_init_const : Error<
- "default initialization of an object of const type %0">;
+ "default initialization of an object of const type %0"
+ "%select{| requires a user-provided default constructor}1">;
def err_delete_operand : Error<"cannot delete expression of type %0">;
def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete "
"expression of type %0 to a pointer">;
@@ -2245,8 +2299,6 @@ def error_multiple_base_initialization : Error <
def err_mem_init_not_member_or_class : Error<
"member initializer %0 does not name a non-static data member or base "
"class">;
-def err_mem_initializer_mismatch : Error<
- "Too many arguments for member initializer %0">;
def warn_field_initialized : Warning<
"member '%0' will be initialized after">,
@@ -2435,11 +2487,16 @@ def warn_printf_write_back : Warning<
def warn_printf_insufficient_data_args : Warning<
"more '%%' conversions than data arguments">, InGroup<Format>;
def warn_printf_too_many_data_args : Warning<
- "more data arguments than '%%' conversions">, InGroup<FormatExtraArgs>;
+ "more data arguments than format specifiers">, InGroup<FormatExtraArgs>;
def warn_printf_invalid_conversion : Warning<
- "invalid conversion '%0'">, InGroup<Format>;
+ "invalid conversion specifier '%0'">, InGroup<Format>;
+def warn_printf_incomplete_specifier : Warning<
+ "incomplete format specifier">, InGroup<Format>;
def warn_printf_missing_format_string : Warning<
"format string missing">, InGroup<Format>;
+def warn_printf_conversion_argument_type_mismatch : Warning<
+ "conversion specifies type %0 but the argument has type %1">,
+ InGroup<Format>;
def warn_null_arg : Warning<
"null passed to a callee which requires a non-null argument">,
InGroup<NonNull>;
@@ -2454,12 +2511,18 @@ def warn_printf_asterisk_width_missing_arg : Warning<
def warn_printf_asterisk_precision_missing_arg : Warning<
"'.*' specified field precision is missing a matching 'int' argument">;
def warn_printf_asterisk_width_wrong_type : Warning<
- "field width should have type 'int', but argument has type %0">,
+ "field width should have type %0, but argument has type %1">,
InGroup<Format>;
def warn_printf_asterisk_precision_wrong_type : Warning<
- "field precision should have type 'int', but argument has type %0">,
+ "field precision should have type %0, but argument has type %1">,
InGroup<Format>;
-
+def warn_printf_nonsensical_precision: Warning<
+ "precision used in '%0' conversion specifier (where it has no meaning)">,
+ InGroup<Format>;
+def warn_printf_nonsensical_flag: Warning<
+ "flag '%0' results in undefined behavior in '%1' conversion specifier">,
+ InGroup<Format>;
+
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr : Warning<
"address of stack memory associated with local variable %0 returned">;
@@ -2511,6 +2574,10 @@ def warn_case_value_overflow : Warning<
"overflow converting case value to switch condition type (%0 to %1)">;
def err_duplicate_case : Error<"duplicate case value '%0'">;
def warn_case_empty_range : Warning<"empty case range specified">;
+def warn_missing_cases : Warning<"enumeration value %0 not handled in switch">,
+ InGroup<DiagGroup<"switch-enum"> >;
+def not_in_enum : Warning<"case value not in enumerated type %0">,
+ InGroup<DiagGroup<"switch-enum"> >;
def err_typecheck_statement_requires_scalar : Error<
"statement requires expression of scalar type (%0 invalid)">;
def err_typecheck_statement_requires_integer : Error<
@@ -2679,6 +2746,7 @@ def err_undeclared_protocol_suggest : Error<
"cannot find protocol declaration for %0; did you mean %1?">;
def note_base_class_specified_here : Note<
"base class %0 specified here">;
+
}
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 2b6092dea309..d909f83e74d5 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -40,12 +40,14 @@ public:
unsigned ObjC1 : 1; // Objective-C 1 support enabled.
unsigned ObjC2 : 1; // Objective-C 2 support enabled.
unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled
+ unsigned ObjCNonFragileABI2 : 1; // Objective-C enhanced modern abi enabled
unsigned PascalStrings : 1; // Allow Pascal strings
unsigned WritableStrings : 1; // Allow writable strings
unsigned LaxVectorConversions : 1;
unsigned AltiVec : 1; // Support AltiVec-style vector initializers.
unsigned Exceptions : 1; // Support exception handling.
+ unsigned SjLjExceptions : 1; // Use setjmp-longjump exception handling.
unsigned RTTI : 1; // Support RTTI information.
unsigned NeXTRuntime : 1; // Use NeXT runtime.
@@ -95,7 +97,9 @@ public:
// operators
unsigned ElideConstructors : 1; // Whether C++ copy constructors should be
// elided if possible.
- unsigned CatchUndefined :1; // Generate code to check for undefined ops.
+ unsigned CatchUndefined : 1; // Generate code to check for undefined ops.
+ unsigned DumpVtableLayouts : 1; // Dump the layouts of all the emitted
+ // vtables.
private:
unsigned GC : 2; // Objective-C Garbage Collection modes. We
// declare this enum as unsigned because MSVC
@@ -124,10 +128,10 @@ public:
Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0;
GNUMode = ImplicitInt = Digraphs = 0;
HexFloats = 0;
- GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0;
+ GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0;
CXXOperatorNames = PascalStrings = WritableStrings = 0;
- Exceptions = Freestanding = NoBuiltin = 0;
+ Exceptions = SjLjExceptions = Freestanding = NoBuiltin = 0;
NeXTRuntime = 1;
RTTI = 1;
LaxVectorConversions = 1;
@@ -136,8 +140,7 @@ public:
SymbolVisibility = (unsigned) Default;
- // FIXME: The default should be 1.
- ThreadsafeStatics = 0;
+ ThreadsafeStatics = 1;
POSIXThreads = 0;
Blocks = 0;
BlockIntrospection = 0;
@@ -167,6 +170,7 @@ public:
CharIsSigned = 1;
ShortWChar = 0;
CatchUndefined = 0;
+ DumpVtableLayouts = 0;
}
GCMode getGCMode() const { return (GCMode) GC; }
diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h
new file mode 100644
index 000000000000..de0de348d351
--- /dev/null
+++ b/include/clang/Basic/Linkage.h
@@ -0,0 +1,57 @@
+//===--- Linkage.h - Linkage enumeration and utilities ----------*- 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 Linkage enumeration and various utility
+// functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_LINKAGE_H
+#define LLVM_CLANG_BASIC_LINKAGE_H
+
+namespace clang {
+
+/// \brief Describes the different kinds of linkage
+/// (C++ [basic.link], C99 6.2.2) that an entity may have.
+enum Linkage {
+ /// \brief No linkage, which means that the entity is unique and
+ /// can only be referred to from within its scope.
+ NoLinkage = 0,
+
+ /// \brief Internal linkage, which indicates that the entity can
+ /// be referred to from within the translation unit (but not other
+ /// translation units).
+ InternalLinkage,
+
+ /// \brief External linkage within a unique namespace. From the
+ /// langauge perspective, these entities have external
+ /// linkage. However, since they reside in an anonymous namespace,
+ /// their names are unique to this translation unit, which is
+ /// equivalent to having internal linkage from the code-generation
+ /// point of view.
+ UniqueExternalLinkage,
+
+ /// \brief External linkage, which indicates that the entity can
+ /// be referred to from other translation units.
+ ExternalLinkage
+};
+
+/// \brief Determine whether the given linkage is semantically
+/// external.
+inline bool isExternalLinkage(Linkage L) {
+ return L == UniqueExternalLinkage || L == ExternalLinkage;
+}
+
+/// \brief Compute the minimum linkage given two linages.
+static inline Linkage minLinkage(Linkage L1, Linkage L2) {
+ return L1 < L2? L1 : L2;
+}
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_LINKAGE_H
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index 0d970123f745..873aaeecb6bf 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -1,4 +1,4 @@
-//===--- PartialDiagnostic.h - Diagnostic "closures" ----------------------===//
+//===--- PartialDiagnostic.h - Diagnostic "closures" ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index b4cf959dc551..15ece685104c 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -669,12 +669,20 @@ public:
::const_iterator fileinfo_iterator;
fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); }
fileinfo_iterator fileinfo_end() const { return FileInfos.end(); }
+ bool hasFileInfo(const FileEntry *File) const {
+ return FileInfos.find(File) != FileInfos.end();
+ }
/// PrintStats - Print statistics to stderr.
///
void PrintStats() const;
unsigned sloc_entry_size() const { return SLocEntryTable.size(); }
+
+ // FIXME: Exposing this is a little gross; what we want is a good way
+ // to iterate the entries that were not defined in a PCH file (or
+ // any other external source).
+ unsigned sloc_loaded_entry_size() const { return SLocEntryLoaded.size(); }
const SrcMgr::SLocEntry &getSLocEntry(unsigned ID) const {
assert(ID < SLocEntryTable.size() && "Invalid id");
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 4cace86dd18d..9e54762add7d 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -77,6 +77,7 @@ namespace clang {
AS_private,
AS_none
};
-}
+
+} // end namespace clang
#endif // LLVM_CLANG_BASIC_SPECIFIERS_H
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 97e0495bfbe2..bc2cf198c3f5 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -226,11 +226,11 @@ public:
/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
- bool isValidGCCRegisterName(const char *Name) const;
+ bool isValidGCCRegisterName(llvm::StringRef Name) const;
// getNormalizedGCCRegisterName - Returns the "normalized" GCC register name.
// For example, on x86 it will return "ax" when "eax" is passed in.
- const char *getNormalizedGCCRegisterName(const char *Name) const;
+ llvm::StringRef getNormalizedGCCRegisterName(llvm::StringRef Name) const;
struct ConstraintInfo {
enum {
@@ -246,10 +246,9 @@ public:
std::string ConstraintStr; // constraint: "=rm"
std::string Name; // Operand name: [foo] with no []'s.
public:
- ConstraintInfo(const char *str, unsigned strlen, const std::string &name)
- : Flags(0), TiedOperand(-1), ConstraintStr(str, str+strlen), Name(name) {}
- explicit ConstraintInfo(const std::string &Str, const std::string &name)
- : Flags(0), TiedOperand(-1), ConstraintStr(Str), Name(name) {}
+ ConstraintInfo(llvm::StringRef ConstraintStr, llvm::StringRef Name)
+ : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()),
+ Name(Name.str()) {}
const std::string &getConstraintStr() const { return ConstraintStr; }
const std::string &getName() const { return Name; }
@@ -321,12 +320,6 @@ public:
virtual bool useGlobalsForAutomaticVariables() const { return false; }
- /// getUnicodeStringSection - Return the section to use for unicode
- /// string literals, or 0 if no special section is used.
- virtual const char *getUnicodeStringSection() const {
- return 0;
- }
-
/// getCFStringSection - Return the section to use for CFString
/// literals, or 0 if no special section is used.
virtual const char *getCFStringSection() const {
@@ -343,7 +336,7 @@ public:
/// and give good diagnostics in cases when the assembler or code generator
/// would otherwise reject the section specifier.
///
- virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const {
+ virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const {
return "";
}
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index bb022f11759d..522ac13b4e32 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -227,7 +227,7 @@ KEYWORD(__func__ , KEYALL)
// C++ 2.11p1: Keywords.
KEYWORD(asm , KEYCXX|KEYGNU)
-KEYWORD(bool , BOOLSUPPORT)
+KEYWORD(bool , BOOLSUPPORT|KEYALTIVEC)
KEYWORD(catch , KEYCXX)
KEYWORD(class , KEYCXX)
KEYWORD(const_cast , KEYCXX)
@@ -235,7 +235,7 @@ KEYWORD(delete , KEYCXX)
KEYWORD(dynamic_cast , KEYCXX)
KEYWORD(explicit , KEYCXX)
KEYWORD(export , KEYCXX)
-KEYWORD(false , BOOLSUPPORT)
+KEYWORD(false , BOOLSUPPORT|KEYALTIVEC)
KEYWORD(friend , KEYCXX)
KEYWORD(mutable , KEYCXX)
KEYWORD(namespace , KEYCXX)
@@ -249,7 +249,7 @@ KEYWORD(static_cast , KEYCXX)
KEYWORD(template , KEYCXX)
KEYWORD(this , KEYCXX)
KEYWORD(throw , KEYCXX)
-KEYWORD(true , BOOLSUPPORT)
+KEYWORD(true , BOOLSUPPORT|KEYALTIVEC)
KEYWORD(try , KEYCXX)
KEYWORD(typename , KEYCXX)
KEYWORD(typeid , KEYCXX)
@@ -340,6 +340,10 @@ KEYWORD(__ptr64 , KEYALL)
KEYWORD(__w64 , KEYALL)
KEYWORD(__forceinline , KEYALL)
+// Altivec Extension.
+KEYWORD(__vector , KEYALTIVEC)
+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)
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
index 4710b6b608e6..2728637ba497 100644
--- a/include/clang/Basic/Version.h
+++ b/include/clang/Basic/Version.h
@@ -56,16 +56,16 @@ namespace clang {
/// \brief Retrieves the repository revision number (or identifer) from which
/// this Clang was built.
- llvm::StringRef getClangRevision();
+ std::string getClangRevision();
/// \brief Retrieves the full repository version that is an amalgamation of
/// the information in getClangRepositoryPath() and getClangRevision().
- llvm::StringRef getClangFullRepositoryVersion();
+ std::string getClangFullRepositoryVersion();
/// \brief Retrieves a string representing the complete clang version,
/// which includes the clang version number, the repository version,
/// and the vendor tag.
- const char *getClangFullVersion();
+ std::string getClangFullVersion();
}
#endif // LLVM_CLANG_BASIC_VERSION_H
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Checker/BugReporter/BugReporter.h
index 6f6681a3629b..6c41668ccece 100644
--- a/include/clang/Analysis/PathSensitive/BugReporter.h
+++ b/include/clang/Checker/BugReporter/BugReporter.h
@@ -17,9 +17,9 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/BugType.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
@@ -202,7 +202,7 @@ public:
~RangedBugReport();
// FIXME: Move this out of line.
- void addRange(SourceRange R) {
+ void addRange(SourceRange R) {
assert(R.isValid());
Ranges.push_back(R);
}
@@ -464,6 +464,10 @@ const Stmt *GetRetValExpr(const ExplodedNode *N);
void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
const ExplodedNode* N);
+void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
+ const ExplodedNode *N);
+
+
} // end namespace clang::bugreporter
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Analysis/PathSensitive/BugType.h b/include/clang/Checker/BugReporter/BugType.h
index b75a8189e54c..4f1523a5440d 100644
--- a/include/clang/Analysis/PathSensitive/BugType.h
+++ b/include/clang/Checker/BugReporter/BugType.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
-#include "clang/Analysis/PathSensitive/BugReporter.h"
#include <llvm/ADT/FoldingSet.h>
#include <string>
diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Checker/BugReporter/PathDiagnostic.h
index d380c45480cb..d380c45480cb 100644
--- a/include/clang/Analysis/PathDiagnostic.h
+++ b/include/clang/Checker/BugReporter/PathDiagnostic.h
diff --git a/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h b/include/clang/Checker/Checkers/DereferenceChecker.h
index a84183e7f27f..a84183e7f27f 100644
--- a/include/clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h
+++ b/include/clang/Checker/Checkers/DereferenceChecker.h
diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Checker/Checkers/LocalCheckers.h
index 9c343e078641..4a9e381a7c15 100644
--- a/include/clang/Analysis/LocalCheckers.h
+++ b/include/clang/Checker/Checkers/LocalCheckers.h
@@ -31,13 +31,11 @@ class BugReporter;
class ObjCImplementationDecl;
class LangOptions;
class GRExprEngine;
+class TranslationUnitDecl;
void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map,
BugReporter& BR);
-void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
- bool FullUninitTaint=false);
-
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
const LangOptions& lopts);
@@ -53,8 +51,8 @@ void RegisterAppleChecks(GRExprEngine& Eng, const Decl &D);
void RegisterExperimentalChecks(GRExprEngine &Eng);
void RegisterExperimentalInternalChecks(GRExprEngine &Eng);
+void CheckLLVMConventions(TranslationUnitDecl &TU, BugReporter &BR);
void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
-
void CheckSizeofPointer(const Decl *D, BugReporter &BR);
void RegisterCallInliner(GRExprEngine &Eng);
diff --git a/include/clang/Checker/DomainSpecific/CocoaConventions.h b/include/clang/Checker/DomainSpecific/CocoaConventions.h
new file mode 100644
index 000000000000..ee3d648b8608
--- /dev/null
+++ b/include/clang/Checker/DomainSpecific/CocoaConventions.h
@@ -0,0 +1,40 @@
+//===- CocoaConventions.h - Special handling of Cocoa conventions -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CHECKER_DS_COCOA
+#define LLVM_CLANG_CHECKER_DS_COCOA
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace cocoa {
+
+ enum NamingConvention { NoConvention, CreateRule, InitRule };
+
+ NamingConvention deriveNamingConvention(Selector S);
+
+ static inline bool followsFundamentalRule(Selector S) {
+ return deriveNamingConvention(S) == CreateRule;
+ }
+
+ bool isRefType(QualType RetTy, llvm::StringRef Prefix,
+ llvm::StringRef Name = llvm::StringRef());
+
+ bool isCFObjectRef(QualType T);
+
+ bool isCocoaObjectRef(QualType T);
+
+}}
+
+#endif
diff --git a/include/clang/Analysis/ManagerRegistry.h b/include/clang/Checker/ManagerRegistry.h
index 972993855c28..ebfd28e10930 100644
--- a/include/clang/Analysis/ManagerRegistry.h
+++ b/include/clang/Checker/ManagerRegistry.h
@@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H
#define LLVM_CLANG_ANALYSIS_MANAGER_REGISTRY_H
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRState.h"
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h
index 8288864f2b61..fdf52a7dc770 100644
--- a/include/clang/Analysis/PathSensitive/AnalysisManager.h
+++ b/include/clang/Checker/PathSensitive/AnalysisManager.h
@@ -15,9 +15,9 @@
#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H
#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Checker/PathSensitive/BasicValueFactory.h
index 12f0ce2d50b7..2f0b6c2a0348 100644
--- a/include/clang/Analysis/PathSensitive/BasicValueFactory.h
+++ b/include/clang/Checker/PathSensitive/BasicValueFactory.h
@@ -16,8 +16,8 @@
#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
-#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/SVals.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/APSInt.h"
@@ -46,19 +46,19 @@ public:
};
class LazyCompoundValData : public llvm::FoldingSetNode {
- const GRState *state;
+ const void *store;
const TypedRegion *region;
public:
- LazyCompoundValData(const GRState *st, const TypedRegion *r)
- : state(st), region(r) {}
+ LazyCompoundValData(const void *st, const TypedRegion *r)
+ : store(st), region(r) {}
- const GRState *getState() const { return state; }
+ const void *getStore() const { return store; }
const TypedRegion *getRegion() const { return region; }
- static void Profile(llvm::FoldingSetNodeID& ID, const GRState *state,
+ static void Profile(llvm::FoldingSetNodeID& ID, const void *store,
const TypedRegion *region);
- void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, state, region); }
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
};
class BasicValueFactory {
@@ -169,7 +169,7 @@ public:
const CompoundValData *getCompoundValData(QualType T,
llvm::ImmutableList<SVal> Vals);
- const LazyCompoundValData *getLazyCompoundValData(const GRState *state,
+ const LazyCompoundValData *getLazyCompoundValData(const void *store,
const TypedRegion *region);
llvm::ImmutableList<SVal> getEmptySValList() {
diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Checker/PathSensitive/Checker.h
index 924a8b11b098..d498044b82ca 100644
--- a/include/clang/Analysis/PathSensitive/Checker.h
+++ b/include/clang/Checker/PathSensitive/Checker.h
@@ -15,9 +15,9 @@
#ifndef LLVM_CLANG_ANALYSIS_CHECKER
#define LLVM_CLANG_ANALYSIS_CHECKER
#include "clang/Analysis/Support/SaveAndRestore.h"
-#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtCXX.h"
diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Checker/PathSensitive/CheckerVisitor.def
index 7ec27efe5199..2edc4a37b7eb 100644
--- a/include/clang/Analysis/PathSensitive/CheckerVisitor.def
+++ b/include/clang/Checker/PathSensitive/CheckerVisitor.def
@@ -22,7 +22,6 @@
PREVISIT(ArraySubscriptExpr, Stmt)
PREVISIT(BinaryOperator, Stmt)
PREVISIT(CallExpr, Stmt)
-PREVISIT(CastExpr, Stmt)
PREVISIT(CXXOperatorCallExpr, CallExpr)
PREVISIT(DeclStmt, Stmt)
PREVISIT(ObjCMessageExpr, Stmt)
diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.h b/include/clang/Checker/PathSensitive/CheckerVisitor.h
index 37ec8def50b3..72f0ae1375e8 100644
--- a/include/clang/Analysis/PathSensitive/CheckerVisitor.h
+++ b/include/clang/Checker/PathSensitive/CheckerVisitor.h
@@ -13,7 +13,7 @@
#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR
#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
namespace clang {
@@ -42,7 +42,6 @@ public:
return;
case Stmt::ImplicitCastExprClass:
- case Stmt::ExplicitCastExprClass:
case Stmt::CStyleCastExprClass:
static_cast<ImplClass*>(this)->PreVisitCastExpr(C,
static_cast<const CastExpr*>(S));
@@ -57,7 +56,7 @@ public:
case Stmt::NAME ## Class:\
static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
break;
-#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
+#include "clang/Checker/PathSensitive/CheckerVisitor.def"
}
}
@@ -76,24 +75,26 @@ case Stmt::NAME ## Class:\
static_cast<ImplClass*>(this)->\
PostVisit ## NAME(C,static_cast<const NAME*>(S));\
break;
-#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
+#include "clang/Checker/PathSensitive/CheckerVisitor.def"
}
}
void PreVisitStmt(CheckerContext &C, const Stmt *S) {}
void PostVisitStmt(CheckerContext &C, const Stmt *S) {}
+
+ 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) {\
- PreVisit ## FALLBACK(C, S);\
+ static_cast<ImplClass*>(this)->PreVisit ## FALLBACK(C, S);\
}
-#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
-
#define POSTVISIT(NAME, FALLBACK) \
void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
- PostVisit ## FALLBACK(C, S);\
+ static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
}
-#include "clang/Analysis/PathSensitive/CheckerVisitor.def"
+#include "clang/Checker/PathSensitive/CheckerVisitor.def"
};
} // end clang namespace
diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Checker/PathSensitive/ConstraintManager.h
index c8292802ae9d..ce7d1b381714 100644
--- a/include/clang/Analysis/PathSensitive/ConstraintManager.h
+++ b/include/clang/Checker/PathSensitive/ConstraintManager.h
@@ -15,7 +15,7 @@
#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
-#include "clang/Analysis/PathSensitive/Store.h"
+#include "clang/Checker/PathSensitive/Store.h"
namespace llvm {
class APSInt;
diff --git a/include/clang/Analysis/PathSensitive/Environment.h b/include/clang/Checker/PathSensitive/Environment.h
index 6d5c5678e59b..0852c31faeb6 100644
--- a/include/clang/Analysis/PathSensitive/Environment.h
+++ b/include/clang/Checker/PathSensitive/Environment.h
@@ -16,11 +16,11 @@
// For using typedefs in StoreManager. Should find a better place for these
// typedefs.
-#include "clang/Analysis/PathSensitive/Store.h"
+#include "clang/Checker/PathSensitive/Store.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/SmallVector.h"
-#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/SVals.h"
#include "llvm/Support/Allocator.h"
#include "llvm/ADT/FoldingSet.h"
diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Checker/PathSensitive/ExplodedGraph.h
index fb5e1b8a415f..d6c4436c594c 100644
--- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h
+++ b/include/clang/Checker/PathSensitive/ExplodedGraph.h
@@ -16,7 +16,7 @@
#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
#include "clang/Analysis/ProgramPoint.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/FoldingSet.h"
diff --git a/include/clang/Analysis/PathSensitive/GRAuditor.h b/include/clang/Checker/PathSensitive/GRAuditor.h
index 015c82e80bb5..015c82e80bb5 100644
--- a/include/clang/Analysis/PathSensitive/GRAuditor.h
+++ b/include/clang/Checker/PathSensitive/GRAuditor.h
diff --git a/include/clang/Analysis/PathSensitive/GRBlockCounter.h b/include/clang/Checker/PathSensitive/GRBlockCounter.h
index 67ed9532db02..67ed9532db02 100644
--- a/include/clang/Analysis/PathSensitive/GRBlockCounter.h
+++ b/include/clang/Checker/PathSensitive/GRBlockCounter.h
diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h
index 74f7a147b841..6da45815f996 100644
--- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h
+++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h
@@ -16,11 +16,11 @@
#define LLVM_CLANG_ANALYSIS_GRENGINE
#include "clang/AST/Expr.h"
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/GRWorkList.h"
-#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
-#include "clang/Analysis/PathSensitive/GRAuditor.h"
-#include "clang/Analysis/PathSensitive/GRSubEngine.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/PathSensitive/GRWorkList.h"
+#include "clang/Checker/PathSensitive/GRBlockCounter.h"
+#include "clang/Checker/PathSensitive/GRAuditor.h"
+#include "clang/Checker/PathSensitive/GRSubEngine.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index df90ad9f7f08..90a2cd55972a 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -16,13 +16,13 @@
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
-#include "clang/Analysis/PathSensitive/AnalysisManager.h"
-#include "clang/Analysis/PathSensitive/GRSubEngine.h"
-#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
+#include "clang/Checker/PathSensitive/GRSubEngine.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
@@ -328,17 +328,6 @@ protected:
void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue);
- void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
- ObjCMessageExpr::arg_iterator I,
- ObjCMessageExpr::arg_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst,
- bool asLValue);
-
- void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue);
-
/// VisitReturnStmt - Transfer function logic for return statements.
void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h b/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h
index 60db406cd13d..5503412f7e45 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngineBuilders.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h
@@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
index 978ff0889e64..383463b822cb 100644
--- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
+++ b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
@@ -16,8 +16,8 @@
#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS
#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
-#include "clang/Analysis/PathSensitive/GRAuditor.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRAuditor.h"
+#include "clang/Checker/PathSensitive/GRState.h"
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h
index 11cdac0e96de..4e44697a272f 100644
--- a/include/clang/Analysis/PathSensitive/GRState.h
+++ b/include/clang/Checker/PathSensitive/GRState.h
@@ -16,11 +16,11 @@
// FIXME: Reduce the number of includes.
-#include "clang/Analysis/PathSensitive/Environment.h"
-#include "clang/Analysis/PathSensitive/Store.h"
-#include "clang/Analysis/PathSensitive/ConstraintManager.h"
-#include "clang/Analysis/PathSensitive/ValueManager.h"
-#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/Environment.h"
+#include "clang/Checker/PathSensitive/Store.h"
+#include "clang/Checker/PathSensitive/ConstraintManager.h"
+#include "clang/Checker/PathSensitive/ValueManager.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/ASTContext.h"
@@ -216,7 +216,7 @@ public:
/// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
- const GRState* bindCompoundLiteral(const CompoundLiteralExpr* CL,
+ const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL,
const LocationContext *LC,
SVal V) const;
@@ -607,19 +607,24 @@ inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx,
inline const GRState *
GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL,
const LocationContext *LC, SVal V) const {
- return getStateManager().StoreMgr->BindCompoundLiteral(this, CL, LC, V);
+ Store new_store =
+ getStateManager().StoreMgr->BindCompoundLiteral(St, CL, LC, V);
+ return makeWithStore(new_store);
}
inline const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const {
- return getStateManager().StoreMgr->BindDecl(this, VR, IVal);
+ Store new_store = getStateManager().StoreMgr->BindDecl(St, VR, IVal);
+ return makeWithStore(new_store);
}
inline const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const {
- return getStateManager().StoreMgr->BindDeclWithNoInit(this, VR);
+ Store new_store = getStateManager().StoreMgr->BindDeclWithNoInit(St, VR);
+ return makeWithStore(new_store);
}
inline const GRState *GRState::bindLoc(Loc LV, SVal V) const {
- return getStateManager().StoreMgr->Bind(this, LV, V);
+ Store new_store = getStateManager().StoreMgr->Bind(St, LV, V);
+ return makeWithStore(new_store);
}
inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
@@ -671,11 +676,11 @@ inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
}
inline SVal GRState::getSVal(Loc LV, QualType T) const {
- return getStateManager().StoreMgr->Retrieve(this, LV, T).getSVal();
+ return getStateManager().StoreMgr->Retrieve(St, LV, T);
}
inline SVal GRState::getSVal(const MemRegion* R) const {
- return getStateManager().StoreMgr->Retrieve(this, loc::MemRegionVal(R)).getSVal();
+ return getStateManager().StoreMgr->Retrieve(St, loc::MemRegionVal(R));
}
inline BasicValueFactory &GRState::getBasicVals() const {
diff --git a/include/clang/Analysis/PathSensitive/GRStateTrait.h b/include/clang/Checker/PathSensitive/GRStateTrait.h
index 5189a1f5aa7e..5189a1f5aa7e 100644
--- a/include/clang/Analysis/PathSensitive/GRStateTrait.h
+++ b/include/clang/Checker/PathSensitive/GRStateTrait.h
diff --git a/include/clang/Analysis/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h
index 5b383fae9bd0..ce57c2c68b4b 100644
--- a/include/clang/Analysis/PathSensitive/GRSubEngine.h
+++ b/include/clang/Checker/PathSensitive/GRSubEngine.h
@@ -13,7 +13,7 @@
#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
-#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/SVals.h"
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
index b058460a4934..04634effd587 100644
--- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
+++ b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
@@ -15,9 +15,9 @@
#ifndef LLVM_CLANG_ANALYSIS_GRTF
#define LLVM_CLANG_ANALYSIS_GRTF
-#include "clang/Analysis/PathSensitive/SVals.h"
-#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include <vector>
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/GRWorkList.h b/include/clang/Checker/PathSensitive/GRWorkList.h
index 857fa316911f..b8f90fa1eea1 100644
--- a/include/clang/Analysis/PathSensitive/GRWorkList.h
+++ b/include/clang/Checker/PathSensitive/GRWorkList.h
@@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST
#define LLVM_CLANG_ANALYSIS_GRWORKLIST
-#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
+#include "clang/Checker/PathSensitive/GRBlockCounter.h"
#include <cstddef>
namespace clang {
diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h
index 3bcedbefd65c..12bc0b795685 100644
--- a/include/clang/Analysis/PathSensitive/MemRegion.h
+++ b/include/clang/Checker/PathSensitive/MemRegion.h
@@ -18,8 +18,8 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
-#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/SVals.h"
#include "clang/AST/ASTContext.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/FoldingSet.h"
@@ -249,17 +249,20 @@ public:
class ElementRegion;
-class RegionRawOffset : public std::pair<const MemRegion*, int64_t> {
+class RegionRawOffset {
private:
friend class ElementRegion;
+ const MemRegion *Region;
+ int64_t Offset;
+
RegionRawOffset(const MemRegion* reg, int64_t offset = 0)
- : std::pair<const MemRegion*, int64_t>(reg, offset) {}
+ : Region(reg), Offset(offset) {}
public:
// FIXME: Eventually support symbolic offsets.
- int64_t getByteOffset() const { return second; }
- const MemRegion *getRegion() const { return first; }
+ int64_t getByteOffset() const { return Offset; }
+ const MemRegion *getRegion() const { return Region; }
void dumpToStream(llvm::raw_ostream& os) const;
void dump() const;
diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Checker/PathSensitive/SVals.h
index 9206817989db..65a8a2c01df5 100644
--- a/include/clang/Analysis/PathSensitive/SVals.h
+++ b/include/clang/Checker/PathSensitive/SVals.h
@@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H
#define LLVM_CLANG_ANALYSIS_RVALUE_H
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/ImmutableList.h"
@@ -388,7 +388,7 @@ public:
const LazyCompoundValData *getCVData() const {
return static_cast<const LazyCompoundValData*>(Data);
}
- const GRState *getState() const;
+ const void *getStore() const;
const TypedRegion *getRegion() const;
static bool classof(const SVal *V) {
diff --git a/include/clang/Analysis/PathSensitive/SValuator.h b/include/clang/Checker/PathSensitive/SValuator.h
index 4a4b502c6271..9beb8cb08661 100644
--- a/include/clang/Analysis/PathSensitive/SValuator.h
+++ b/include/clang/Checker/PathSensitive/SValuator.h
@@ -16,7 +16,7 @@
#define LLVM_CLANG_ANALYSIS_SVALUATOR
#include "clang/AST/Expr.h"
-#include "clang/Analysis/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/SVals.h"
namespace clang {
@@ -38,33 +38,8 @@ public:
SValuator(ValueManager &valMgr) : ValMgr(valMgr) {}
virtual ~SValuator() {}
- template <typename T>
- class GenericCastResult : public std::pair<const GRState *, T> {
- public:
- const GRState *getState() const { return this->first; }
- T getSVal() const { return this->second; }
- GenericCastResult(const GRState *s, T v)
- : std::pair<const GRState*,T>(s, v) {}
- };
+ SVal EvalCast(SVal V, QualType castTy, QualType originalType);
- class CastResult : public GenericCastResult<SVal> {
- public:
- CastResult(const GRState *s, SVal v) : GenericCastResult<SVal>(s, v) {}
- };
-
- class DefinedOrUnknownCastResult :
- public GenericCastResult<DefinedOrUnknownSVal> {
- public:
- DefinedOrUnknownCastResult(const GRState *s, DefinedOrUnknownSVal v)
- : GenericCastResult<DefinedOrUnknownSVal>(s, v) {}
- };
-
- CastResult EvalCast(SVal V, const GRState *ST,
- QualType castTy, QualType originalType);
-
- DefinedOrUnknownCastResult EvalCast(DefinedOrUnknownSVal V, const GRState *ST,
- QualType castTy, QualType originalType);
-
virtual SVal EvalMinus(NonLoc val) = 0;
virtual SVal EvalComplement(NonLoc val) = 0;
diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h
index 5606df0014f0..c660e7b7feee 100644
--- a/include/clang/Analysis/PathSensitive/Store.h
+++ b/include/clang/Checker/PathSensitive/Store.h
@@ -14,9 +14,9 @@
#ifndef LLVM_CLANG_ANALYSIS_STORE_H
#define LLVM_CLANG_ANALYSIS_STORE_H
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathSensitive/SVals.h"
-#include "clang/Analysis/PathSensitive/ValueManager.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/ValueManager.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
@@ -41,6 +41,7 @@ protected:
/// MRMgr - Manages region objects associated with this StoreManager.
MemRegionManager &MRMgr;
+ ASTContext &Ctx;
StoreManager(GRStateManager &stateMgr);
@@ -54,8 +55,7 @@ public:
/// expected type of the returned value. This is used if the value is
/// lazily computed.
/// \return The value bound to the location \c loc.
- virtual SValuator::CastResult Retrieve(const GRState *state, Loc loc,
- QualType T = QualType()) = 0;
+ virtual SVal Retrieve(Store store, Loc loc, QualType T = QualType()) = 0;
/// Return a state with the specified value bound to the given location.
/// \param[in] state The analysis state.
@@ -64,7 +64,7 @@ public:
/// \return A pointer to a GRState object that contains the same bindings as
/// \c state with the addition of having the value specified by \c val bound
/// to the location given for \c loc.
- virtual const GRState *Bind(const GRState *state, Loc loc, SVal val) = 0;
+ virtual Store Bind(Store store, Loc loc, SVal val) = 0;
virtual Store Remove(Store St, Loc L) = 0;
@@ -72,10 +72,9 @@ public:
/// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
/// for the compound literal and 'BegInit' and 'EndInit' represent an
/// array of initializer values.
- virtual const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* cl,
- const LocationContext *LC,
- SVal v) = 0;
+ virtual Store BindCompoundLiteral(Store store,
+ const CompoundLiteralExpr* cl,
+ const LocationContext *LC, SVal v) = 0;
/// getInitialStore - Returns the initial "empty" store representing the
/// value bindings upon entry to an analyzed function.
@@ -88,20 +87,30 @@ public:
/// getSubRegionMap - Returns an opaque map object that clients can query
/// to get the subregions of a given MemRegion object. It is the
// caller's responsibility to 'delete' the returned map.
- virtual SubRegionMap *getSubRegionMap(const GRState *state) = 0;
+ virtual SubRegionMap *getSubRegionMap(Store store) = 0;
- virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) = 0;
+ virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) {
+ return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
+ }
- virtual SVal getLValueString(const StringLiteral* sl) = 0;
+ virtual SVal getLValueString(const StringLiteral* S) {
+ return ValMgr.makeLoc(MRMgr.getStringRegion(S));
+ }
- SVal getLValueCompoundLiteral(const CompoundLiteralExpr* cl,
- const LocationContext *LC);
+ SVal getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
+ const LocationContext *LC) {
+ return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+ }
- virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) = 0;
+ virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) {
+ return getLValueFieldOrIvar(decl, base);
+ }
- virtual SVal getLValueField(const FieldDecl* D, SVal Base) = 0;
+ virtual SVal getLValueField(const FieldDecl* D, SVal Base) {
+ return getLValueFieldOrIvar(D, Base);
+ }
- virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0;
+ virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base);
// FIXME: Make out-of-line.
virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state,
@@ -129,33 +138,31 @@ public:
const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy);
/// EvalBinOp - Perform pointer arithmetic.
- virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,
+ virtual SVal EvalBinOp(BinaryOperator::Opcode Op,
Loc lhs, NonLoc rhs, QualType resultTy) {
return UnknownVal();
}
- virtual void RemoveDeadBindings(GRState &state, Stmt* Loc,
- SymbolReaper& SymReaper,
+ virtual Store RemoveDeadBindings(Store store, Stmt* Loc,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
- virtual const GRState *BindDecl(const GRState *ST, const VarRegion *VR,
- SVal initVal) = 0;
+ virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
- virtual const GRState *BindDeclWithNoInit(const GRState *ST,
- const VarRegion *VR) = 0;
+ virtual Store BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
- virtual const GRState *InvalidateRegion(const GRState *state,
- const MemRegion *R,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS) = 0;
+ virtual Store InvalidateRegion(Store store,
+ const MemRegion *R,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS) = 0;
- virtual const GRState *InvalidateRegions(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS);
+ virtual Store InvalidateRegions(Store store,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
// FIXME: Make out-of-line.
virtual const GRState *setExtent(const GRState *state,
@@ -192,6 +199,9 @@ protected:
/// as another region.
SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy,
bool performTestOnly = true);
+
+private:
+ SVal getLValueFieldOrIvar(const Decl* D, SVal Base);
};
// FIXME: Do we still need this?
@@ -214,7 +224,7 @@ public:
StoreManager *CreateBasicStoreManager(GRStateManager& StMgr);
StoreManager *CreateRegionStoreManager(GRStateManager& StMgr);
StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr);
-
+StoreManager *CreateFlatStoreManager(GRStateManager &StMgr);
} // end clang namespace
#endif
diff --git a/include/clang/Checker/PathSensitive/SummaryManager.h b/include/clang/Checker/PathSensitive/SummaryManager.h
new file mode 100644
index 000000000000..fd23189491b3
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/SummaryManager.h
@@ -0,0 +1,57 @@
+//== SummaryManager.h - Generic handling of function summaries --*- 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 SummaryManager and related classes, which provides
+// a generic mechanism for managing function summaries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CHECKER_SUMMARY
+#define LLVM_CLANG_CHECKER_SUMMARY
+
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+
+namespace summMgr {
+
+
+/* Key kinds:
+
+ - C functions
+ - C++ functions (name + parameter types)
+ - ObjC methods:
+ - Class, selector (class method)
+ - Class, selector (instance method)
+ - Category, selector (instance method)
+ - Protocol, selector (instance method)
+ - C++ methods
+ - Class, function name + parameter types + const
+ */
+
+class SummaryKey {
+
+};
+
+} // end namespace clang::summMgr
+
+class SummaryManagerImpl {
+
+};
+
+
+template <typename T>
+class SummaryManager : SummaryManagerImpl {
+
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Analysis/PathSensitive/SymbolManager.h b/include/clang/Checker/PathSensitive/SymbolManager.h
index 8eb319647953..8eb319647953 100644
--- a/include/clang/Analysis/PathSensitive/SymbolManager.h
+++ b/include/clang/Checker/PathSensitive/SymbolManager.h
diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Checker/PathSensitive/ValueManager.h
index 9cec3c421fbe..ea3af57ed3e4 100644
--- a/include/clang/Analysis/PathSensitive/ValueManager.h
+++ b/include/clang/Checker/PathSensitive/ValueManager.h
@@ -17,11 +17,11 @@
#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H
#include "llvm/ADT/OwningPtr.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathSensitive/SVals.h"
-#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
-#include "clang/Analysis/PathSensitive/SValuator.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/BasicValueFactory.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/SValuator.h"
namespace llvm { class BumpPtrAllocator; }
@@ -115,8 +115,8 @@ public:
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
}
- NonLoc makeLazyCompoundVal(const GRState *state, const TypedRegion *R) {
- return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(state, R));
+ NonLoc makeLazyCompoundVal(const void *store, const TypedRegion *R) {
+ return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(store, R));
}
NonLoc makeZeroArrayIndex() {
diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h
index 8682715ce552..e1d4ad1b1cce 100644
--- a/include/clang/CodeGen/CodeGenOptions.h
+++ b/include/clang/CodeGen/CodeGenOptions.h
@@ -41,6 +41,8 @@ public:
unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled.
unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled.
unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss
+ unsigned ObjCLegacyDispatch: 1; /// Use legacy Objective-C dispatch, even with
+ /// 2.0 runtime.
unsigned OptimizationLevel : 3; /// The -O[0-4] option specified.
unsigned OptimizeSize : 1; /// If -Os is specified.
unsigned SoftFloat : 1; /// -soft-float.
@@ -90,12 +92,13 @@ public:
NoCommon = 0;
NoImplicitFloat = 0;
NoZeroInitializedInBSS = 0;
+ ObjCLegacyDispatch = 0;
OptimizationLevel = 0;
OptimizeSize = 0;
- UnrollLoops = 0;
SoftFloat = 0;
TimePasses = 0;
UnitAtATime = 1;
+ UnrollLoops = 0;
UnwindTables = 0;
VerifyModule = 1;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 2511dfb7677a..047363ea597b 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -38,19 +38,21 @@ def analysis_CFGView : Flag<"-cfg-view">,
HelpText<"View Control-Flow Graphs using GraphViz">;
def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">,
HelpText<"Print results of live variable analysis">;
-def analysis_SecuritySyntacticChecks : Flag<"-warn-security-syntactic">,
+def analysis_LLVMConventionChecker : Flag<"-analyzer-check-llvm-conventions">,
+ HelpText<"Check code for LLVM codebase conventions (domain-specific)">;
+def analysis_SecuritySyntacticChecks : Flag<"-analyzer-check-security-syntactic">,
HelpText<"Perform quick security checks that require no data flow">;
-def analysis_WarnDeadStores : Flag<"-warn-dead-stores">,
+def analysis_WarnDeadStores : Flag<"-analyzer-check-dead-stores">,
HelpText<"Warn about stores to dead variables">;
def analysis_WarnUninitVals : Flag<"-warn-uninit-values">,
HelpText<"Warn about uses of uninitialized variables">;
-def analysis_WarnObjCMethSigs : Flag<"-warn-objc-methodsigs">,
+def analysis_WarnObjCMethSigs : Flag<"-analyzer-check-objc-methodsigs">,
HelpText<"Warn about Objective-C method signatures with type incompatibilities">;
-def analysis_WarnObjCDealloc : Flag<"-warn-objc-missing-dealloc">,
+def analysis_WarnObjCDealloc : Flag<"-analyzer-check-objc-missing-dealloc">,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">;
-def analysis_WarnObjCUnusedIvars : Flag<"-warn-objc-unused-ivars">,
+def analysis_WarnObjCUnusedIvars : Flag<"-analyzer-check-objc-unused-ivars">,
HelpText<"Warn about private ivars that are never used">;
-def analysis_CheckerCFRef : Flag<"-checker-cfref">,
+def analysis_ObjCMemChecker : Flag<"-analyzer-check-objc-mem">,
HelpText<"Run the [Core] Foundation reference count checker">;
def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">,
HelpText<"Warn about unintended use of sizeof() on pointer expressions">;
@@ -102,6 +104,8 @@ def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">,
def disable_llvm_optzns : Flag<"-disable-llvm-optzns">,
HelpText<"Don't run LLVM optimization passes">;
+def disable_llvm_verifier : Flag<"-disable-llvm-verifier">,
+ HelpText<"Don't run the LLVM IR verifier pass">;
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">,
@@ -115,6 +119,10 @@ def no_implicit_float : Flag<"-no-implicit-float">,
HelpText<"Don't generate implicit floating point instructions (x86-only)">;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">,
HelpText<"Disallow merging of constants.">;
+def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">,
+ HelpText<"Do not emit code to make initialization of local statics thread safe">;
+def fdump_vtable_layouts : Flag<"-fdump-vtable-layouts">,
+ HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">;
def masm_verbose : Flag<"-masm-verbose">,
HelpText<"Generate verbose assembly output">;
def mcode_model : Separate<"-mcode-model">,
@@ -165,6 +173,7 @@ 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 fdiagnostics_binary : Flag<"-fdiagnostics-binary">;
def w : Flag<"-w">, HelpText<"Suppress all warnings">;
def pedantic : Flag<"-pedantic">;
def pedantic_errors : Flag<"-pedantic-errors">;
@@ -197,6 +206,9 @@ def verify : Flag<"-verify">,
// CompilerInvocation out of a driver-derived argument vector.
def cc1 : Flag<"-cc1">;
+def ast_merge : Separate<"-ast-merge">,
+ MetaVarName<"<ast file>">,
+ HelpText<"Merge the given AST file into the translation unit being compiled.">;
def code_completion_at : Separate<"-code-completion-at">,
MetaVarName<"<file>:<line>:<column>">,
HelpText<"Dump code-completion information at a location">;
@@ -280,6 +292,8 @@ def emit_llvm_bc : Flag<"-emit-llvm-bc">,
HelpText<"Build ASTs then convert to LLVM, emit .bc file">;
def emit_llvm_only : Flag<"-emit-llvm-only">,
HelpText<"Build ASTs and convert to LLVM, discarding output">;
+def emit_obj : Flag<"-emit-obj">,
+ HelpText<"Emit native object files">;
def rewrite_test : Flag<"-rewrite-test">,
HelpText<"Rewriter playground">;
def rewrite_objc : Flag<"-rewrite-objc">,
@@ -319,6 +333,8 @@ def fblocks : Flag<"-fblocks">,
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
def fexceptions : Flag<"-fexceptions">,
HelpText<"Enable support for exception handling">;
+def fsjlj_exceptions : Flag<"-fsjlj-exceptions">,
+ HelpText<"Use SjLj style exceptions">;
def ffreestanding : Flag<"-ffreestanding">,
HelpText<"Assert that the compilation takes place in a freestanding environment">;
def fgnu_runtime : Flag<"-fgnu-runtime">,
@@ -346,10 +362,14 @@ def fobjc_gc : Flag<"-fobjc-gc">,
HelpText<"Enable Objective-C garbage collection">;
def fobjc_gc_only : Flag<"-fobjc-gc-only">,
HelpText<"Use GC exclusively for Objective-C related memory management">;
+def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">,
+ HelpText<"Use legacy dispatch with the Objective-C non-fragile ABI">;
def print_ivar_layout : Flag<"-print-ivar-layout">,
HelpText<"Enable Objective-C Ivar layout bitmap print trace">;
def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">,
HelpText<"enable objective-c's nonfragile abi">;
+def fobjc_nonfragile_abi2 : Flag<"-fobjc-nonfragile-abi2">,
+ HelpText<"enable objective-c's enhanced nonfragile abi">;
def ftrapv : Flag<"-ftrapv">,
HelpText<"Trap on integer overflow">;
def pic_level : Separate<"-pic-level">,
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 3186471ce613..64f88ed98318 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -77,32 +77,36 @@ public:
/// Information about the host which can be overriden by the user.
std::string HostBits, HostMachine, HostSystem, HostRelease;
+ /// Name to use when calling the generic gcc.
+ std::string CCCGenericGCCName;
+
/// Whether the driver should follow g++ like behavior.
- bool CCCIsCXX : 1;
+ unsigned CCCIsCXX : 1;
/// Echo commands while executing (in -v style).
- bool CCCEcho : 1;
+ unsigned CCCEcho : 1;
/// Only print tool bindings, don't build any jobs.
- bool CCCPrintBindings : 1;
-
- /// Name to use when calling the generic gcc.
- std::string CCCGenericGCCName;
+ unsigned CCCPrintBindings : 1;
private:
+ /// Whether to check that input files exist when constructing compilation
+ /// jobs.
+ unsigned CheckInputsExist : 1;
+
/// Use the clang compiler where possible.
- bool CCCUseClang : 1;
+ unsigned CCCUseClang : 1;
/// Use clang for handling C++ and Objective-C++ inputs.
- bool CCCUseClangCXX : 1;
+ unsigned CCCUseClangCXX : 1;
/// Use clang as a preprocessor (clang's preprocessor will still be
/// used where an integrated CPP would).
- bool CCCUseClangCPP : 1;
+ unsigned CCCUseClangCPP : 1;
public:
/// Use lazy precompiled headers for PCH support.
- bool CCCUsePCH;
+ unsigned CCCUsePCH : 1;
private:
/// Only use clang for the given architectures (only used when
@@ -129,6 +133,10 @@ public:
const Diagnostic &getDiags() const { return Diags; }
+ bool getCheckInputsExist() const { return CheckInputsExist; }
+
+ void setCheckInputsExist(bool Value) { CheckInputsExist = Value; }
+
/// @}
/// @name Primary Functionality
/// @{
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 955d98e4e914..4693e5c1433c 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -252,6 +252,7 @@ def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Grou
def fcreate_profile : Flag<"-fcreate-profile">, 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_binary : Flag<"-fdiagnostics-binary">, Group<f_Group>, Flags<[HelpHidden]>;
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_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;
@@ -302,6 +303,7 @@ def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_
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_objc_legacy_dispatch : Flag<"-fno-objc-legacy-dispatch">, Group<f_Group>;
def fno_omit_frame_pointer : Flag<"-fno-omit-frame-pointer">, Group<f_Group>;
def fno_pascal_strings : Flag<"-fno-pascal-strings">, Group<f_Group>;
def fno_rtti : Flag<"-fno-rtti">, Group<f_Group>;
@@ -309,6 +311,7 @@ def fno_show_column : Flag<"-fno-show-column">, Group<f_Group>;
def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>;
def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<clang_ignored_f_Group>;
+def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, 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_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
@@ -317,8 +320,10 @@ def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>;
def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>;
+def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>;
def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>;
def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, Group<f_Group>;
+def fobjc_nonfragile_abi2 : Flag<"-fobjc-nonfragile-abi2">, Group<f_Group>;
def fobjc_sender_dependent_dispatch : Flag<"-fobjc-sender-dependent-dispatch">, Group<f_Group>;
def fobjc : Flag<"-fobjc">, Group<f_Group>;
def fomit_frame_pointer : Flag<"-fomit-frame-pointer">, Group<f_Group>;
@@ -348,6 +353,7 @@ def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
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 funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>;
@@ -374,6 +380,7 @@ def image__base : Separate<"-image_base">;
def include_ : JoinedOrSeparate<"-include">, Group<clang_i_Group>, EnumName<"include">;
def init : Separate<"-init">;
def install__name : Separate<"-install_name">;
+def integrated_as : Flag<"-integrated-as">, Flags<[DriverOption]>;
def iprefix : JoinedOrSeparate<"-iprefix">, Group<clang_i_Group>;
def iquote : JoinedOrSeparate<"-iquote">, Group<clang_i_Group>;
def isysroot : JoinedOrSeparate<"-isysroot">, Group<clang_i_Group>;
@@ -398,10 +405,10 @@ def mfix_and_continue : Flag<"-mfix-and-continue">, Group<clang_ignored_m_Group>
def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group<m_Group>;
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 miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group<m_Group>, Flags<[DriverOption]>;
def mkernel : Flag<"-mkernel">, Group<m_Group>;
def mllvm : Separate<"-mllvm">;
-def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group<m_Group>;
+def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group<m_Group>, Flags<[DriverOption]>;
def mmmx : Flag<"-mmmx">, Group<m_x86_Features_Group>;
def mno_3dnowa : Flag<"-mno-3dnowa">, Group<m_x86_Features_Group>;
def mno_3dnow : Flag<"-mno-3dnow">, Group<m_x86_Features_Group>;
@@ -416,7 +423,10 @@ def mno_sse4a : Flag<"-mno-sse4a">, Group<m_x86_Features_Group>;
def mno_sse4 : Flag<"-mno-sse4">, Group<m_x86_Features_Group>;
def mno_sse : Flag<"-mno-sse">, Group<m_x86_Features_Group>;
def mno_ssse3 : Flag<"-mno-ssse3">, Group<m_x86_Features_Group>;
+
def mno_thumb : Flag<"-mno-thumb">, Group<m_Group>;
+def marm : Flag<"-marm">, Alias<mno_thumb>;
+
def mno_warn_nonportable_cfstrings : Flag<"-mno-warn-nonportable-cfstrings">, Group<m_Group>;
def mpascal_strings : Flag<"-mpascal-strings">, Group<m_Group>;
def mred_zone : Flag<"-mred-zone">, Group<m_Group>;
@@ -438,6 +448,7 @@ def m_Joined : Joined<"-m">, Group<m_Group>;
def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[DriverOption, HelpHidden]>,
HelpText<"Use relative instead of canonical paths">;
def no_cpp_precomp : Flag<"-no-cpp-precomp">;
+def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>;
def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>;
def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">;
def nobuiltininc : Flag<"-nobuiltininc">;
@@ -481,6 +492,8 @@ def pthread : Flag<"-pthread">;
def p : Flag<"-p">;
def read__only__relocs : Separate<"-read_only_relocs">;
def remap : Flag<"-remap">;
+def rewrite_objc : Flag<"-rewrite-objc">, Flags<[DriverOption]>,
+ HelpText<"Rewrite Objective-C source to C++">;
def rpath : Separate<"-rpath">, Flags<[LinkerInput]>;
def r : Flag<"-r">;
def save_temps : Flag<"-save-temps">, Flags<[DriverOption]>,
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 8a89f01e0f4b..851e4235b00e 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -45,6 +45,7 @@ public:
virtual bool acceptsPipedInput() const = 0;
virtual bool canPipeOutput() const = 0;
+ virtual bool hasIntegratedAssembler() const { return false; }
virtual bool hasIntegratedCPP() const = 0;
/// ConstructJob - Construct jobs to perform the action \arg JA,
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index cc8d438db3e9..9a82973dca27 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -53,9 +53,9 @@ public:
const Driver &getDriver() const;
const llvm::Triple &getTriple() const { return Triple; }
- std::string getArchName() const { return Triple.getArchName(); }
- std::string getPlatform() const { return Triple.getVendorName(); }
- std::string getOS() const { return Triple.getOSName(); }
+ llvm::StringRef getArchName() const { return Triple.getArchName(); }
+ llvm::StringRef getPlatform() const { return Triple.getVendorName(); }
+ llvm::StringRef getOS() const { return Triple.getOSName(); }
std::string getTripleString() const {
return Triple.getTriple();
@@ -90,10 +90,19 @@ public:
/// IsBlocksDefault - Does this tool chain enable -fblocks by default.
virtual bool IsBlocksDefault() const { return false; }
+ /// IsIntegratedAssemblerDefault - Does this tool chain enable -integrated-as
+ /// by default.
+ virtual bool IsIntegratedAssemblerDefault() const { return false; }
+
/// IsObjCNonFragileABIDefault - Does this tool chain set
/// -fobjc-nonfragile-abi by default.
virtual bool IsObjCNonFragileABIDefault() const { return false; }
+ /// IsObjCLegacyDispatchDefault - Does this tool chain set
+ /// -fobjc-legacy-dispatch by default (this is only used with the non-fragile
+ /// ABI).
+ virtual bool IsObjCLegacyDispatchDefault() const { return false; }
+
/// GetDefaultStackProtectorLevel - Get the default stack protector level for
/// this tool chain (0=off, 1=on, 2=all).
virtual unsigned GetDefaultStackProtectorLevel() const { return 0; }
@@ -114,6 +123,9 @@ public:
/// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf
/// compile unit information.
virtual bool UseDwarfDebugFlags() const { return false; }
+
+ /// UseSjLjExceptions - Does this tool chain use SjLj exceptions.
+ virtual bool UseSjLjExceptions() const { return false; }
};
} // end namespace driver
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index d66fe9221a30..61a5043b34fc 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -72,6 +72,7 @@ TYPE("ast", AST, INVALID, "ast", "u")
TYPE("llvm-asm", LLVMAsm, INVALID, "s", "")
TYPE("llvm-bc", LLVMBC, INVALID, "o", "")
TYPE("plist", Plist, INVALID, "plist", "")
+TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", "")
TYPE("precompiled-header", PCH, INVALID, "gch", "A")
TYPE("object", Object, INVALID, "o", "")
TYPE("treelang", Treelang, INVALID, 0, "u")
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index 978b0d2b2aa6..7ec5063b5334 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -73,10 +73,11 @@ ASTConsumer *CreateObjCRewriter(const std::string &InFile,
// assembly. This runs optimizations depending on the CodeGenOptions
// parameter. The output depends on the Action parameter.
enum BackendAction {
- Backend_EmitAssembly, // Emit native assembly
- Backend_EmitBC, // Emit LLVM bitcode file
+ Backend_EmitAssembly, // Emit native assembly files
+ Backend_EmitBC, // Emit LLVM bitcode files
Backend_EmitLL, // Emit human-readable LLVM assembly
- Backend_EmitNothing // Don't emit anything (benchmarking mode)
+ Backend_EmitNothing, // Don't emit anything (benchmarking mode)
+ Backend_EmitObj // Emit native object files
};
ASTConsumer *CreateBackendConsumer(BackendAction Action,
Diagnostic &Diags,
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 2659dbb2a30c..f122dd954d3e 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -53,6 +53,10 @@ class ASTUnit {
llvm::OwningPtr<ASTContext> Ctx;
bool tempFile;
+ /// Optional owned invocation, just used to make the invocation used in
+ /// LoadFromCommandLine available.
+ llvm::OwningPtr<CompilerInvocation> Invocation;
+
// OnlyLocalDecls - when true, walking this AST should only visit declarations
// that come from the AST itself, not from included precompiled headers.
// FIXME: This is temporary; eventually, CIndex will always do this.
@@ -131,7 +135,6 @@ public:
static ASTUnit *LoadFromPCHFile(const std::string &Filename,
Diagnostic &Diags,
bool OnlyLocalDecls = false,
- bool UseBumpAllocator = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0);
@@ -139,14 +142,14 @@ public:
/// CompilerInvocation object.
///
/// \param CI - The compiler invocation to use; it must have exactly one input
- /// source file.
+ /// source file. The ASTUnit takes ownership of the CompilerInvocation object.
///
/// \param Diags - The diagnostics engine to use for reporting errors; its
/// lifetime is expected to extend past that of the returned ASTUnit.
//
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
- static ASTUnit *LoadFromCompilerInvocation(const CompilerInvocation &CI,
+ static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
Diagnostic &Diags,
bool OnlyLocalDecls = false);
@@ -169,7 +172,6 @@ public:
Diagnostic &Diags,
llvm::StringRef ResourceFilesPath,
bool OnlyLocalDecls = false,
- bool UseBumpAllocator = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0);
};
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def
index 7d55673a612f..287c67ebb7ef 100644
--- a/include/clang/Frontend/Analyses.def
+++ b/include/clang/Frontend/Analyses.def
@@ -24,28 +24,32 @@ ANALYSIS(CFGView, "cfg-view",
ANALYSIS(DisplayLiveVariables, "dump-live-variables",
"Print results of live variable analysis", Code)
-ANALYSIS(SecuritySyntacticChecks, "warn-security-syntactic",
+ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic",
"Perform quick security checks that require no data flow",
Code)
-ANALYSIS(WarnDeadStores, "warn-dead-stores",
+ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions",
+ "Check code for LLVM codebase conventions (domain-specific)",
+ TranslationUnit)
+
+ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores",
"Warn about stores to dead variables", Code)
ANALYSIS(WarnUninitVals, "warn-uninit-values",
"Warn about uses of uninitialized variables", Code)
-ANALYSIS(WarnObjCMethSigs, "warn-objc-methodsigs",
+ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs",
"Warn about Objective-C method signatures with type incompatibilities",
ObjCImplementation)
-ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc",
+ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc",
"Warn about Objective-C classes that lack a correct implementation of -dealloc",
ObjCImplementation)
-ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars",
+ANALYSIS(WarnObjCUnusedIvars, "analyzer-check-objc-unused-ivars",
"Warn about private ivars that are never used", ObjCImplementation)
-ANALYSIS(CheckerCFRef, "checker-cfref",
+ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem",
"Run the [Core] Foundation reference count checker", Code)
ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer",
@@ -61,6 +65,7 @@ ANALYSIS(InlineCall, "inline-call",
ANALYSIS_STORE(BasicStore, "basic", "Use basic analyzer store", CreateBasicStoreManager)
ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager)
+ANALYSIS_STORE(FlatStore, "flat", "Use flat analyzer store", CreateFlatStoreManager)
#ifndef ANALYSIS_CONSTRAINTS
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index edafe623a4f6..1be4118e5542 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -58,11 +58,10 @@ class TargetInfo;
/// and a long form that takes explicit instances of any required objects.
class CompilerInstance {
/// The LLVM context used for this instance.
- llvm::LLVMContext *LLVMContext;
- bool OwnsLLVMContext;
+ llvm::OwningPtr<llvm::LLVMContext> LLVMContext;
/// The options used in this compiler instance.
- CompilerInvocation Invocation;
+ llvm::OwningPtr<CompilerInvocation> Invocation;
/// The diagnostics engine instance.
llvm::OwningPtr<Diagnostic> Diagnostics;
@@ -97,11 +96,10 @@ class CompilerInstance {
/// The list of active output files.
std::list< std::pair<std::string, llvm::raw_ostream*> > OutputFiles;
+ void operator=(const CompilerInstance &); // DO NOT IMPLEMENT
+ CompilerInstance(const CompilerInstance&); // DO NOT IMPLEMENT
public:
- /// Create a new compiler instance with the given LLVM context, optionally
- /// taking ownership of it.
- CompilerInstance(llvm::LLVMContext *_LLVMContext = 0,
- bool _OwnsLLVMContext = true);
+ CompilerInstance();
~CompilerInstance();
/// @name High-Level Operations
@@ -150,93 +148,101 @@ public:
return *LLVMContext;
}
+ llvm::LLVMContext *takeLLVMContext() { return LLVMContext.take(); }
+
/// setLLVMContext - Replace the current LLVM context and take ownership of
/// \arg Value.
- void setLLVMContext(llvm::LLVMContext *Value, bool TakeOwnership = true) {
- LLVMContext = Value;
- OwnsLLVMContext = TakeOwnership;
- }
+ void setLLVMContext(llvm::LLVMContext *Value);
/// }
/// @name Compiler Invocation and Options
/// {
- CompilerInvocation &getInvocation() { return Invocation; }
- const CompilerInvocation &getInvocation() const { return Invocation; }
- void setInvocation(const CompilerInvocation &Value) { Invocation = Value; }
+ bool hasInvocation() const { return Invocation != 0; }
+
+ CompilerInvocation &getInvocation() {
+ assert(Invocation && "Compiler instance has no invocation!");
+ return *Invocation;
+ }
+
+ CompilerInvocation *takeInvocation() { return Invocation.take(); }
+
+ /// setInvocation - Replace the current invocation; the compiler instance
+ /// takes ownership of \arg Value.
+ void setInvocation(CompilerInvocation *Value);
/// }
/// @name Forwarding Methods
/// {
AnalyzerOptions &getAnalyzerOpts() {
- return Invocation.getAnalyzerOpts();
+ return Invocation->getAnalyzerOpts();
}
const AnalyzerOptions &getAnalyzerOpts() const {
- return Invocation.getAnalyzerOpts();
+ return Invocation->getAnalyzerOpts();
}
CodeGenOptions &getCodeGenOpts() {
- return Invocation.getCodeGenOpts();
+ return Invocation->getCodeGenOpts();
}
const CodeGenOptions &getCodeGenOpts() const {
- return Invocation.getCodeGenOpts();
+ return Invocation->getCodeGenOpts();
}
DependencyOutputOptions &getDependencyOutputOpts() {
- return Invocation.getDependencyOutputOpts();
+ return Invocation->getDependencyOutputOpts();
}
const DependencyOutputOptions &getDependencyOutputOpts() const {
- return Invocation.getDependencyOutputOpts();
+ return Invocation->getDependencyOutputOpts();
}
DiagnosticOptions &getDiagnosticOpts() {
- return Invocation.getDiagnosticOpts();
+ return Invocation->getDiagnosticOpts();
}
const DiagnosticOptions &getDiagnosticOpts() const {
- return Invocation.getDiagnosticOpts();
+ return Invocation->getDiagnosticOpts();
}
FrontendOptions &getFrontendOpts() {
- return Invocation.getFrontendOpts();
+ return Invocation->getFrontendOpts();
}
const FrontendOptions &getFrontendOpts() const {
- return Invocation.getFrontendOpts();
+ return Invocation->getFrontendOpts();
}
HeaderSearchOptions &getHeaderSearchOpts() {
- return Invocation.getHeaderSearchOpts();
+ return Invocation->getHeaderSearchOpts();
}
const HeaderSearchOptions &getHeaderSearchOpts() const {
- return Invocation.getHeaderSearchOpts();
+ return Invocation->getHeaderSearchOpts();
}
LangOptions &getLangOpts() {
- return Invocation.getLangOpts();
+ return Invocation->getLangOpts();
}
const LangOptions &getLangOpts() const {
- return Invocation.getLangOpts();
+ return Invocation->getLangOpts();
}
PreprocessorOptions &getPreprocessorOpts() {
- return Invocation.getPreprocessorOpts();
+ return Invocation->getPreprocessorOpts();
}
const PreprocessorOptions &getPreprocessorOpts() const {
- return Invocation.getPreprocessorOpts();
+ return Invocation->getPreprocessorOpts();
}
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
- return Invocation.getPreprocessorOutputOpts();
+ return Invocation->getPreprocessorOutputOpts();
}
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
- return Invocation.getPreprocessorOutputOpts();
+ return Invocation->getPreprocessorOutputOpts();
}
TargetOptions &getTargetOpts() {
- return Invocation.getTargetOpts();
+ return Invocation->getTargetOpts();
}
const TargetOptions &getTargetOpts() const {
- return Invocation.getTargetOpts();
+ return Invocation->getTargetOpts();
}
/// }
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index 13039bb5063e..b37c18057f0f 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -31,9 +31,12 @@ public:
unsigned ShowOptionNames : 1; /// Show the diagnostic name for mappable
/// diagnostics.
unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences.
- unsigned VerifyDiagnostics; /// Check that diagnostics match the expected
+ unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected
/// diagnostics, indicated by markers in the
/// input source file.
+ unsigned BinaryOutput : 1; /// Emit diagnostics via the diagnostic
+ /// binary serialization mechanism, to be
+ /// deserialized by, e.g., the CIndex library.
/// The distance between tab stops.
unsigned TabStop;
@@ -66,6 +69,7 @@ public:
ShowOptionNames = 0;
ShowSourceRanges = 0;
VerifyDiagnostics = 0;
+ BinaryOutput = 0;
}
};
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index 3042767af874..7b7db3785cf3 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -18,6 +18,7 @@ namespace clang {
class ASTUnit;
class ASTConsumer;
class CompilerInstance;
+class ASTMergeAction;
/// FrontendAction - Abstract base class for actions which can be performed by
/// the frontend.
@@ -25,6 +26,7 @@ class FrontendAction {
std::string CurrentFile;
llvm::OwningPtr<ASTUnit> CurrentASTUnit;
CompilerInstance *Instance;
+ friend class ASTMergeAction;
protected:
/// @name Implementation Action Interface
@@ -104,6 +106,10 @@ public:
return *CurrentASTUnit;
}
+ ASTUnit *takeCurrentASTUnit() {
+ return CurrentASTUnit.take();
+ }
+
void setCurrentFile(llvm::StringRef Value, ASTUnit *AST = 0);
/// @}
@@ -167,7 +173,7 @@ public:
};
/// ASTFrontendAction - Abstract base class to use for AST consumer based
-/// frontend actios.
+/// frontend actions.
class ASTFrontendAction : public FrontendAction {
/// ExecuteAction - Implement the ExecuteAction interface by running Sema on
/// the already initialized AST consumer.
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 33bb8aaf6e1d..cbb3508c8a76 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -11,6 +11,8 @@
#define LLVM_CLANG_FRONTEND_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
+#include <string>
+#include <vector>
namespace clang {
class FixItRewriter;
@@ -119,6 +121,43 @@ public:
virtual bool hasCodeCompletionSupport() const { return true; }
};
+/**
+ * \brief Frontend action adaptor that merges ASTs together.
+ *
+ * This action takes an existing AST file and "merges" it into the AST
+ * context, producing a merged context. This action is an action
+ * adaptor, which forwards most of its calls to another action that
+ * will consume the merged context.
+ */
+class ASTMergeAction : public FrontendAction {
+ /// \brief The action that the merge action adapts.
+ FrontendAction *AdaptedAction;
+
+ /// \brief The set of AST files to merge.
+ std::vector<std::string> ASTFiles;
+
+protected:
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile);
+
+ virtual bool BeginSourceFileAction(CompilerInstance &CI,
+ llvm::StringRef Filename);
+
+ virtual void ExecuteAction();
+ virtual void EndSourceFileAction();
+
+public:
+ ASTMergeAction(FrontendAction *AdaptedAction,
+ std::string *ASTFiles, unsigned NumASTFiles);
+ virtual ~ASTMergeAction();
+
+ virtual bool usesPreprocessorOnly() const;
+ virtual bool usesCompleteTranslationUnit();
+ virtual bool hasPCHSupport() const;
+ virtual bool hasASTSupport() const;
+ virtual bool hasCodeCompletionSupport() const;
+};
+
//===----------------------------------------------------------------------===//
// Code Gen AST Actions
//===----------------------------------------------------------------------===//
@@ -154,6 +193,11 @@ public:
EmitLLVMOnlyAction();
};
+class EmitObjAction : public CodeGenAction {
+public:
+ EmitObjAction();
+};
+
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 735a86a70fcb..80ba77864a5b 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -31,6 +31,7 @@ namespace frontend {
EmitHTML, ///< Translate input source into HTML.
EmitLLVM, ///< Emit a .ll file.
EmitLLVMOnly, ///< Generate LLVM IR, but do not
+ EmitObj, ///< Emit a .o file.
FixIt, ///< Parse and apply any fixits to the source.
GeneratePCH, ///< Generate pre-compiled header.
GeneratePTH, ///< Generate pre-tokenized header.
@@ -109,6 +110,9 @@ public:
/// The list of plugins to load.
std::vector<std::string> Plugins;
+ /// \brief The list of AST files to merge.
+ std::vector<std::string> ASTMergeFiles;
+
public:
FrontendOptions() {
DebugCodeCompletionPrinter = 1;
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index 1a9f4ceab933..e22d37ba34f5 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -221,7 +221,11 @@ namespace clang {
/// \brief Record code for the version control branch and revision
/// information of the compiler used to build this PCH file.
- VERSION_CONTROL_BRANCH_REVISION = 21
+ VERSION_CONTROL_BRANCH_REVISION = 21,
+
+ /// \brief Record code for the array of unused static functions.
+ UNUSED_STATIC_FUNCS = 22
+
};
/// \brief Record types used within a source manager block.
@@ -686,7 +690,11 @@ namespace clang {
// \brief A CXXConstCastExpr record.
EXPR_CXX_CONST_CAST,
// \brief A CXXFunctionalCastExpr record.
- EXPR_CXX_FUNCTIONAL_CAST
+ EXPR_CXX_FUNCTIONAL_CAST,
+ // \brief A CXXBoolLiteralExpr record.
+ EXPR_CXX_BOOL_LITERAL,
+ // \brief A CXXNullPtrLiteralExpr record.
+ EXPR_CXX_NULL_PTR_LITERAL
};
/// \brief The kinds of designators that can occur in a
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index 9665ce189f4a..065006fce5c4 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -306,6 +306,10 @@ private:
/// \brief The set of tentative definitions stored in the the PCH
/// file.
llvm::SmallVector<uint64_t, 16> TentativeDefinitions;
+
+ /// \brief The set of tentative definitions stored in the the PCH
+ /// file.
+ llvm::SmallVector<uint64_t, 16> UnusedStaticFuncs;
/// \brief The set of locally-scoped external declarations stored in
/// the the PCH file.
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 0f36df43e232..6a6e319463f0 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -199,6 +199,9 @@ public:
/// the current file.
SourceLocation getSourceLocation() { return getSourceLocation(BufferPtr); }
+ /// \brief Return the current location in the buffer.
+ const char *getBufferLocation() const { return BufferPtr; }
+
/// Stringify - Convert the specified string into a C string by escaping '\'
/// and " characters. This does not add surrounding ""'s to the string.
/// If Charify is true, this escapes the ' character instead of ".
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index 604eae1027aa..b5dde9a700e8 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -124,6 +124,10 @@ public:
UintData = L.getRawEncoding();
}
+ SourceLocation getLastLoc() const {
+ return isAnnotation() ? getAnnotationEndLoc() : getLocation();
+ }
+
/// getAnnotationRange - SourceRange of the group of tokens that this
/// annotation token represents.
SourceRange getAnnotationRange() const {
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index ff33f5039d5d..ec542f08c303 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -459,6 +459,8 @@ public:
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy();
}
+ virtual void ActOnObjCCatchParam(DeclPtrTy D) {
+ }
/// AddInitializerToDecl - This action is called immediately after
/// ActOnDeclarator (when an initializer is present). The code is factored
@@ -808,6 +810,11 @@ public:
return StmtEmpty();
}
+ /// ActOnSwitchBodyError - This is called if there is an error parsing the
+ /// body of the switch stmt instead of ActOnFinishSwitchStmt.
+ virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
+ StmtArg Body) {}
+
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body) {
return StmtEmpty();
@@ -897,7 +904,7 @@ public:
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
- std::string *Names,
+ IdentifierInfo **Names,
MultiExprArg Constraints,
MultiExprArg Exprs,
ExprArg AsmString,
@@ -1270,7 +1277,8 @@ public:
/// definition.
virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
IdentifierInfo *Ident,
- SourceLocation LBrace) {
+ SourceLocation LBrace,
+ AttributeList *AttrList) {
return DeclPtrTy();
}
@@ -1649,9 +1657,12 @@ public:
/// a well-formed program), ColonLoc is the location of the ':' that
/// starts the constructor initializer, and MemInit/NumMemInits
/// contains the individual member (and base) initializers.
+ /// AnyErrors will be true if there were any invalid member initializers
+ /// that are not represented in the list.
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits){
+ MemInitTy **MemInits, unsigned NumMemInits,
+ bool AnyErrors){
}
virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {}
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index f923b5e910db..4fe81a7eb5c2 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -153,6 +153,8 @@ private:
/*TSC*/unsigned TypeSpecComplex : 2;
/*TSS*/unsigned TypeSpecSign : 2;
/*TST*/unsigned TypeSpecType : 5;
+ bool TypeAltiVecVector : 1;
+ bool TypeAltiVecPixel : 1;
bool TypeSpecOwned : 1;
// type-qualifiers
@@ -193,7 +195,7 @@ private:
SourceRange Range;
SourceLocation StorageClassSpecLoc, SCS_threadLoc;
- SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc;
+ SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc, AltiVecLoc;
SourceRange TypeofParensRange;
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
@@ -213,6 +215,8 @@ public:
TypeSpecComplex(TSC_unspecified),
TypeSpecSign(TSS_unspecified),
TypeSpecType(TST_unspecified),
+ TypeAltiVecVector(false),
+ TypeAltiVecPixel(false),
TypeSpecOwned(false),
TypeQualifiers(TSS_unspecified),
FS_inline_specified(false),
@@ -250,6 +254,8 @@ public:
TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; }
TSS getTypeSpecSign() const { return (TSS)TypeSpecSign; }
TST getTypeSpecType() const { return (TST)TypeSpecType; }
+ bool isTypeAltiVecVector() const { return TypeAltiVecVector; }
+ bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; }
bool isTypeSpecOwned() const { return TypeSpecOwned; }
void *getTypeRep() const { return TypeRep; }
CXXScopeSpec &getTypeSpecScope() { return TypeScope; }
@@ -260,6 +266,7 @@ public:
SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; }
SourceLocation getTypeSpecSignLoc() const { return TSSLoc; }
SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; }
+ SourceLocation getAltiVecLoc() const { return AltiVecLoc; }
SourceRange getTypeofParensRange() const { return TypeofParensRange; }
void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
@@ -344,6 +351,10 @@ public:
unsigned &DiagID);
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, void *Rep = 0, bool Owned = false);
+ bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID);
+ bool SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID);
bool SetTypeSpecError();
void UpdateTypeRep(void *Rep) { TypeRep = Rep; }
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index e7cb0a2493d3..f4d3d3e54d51 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -81,6 +81,11 @@ class Parser {
/// Ident_super - IdentifierInfo for "super", to support fast
/// comparison.
IdentifierInfo *Ident_super;
+ /// Ident_vector and Ident_pixel - cached IdentifierInfo's for
+ /// "vector" and "pixel" fast comparison. Only present if
+ /// AltiVec enabled.
+ IdentifierInfo *Ident_vector;
+ IdentifierInfo *Ident_pixel;
llvm::OwningPtr<PragmaHandler> PackHandler;
llvm::OwningPtr<PragmaHandler> UnusedHandler;
@@ -320,6 +325,81 @@ private:
/// annotated.
bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
+ /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens,
+ /// replacing them with the non-context-sensitive keywords. This returns
+ /// true if the token was replaced.
+ bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) {
+ if (getLang().AltiVec) {
+ if (Tok.getIdentifierInfo() == Ident_vector) {
+ const Token nextToken = NextToken();
+ switch (nextToken.getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw___pixel:
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ return true;
+ case tok::identifier:
+ if (nextToken.getIdentifierInfo() == Ident_pixel) {
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if ((Tok.getIdentifierInfo() == Ident_pixel) &&
+ DS.isTypeAltiVecVector()) {
+ isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// TryAltiVecVectorToken - Check for context-sensitive AltiVec vector
+ /// identifier token, replacing it with the non-context-sensitive __vector.
+ /// This returns true if the token was replaced.
+ bool TryAltiVecVectorToken() {
+ if (getLang().AltiVec) {
+ if (Tok.getIdentifierInfo() == Ident_vector) {
+ const Token nextToken = NextToken();
+ switch (nextToken.getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw___pixel:
+ Tok.setKind(tok::kw___vector);
+ return true;
+ case tok::identifier:
+ if (nextToken.getIdentifierInfo() == Ident_pixel) {
+ Tok.setKind(tok::kw___vector);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return false;
+ }
+
/// TentativeParsingAction - An object that is used as a kind of "tentative
/// parsing transaction". It gets instantiated to mark the token position and
/// after the token consumption is done, Commit() or Revert() is called to
@@ -1009,9 +1089,9 @@ private:
OwningStmtResult ParseReturnStatement(AttributeList *Attr);
OwningStmtResult ParseAsmStatement(bool &msAsm);
OwningStmtResult FuzzyParseMicrosoftAsmStatement();
- bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
- llvm::SmallVectorImpl<ExprTy*> &Constraints,
- llvm::SmallVectorImpl<ExprTy*> &Exprs);
+ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
+ llvm::SmallVectorImpl<ExprTy *> &Constraints,
+ llvm::SmallVectorImpl<ExprTy *> &Exprs);
//===--------------------------------------------------------------------===//
// C++ 6: Statements and Blocks
@@ -1065,7 +1145,8 @@ private:
bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid,
const char *&PrevSpec,
unsigned &DiagID,
- const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
+ bool SuppressDeclarations = false);
void ParseSpecifierQualifierList(DeclSpec &DS);
@@ -1311,7 +1392,8 @@ private:
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
- AccessSpecifier AS = AS_none);
+ AccessSpecifier AS = AS_none,
+ bool SuppressDeclarations = false);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
DeclPtrTy TagDecl);
void ParseCXXClassMemberDeclaration(AccessSpecifier AS,
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c1bc70989d4e..c23babb9a4a5 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -56,6 +56,10 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
}
ASTContext::~ASTContext() {
+ // Release the DenseMaps associated with DeclContext objects.
+ // FIXME: Is this the ideal solution?
+ ReleaseDeclContextMaps();
+
if (FreeMemory) {
// Deallocate all the types.
while (!Types.empty()) {
@@ -533,12 +537,12 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
}
}
-/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the
+/// getDeclAlign - Return a conservative estimate of the alignment of the
/// specified decl. Note that bitfields do not have a valid alignment, so
/// this method will assert on them.
/// If @p RefAsPointee, references are treated like their underlying type
/// (for alignof), else they're treated like pointers (for CodeGen).
-unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) {
+CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) {
unsigned Align = Target.getCharWidth();
if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
@@ -561,7 +565,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) {
}
}
- return Align / Target.getCharWidth();
+ return CharUnits::fromQuantity(Align / Target.getCharWidth());
}
/// getTypeSize - Return the size of the specified type, in bits. This method
@@ -820,6 +824,15 @@ CharUnits ASTContext::getTypeSizeInChars(const Type *T) {
return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
}
+/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
+/// characters. This method does not work on incomplete types.
+CharUnits ASTContext::getTypeAlignInChars(QualType T) {
+ return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth());
+}
+CharUnits ASTContext::getTypeAlignInChars(const Type *T) {
+ return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth());
+}
+
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
/// type for the current target in bits. This can be different than the ABI
/// alignment in cases where it is beneficial for performance to overalign
@@ -904,12 +917,12 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
/// CollectInheritedProtocols - Collect all protocols in current class and
/// those inherited by it.
void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
- llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols) {
+ llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols) {
if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
PE = OI->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.push_back(Proto);
+ Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -930,7 +943,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(),
PE = OC->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.push_back(Proto);
+ Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -941,7 +954,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(),
PE = OP->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.push_back(Proto);
+ Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -1088,7 +1101,7 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) {
/// specified record (struct/union/class), which indicates its size and field
/// position information.
const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
- D = D->getDefinition(*this);
+ D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
// Look up this layout, if already laid out, return what we have.
@@ -1105,7 +1118,7 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
}
const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
- RD = cast<CXXRecordDecl>(RD->getDefinition(*this));
+ RD = cast<CXXRecordDecl>(RD->getDefinition());
assert(RD && "Cannot get key function for forward declarations!");
const CXXMethodDecl *&Entry = KeyFunctions[RD];
@@ -1519,12 +1532,12 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
void *InsertPos = 0;
DependentSizedArrayType *Canon = 0;
+ llvm::FoldingSetNodeID ID;
if (NumElts) {
// Dependently-sized array types that do not have a specified
// number of elements will have their sizes deduced from an
// initializer.
- llvm::FoldingSetNodeID ID;
DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
EltTypeQuals, NumElts);
@@ -1545,8 +1558,13 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
DependentSizedArrayType(*this, EltTy, QualType(),
NumElts, ASM, EltTypeQuals, Brackets);
- if (NumElts)
+ if (NumElts) {
+ DependentSizedArrayType *CanonCheck
+ = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CanonCheck && "Dependent-sized canonical array type broken");
+ (void)CanonCheck;
DependentSizedArrayTypes.InsertNode(New, InsertPos);
+ }
} else {
QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
ASM, EltTypeQuals,
@@ -1596,7 +1614,8 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy,
/// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type.
-QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
+QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
+ bool IsAltiVec, bool IsPixel) {
BuiltinType *baseType;
baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
@@ -1604,7 +1623,8 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
- VectorType::Profile(ID, vecType, NumElts, Type::Vector);
+ VectorType::Profile(ID, vecType, NumElts, Type::Vector,
+ IsAltiVec, IsPixel);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -1612,15 +1632,16 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
// If the element type isn't canonical, this won't be a canonical type either,
// so fill in the canonical type field.
QualType Canonical;
- if (!vecType.isCanonical()) {
- Canonical = getVectorType(getCanonicalType(vecType), NumElts);
+ if (!vecType.isCanonical() || IsAltiVec || IsPixel) {
+ Canonical = getVectorType(getCanonicalType(vecType),
+ NumElts, false, false);
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
}
VectorType *New = new (*this, TypeAlignment)
- VectorType(vecType, NumElts, Canonical);
+ VectorType(vecType, NumElts, Canonical, IsAltiVec, IsPixel);
VectorTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
@@ -1636,7 +1657,7 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
- VectorType::Profile(ID, vecType, NumElts, Type::ExtVector);
+ VectorType::Profile(ID, vecType, NumElts, Type::ExtVector, false, false);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -1681,6 +1702,11 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
New = new (*this, TypeAlignment)
DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr,
AttrLoc);
+
+ DependentSizedExtVectorType *CanonCheck
+ = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CanonCheck && "Dependent-sized ext_vector canonical type broken");
+ (void)CanonCheck;
DependentSizedExtVectorTypes.InsertNode(New, InsertPos);
} else {
QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
@@ -1694,12 +1720,6 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
return QualType(New, 0);
}
-static CallingConv getCanonicalCallingConv(CallingConv CC) {
- if (CC == CC_C)
- return CC_Default;
- return CC;
-}
-
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
@@ -1707,7 +1727,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionNoProtoType::Profile(ID, ResultTy, NoReturn);
+ FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv);
void *InsertPos = 0;
if (FunctionNoProtoType *FT =
@@ -1716,9 +1736,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
QualType Canonical;
if (!ResultTy.isCanonical() ||
- getCanonicalCallingConv(CallConv) != CallConv) {
+ getCanonicalCallConv(CallConv) != CallConv) {
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
- getCanonicalCallingConv(CallConv));
+ getCanonicalCallConv(CallConv));
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -1727,7 +1747,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
}
FunctionNoProtoType *New = new (*this, TypeAlignment)
- FunctionNoProtoType(ResultTy, Canonical, NoReturn);
+ FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1746,7 +1766,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
llvm::FoldingSetNodeID ID;
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- NumExs, ExArray, NoReturn);
+ NumExs, ExArray, NoReturn, CallConv);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -1762,7 +1782,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical;
- if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) {
+ if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
llvm::SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -1772,7 +1792,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals, false,
false, 0, 0, NoReturn,
- getCanonicalCallingConv(CallConv));
+ getCanonicalCallConv(CallConv));
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -1797,29 +1817,30 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
/// getTypeDeclType - Return the unique reference to the type for the
/// specified type declaration.
-QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
+QualType ASTContext::getTypeDeclType(const TypeDecl *Decl,
+ const TypeDecl* PrevDecl) {
assert(Decl && "Passed null for Decl param");
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
- if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
+ if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
return getTypedefType(Typedef);
else if (isa<TemplateTypeParmDecl>(Decl)) {
assert(false && "Template type parameter types are always available.");
- } else if (ObjCInterfaceDecl *ObjCInterface
+ } else if (const ObjCInterfaceDecl *ObjCInterface
= dyn_cast<ObjCInterfaceDecl>(Decl))
return getObjCInterfaceType(ObjCInterface);
- if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
+ if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
if (PrevDecl)
Decl->TypeForDecl = PrevDecl->TypeForDecl;
else
Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record);
- } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
+ } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
if (PrevDecl)
Decl->TypeForDecl = PrevDecl->TypeForDecl;
else
Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum);
- } else if (UnresolvedUsingTypenameDecl *Using =
+ } else if (const UnresolvedUsingTypenameDecl *Using =
dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using);
} else
@@ -1831,7 +1852,7 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
/// getTypedefType - Return the unique reference to the type for the
/// specified typename decl.
-QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
+QualType ASTContext::getTypedefType(const TypedefDecl *Decl) {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
@@ -1883,6 +1904,11 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack);
TypeParm = new (*this, TypeAlignment)
TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon);
+
+ TemplateTypeParmType *TypeCheck
+ = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!TypeCheck && "Template type parameter canonical type broken");
+ (void)TypeCheck;
} else
TypeParm = new (*this, TypeAlignment)
TemplateTypeParmType(Depth, Index, ParameterPack);
@@ -1976,8 +2002,16 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
if (T)
return QualType(T, 0);
- T = new (*this) QualifiedNameType(NNS, NamedType,
- getCanonicalType(NamedType));
+ QualType Canon = NamedType;
+ if (!Canon.isCanonical()) {
+ Canon = getCanonicalType(NamedType);
+ QualifiedNameType *CheckT
+ = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Qualified name canonical type broken");
+ (void)CheckT;
+ }
+
+ T = new (*this) QualifiedNameType(NNS, NamedType, Canon);
Types.push_back(T);
QualifiedNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
@@ -2015,6 +2049,15 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+ llvm::FoldingSetNodeID ID;
+ TypenameType::Profile(ID, NNS, TemplateId);
+
+ void *InsertPos = 0;
+ TypenameType *T
+ = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
@@ -2025,16 +2068,11 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS,
"Canonical type must also be a template specialization type");
Canon = getTypenameType(CanonNNS, CanonTemplateId);
}
- }
- llvm::FoldingSetNodeID ID;
- TypenameType::Profile(ID, NNS, TemplateId);
-
- void *InsertPos = 0;
- TypenameType *T
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (T)
- return QualType(T, 0);
+ TypenameType *CheckT
+ = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Typename canonical type is broken"); (void)CheckT;
+ }
T = new (*this) TypenameType(NNS, TemplateId, Canon);
Types.push_back(T);
@@ -2053,7 +2091,12 @@ ASTContext::getElaboratedType(QualType UnderlyingType,
if (T)
return QualType(T, 0);
- QualType Canon = getCanonicalType(UnderlyingType);
+ QualType Canon = UnderlyingType;
+ if (!Canon.isCanonical()) {
+ Canon = getCanonicalType(Canon);
+ ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Elaborated canonical type is broken"); (void)CheckT;
+ }
T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon);
Types.push_back(T);
@@ -2125,10 +2168,14 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
}
- // No Match;
- ObjCObjectPointerType *QType = new (*this, TypeAlignment)
- ObjCObjectPointerType(*this, Canonical, InterfaceT, Protocols,
- NumProtocols);
+ // No match.
+ unsigned Size = sizeof(ObjCObjectPointerType)
+ + NumProtocols * sizeof(ObjCProtocolDecl *);
+ void *Mem = Allocate(Size, TypeAlignment);
+ ObjCObjectPointerType *QType = new (Mem) ObjCObjectPointerType(Canonical,
+ InterfaceT,
+ Protocols,
+ NumProtocols);
Types.push_back(QType);
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
@@ -2161,9 +2208,13 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos);
}
- ObjCInterfaceType *QType = new (*this, TypeAlignment)
- ObjCInterfaceType(*this, Canonical, const_cast<ObjCInterfaceDecl*>(Decl),
- Protocols, NumProtocols);
+ unsigned Size = sizeof(ObjCInterfaceType)
+ + NumProtocols * sizeof(ObjCProtocolDecl *);
+ void *Mem = Allocate(Size, TypeAlignment);
+ ObjCInterfaceType *QType = new (Mem) ObjCInterfaceType(Canonical,
+ const_cast<ObjCInterfaceDecl*>(Decl),
+ Protocols,
+ NumProtocols);
Types.push_back(QType);
ObjCInterfaceTypes.InsertNode(QType, InsertPos);
@@ -2858,6 +2909,7 @@ QualType ASTContext::getCFConstantStringType() {
CFConstantStringTypeDecl =
CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("NSConstantString"));
+ CFConstantStringTypeDecl->startDefinition();
QualType FieldTypes[4];
@@ -2880,7 +2932,7 @@ QualType ASTContext::getCFConstantStringType() {
CFConstantStringTypeDecl->addDecl(Field);
}
- CFConstantStringTypeDecl->completeDefinition(*this);
+ CFConstantStringTypeDecl->completeDefinition();
}
return getTagDeclType(CFConstantStringTypeDecl);
@@ -2897,6 +2949,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
ObjCFastEnumerationStateTypeDecl =
CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__objcFastEnumerationState"));
+ ObjCFastEnumerationStateTypeDecl->startDefinition();
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2916,7 +2969,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
- ObjCFastEnumerationStateTypeDecl->completeDefinition(*this);
+ ObjCFastEnumerationStateTypeDecl->completeDefinition();
}
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
@@ -2930,6 +2983,7 @@ QualType ASTContext::getBlockDescriptorType() {
// FIXME: Needs the FlagAppleBlock bit.
T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__block_descriptor"));
+ T->startDefinition();
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2952,7 +3006,7 @@ QualType ASTContext::getBlockDescriptorType() {
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
BlockDescriptorType = T;
@@ -2973,6 +3027,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
// FIXME: Needs the FlagAppleBlock bit.
T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__block_descriptor_withcopydispose"));
+ T->startDefinition();
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2999,7 +3054,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
BlockDescriptorExtendedType = T;
@@ -3076,7 +3131,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
return getPointerType(getTagDeclType(T));
}
@@ -3093,6 +3148,7 @@ QualType ASTContext::getBlockParmType(
RecordDecl *T;
T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get(Name.str()));
+ T->startDefinition();
QualType FieldTypes[] = {
getPointerType(VoidPtrTy),
IntTy,
@@ -3139,7 +3195,7 @@ QualType ASTContext::getBlockParmType(
T->addDecl(Field);
}
- T->completeDefinition(*this);
+ T->completeDefinition();
return getPointerType(getTagDeclType(T));
}
@@ -3786,6 +3842,7 @@ TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
bool TemplateKeyword,
TemplateDecl *Template) {
+ // FIXME: Canonicalization?
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
@@ -3823,6 +3880,10 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
} else {
TemplateName Canon = getDependentTemplateName(CanonNNS, Name);
QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon);
+ DependentTemplateName *CheckQTN =
+ DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckQTN && "Dependent type name canonicalization broken");
+ (void)CheckQTN;
}
DependentTemplateNames.InsertNode(QTN, InsertPos);
@@ -3841,8 +3902,8 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
DependentTemplateName::Profile(ID, NNS, Operator);
void *InsertPos = 0;
- DependentTemplateName *QTN =
- DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ DependentTemplateName *QTN
+ = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
if (QTN)
return TemplateName(QTN);
@@ -3853,6 +3914,11 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
} else {
TemplateName Canon = getDependentTemplateName(CanonNNS, Operator);
QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon);
+
+ DependentTemplateName *CheckQTN
+ = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckQTN && "Dependent template name canonicalization broken");
+ (void)CheckQTN;
}
DependentTemplateNames.InsertNode(QTN, InsertPos);
@@ -4123,8 +4189,8 @@ void getIntersectionOfProtocols(ASTContext &Context,
if (LHSNumProtocols > 0)
InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end());
else {
- llvm::SmallVector<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
- Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols);
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
+ Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols);
InheritedProtocolSet.insert(LHSInheritedProtocols.begin(),
LHSInheritedProtocols.end());
}
@@ -4137,13 +4203,13 @@ void getIntersectionOfProtocols(ASTContext &Context,
IntersectionOfProtocols.push_back(RHSProtocols[i]);
}
else {
- llvm::SmallVector<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols;
Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols);
- // FIXME. This may cause duplication of protocols in the list, but should
- // be harmless.
- for (unsigned i = 0, len = RHSInheritedProtocols.size(); i < len; ++i)
- if (InheritedProtocolSet.count(RHSInheritedProtocols[i]))
- IntersectionOfProtocols.push_back(RHSInheritedProtocols[i]);
+ for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
+ RHSInheritedProtocols.begin(),
+ E = RHSInheritedProtocols.end(); I != E; ++I)
+ if (InheritedProtocolSet.count((*I)))
+ IntersectionOfProtocols.push_back((*I));
}
}
@@ -4235,13 +4301,12 @@ bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
/// C99 6.2.7p1: Two types have compatible types if their types are the
/// same. See 6.7.[2,3,5] for additional rules.
bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
+ if (getLangOptions().CPlusPlus)
+ return hasSameType(LHS, RHS);
+
return !mergeTypes(LHS, RHS).isNull();
}
-static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) {
- return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc));
-}
-
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
const FunctionType *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>();
@@ -4266,7 +4331,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
CallingConv lcc = lbase->getCallConv();
CallingConv rcc = rbase->getCallConv();
// Compatible functions must have compatible calling conventions
- if (!isSameCallingConvention(lcc, rcc))
+ if (!isSameCallConv(lcc, rcc))
return QualType();
if (lproto && rproto) { // two C99 style function prototypes
@@ -4303,7 +4368,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
lproto->isVariadic(), lproto->getTypeQuals(),
- NoReturn, lcc);
+ false, false, 0, 0, NoReturn, lcc);
}
if (lproto) allRTypes = false;
@@ -4321,6 +4386,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
unsigned proto_nargs = proto->getNumArgs();
for (unsigned i = 0; i < proto_nargs; ++i) {
QualType argTy = proto->getArgType(i);
+
+ // Look at the promotion type of enum types, since that is the type used
+ // to pass enum values.
+ if (const EnumType *Enum = argTy->getAs<EnumType>())
+ argTy = Enum->getDecl()->getPromotionType();
+
if (argTy->isPromotableIntegerType() ||
getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
return QualType();
@@ -4344,15 +4415,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
// designates the object or function denoted by the reference, and the
// expression is an lvalue unless the reference is an rvalue reference and
// the expression is a function call (possibly inside parentheses).
- // FIXME: C++ shouldn't be going through here! The rules are different
- // enough that they should be handled separately.
- // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really*
- // shouldn't be going through here!
- if (const ReferenceType *RT = LHS->getAs<ReferenceType>())
- LHS = RT->getPointeeType();
- if (const ReferenceType *RT = RHS->getAs<ReferenceType>())
- RHS = RT->getPointeeType();
-
+ assert(!LHS->getAs<ReferenceType>() && "LHS is a reference type?");
+ assert(!RHS->getAs<ReferenceType>() && "RHS is a reference type?");
+
QualType LHSCan = getCanonicalType(LHS),
RHSCan = getCanonicalType(RHS);
@@ -4582,7 +4647,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
// Turn <4 x signed int> -> <4 x unsigned int>
if (const VectorType *VTy = T->getAs<VectorType>())
return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()),
- VTy->getNumElements());
+ VTy->getNumElements(), VTy->isAltiVec(), VTy->isPixel());
// For enums, we return the unsigned version of the base type.
if (const EnumType *ETy = T->getAs<EnumType>())
@@ -4739,7 +4804,8 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
Str = End;
QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
- Type = Context.getVectorType(ElementType, NumElements);
+ // FIXME: Don't know what to do about AltiVec.
+ Type = Context.getVectorType(ElementType, NumElements, false, false);
break;
}
case 'X': {
@@ -4784,6 +4850,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
case 'C':
Type = Type.withConst();
break;
+ case 'D':
+ Type = Context.getVolatileType(Type);
+ break;
}
}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
new file mode 100644
index 000000000000..7402b7dda4ec
--- /dev/null
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -0,0 +1,266 @@
+//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===//
+//
+// 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 diagnostic formatting hook for AST elements.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTDiagnostic.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+/// Determines whether we should have an a.k.a. clause when
+/// pretty-printing a type. There are three main criteria:
+///
+/// 1) Some types provide very minimal sugar that doesn't impede the
+/// user's understanding --- for example, elaborated type
+/// specifiers. If this is all the sugar we see, we don't want an
+/// a.k.a. clause.
+/// 2) Some types are technically sugared but are much more familiar
+/// when seen in their sugared form --- for example, va_list,
+/// vector types, and the magic Objective C types. We don't
+/// want to desugar these, even if we do produce an a.k.a. clause.
+/// 3) Some types may have already been desugared previously in this diagnostic.
+/// if this is the case, doing another "aka" would just be clutter.
+///
+static bool ShouldAKA(ASTContext &Context, QualType QT,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs,
+ QualType &DesugaredQT) {
+ QualType InputTy = QT;
+
+ bool AKA = false;
+ QualifierCollector Qc;
+
+ while (true) {
+ const Type *Ty = Qc.strip(QT);
+
+ // Don't aka just because we saw an elaborated type...
+ if (isa<ElaboratedType>(Ty)) {
+ QT = cast<ElaboratedType>(Ty)->desugar();
+ continue;
+ }
+
+ // ...or a qualified name type...
+ if (isa<QualifiedNameType>(Ty)) {
+ QT = cast<QualifiedNameType>(Ty)->desugar();
+ continue;
+ }
+
+ // ...or a substituted template type parameter.
+ if (isa<SubstTemplateTypeParmType>(Ty)) {
+ QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
+ continue;
+ }
+
+ // Don't desugar template specializations.
+ if (isa<TemplateSpecializationType>(Ty))
+ break;
+
+ // Don't desugar magic Objective-C types.
+ if (QualType(Ty,0) == Context.getObjCIdType() ||
+ QualType(Ty,0) == Context.getObjCClassType() ||
+ QualType(Ty,0) == Context.getObjCSelType() ||
+ QualType(Ty,0) == Context.getObjCProtoType())
+ break;
+
+ // Don't desugar va_list.
+ if (QualType(Ty,0) == Context.getBuiltinVaListType())
+ break;
+
+ // Otherwise, do a single-step desugar.
+ QualType Underlying;
+ bool IsSugar = false;
+ switch (Ty->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Base)
+#define TYPE(Class, Base) \
+case Type::Class: { \
+const Class##Type *CTy = cast<Class##Type>(Ty); \
+if (CTy->isSugared()) { \
+IsSugar = true; \
+Underlying = CTy->desugar(); \
+} \
+break; \
+}
+#include "clang/AST/TypeNodes.def"
+ }
+
+ // If it wasn't sugared, we're done.
+ if (!IsSugar)
+ break;
+
+ // If the desugared type is a vector type, we don't want to expand
+ // it, it will turn into an attribute mess. People want their "vec4".
+ if (isa<VectorType>(Underlying))
+ break;
+
+ // Don't desugar through the primary typedef of an anonymous type.
+ if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
+ if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
+ cast<TypedefType>(QT)->getDecl())
+ break;
+
+ // Otherwise, we're tearing through something opaque; note that
+ // we'll eventually need an a.k.a. clause and keep going.
+ AKA = true;
+ QT = Underlying;
+ continue;
+ }
+
+ // If we never tore through opaque sugar, don't print aka.
+ if (!AKA) return false;
+
+ // If we did, check to see if we already desugared this type in this
+ // diagnostic. If so, don't do it again.
+ for (unsigned i = 0; i != NumPrevArgs; ++i) {
+ // TODO: Handle ak_declcontext case.
+ if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
+ void *Ptr = (void*)PrevArgs[i].second;
+ QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
+ if (PrevTy == InputTy)
+ return false;
+ }
+ }
+
+ DesugaredQT = Qc.apply(QT);
+ return true;
+}
+
+/// \brief Convert the given type to a string suitable for printing as part of
+/// a diagnostic.
+///
+/// \param Context the context in which the type was allocated
+/// \param Ty the type to print
+static std::string
+ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs) {
+ // FIXME: Playing with std::string is really slow.
+ std::string S = Ty.getAsString(Context.PrintingPolicy);
+
+ // Consider producing an a.k.a. clause if removing all the direct
+ // sugar gives us something "significantly different".
+
+ QualType DesugaredTy;
+ if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
+ S = "'"+S+"' (aka '";
+ S += DesugaredTy.getAsString(Context.PrintingPolicy);
+ S += "')";
+ return S;
+ }
+
+ S = "'" + S + "'";
+ return S;
+}
+
+void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
+ intptr_t Val,
+ const char *Modifier,
+ unsigned ModLen,
+ const char *Argument,
+ unsigned ArgLen,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie) {
+ ASTContext &Context = *static_cast<ASTContext*>(Cookie);
+
+ std::string S;
+ bool NeedQuotes = true;
+
+ switch (Kind) {
+ default: assert(0 && "unknown ArgumentKind");
+ case Diagnostic::ak_qualtype: {
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for QualType argument");
+
+ QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
+ S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
+ NeedQuotes = false;
+ break;
+ }
+ case Diagnostic::ak_declarationname: {
+ DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
+ S = N.getAsString();
+
+ if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
+ S = '+' + S;
+ else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
+ && ArgLen==0)
+ S = '-' + S;
+ else
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for DeclarationName argument");
+ break;
+ }
+ case Diagnostic::ak_nameddecl: {
+ bool Qualified;
+ if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
+ Qualified = true;
+ else {
+ assert(ModLen == 0 && ArgLen == 0 &&
+ "Invalid modifier for NamedDecl* argument");
+ Qualified = false;
+ }
+ reinterpret_cast<NamedDecl*>(Val)->
+ getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
+ break;
+ }
+ case Diagnostic::ak_nestednamespec: {
+ llvm::raw_string_ostream OS(S);
+ reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
+ Context.PrintingPolicy);
+ NeedQuotes = false;
+ break;
+ }
+ case Diagnostic::ak_declcontext: {
+ DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
+ assert(DC && "Should never have a null declaration context");
+
+ if (DC->isTranslationUnit()) {
+ // FIXME: Get these strings from some localized place
+ if (Context.getLangOptions().CPlusPlus)
+ S = "the global namespace";
+ else
+ S = "the global scope";
+ } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
+ S = ConvertTypeToDiagnosticString(Context,
+ Context.getTypeDeclType(Type),
+ PrevArgs, NumPrevArgs);
+ } else {
+ // FIXME: Get these strings from some localized place
+ NamedDecl *ND = cast<NamedDecl>(DC);
+ if (isa<NamespaceDecl>(ND))
+ S += "namespace ";
+ else if (isa<ObjCMethodDecl>(ND))
+ S += "method ";
+ else if (isa<FunctionDecl>(ND))
+ S += "function ";
+
+ S += "'";
+ ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
+ S += "'";
+ }
+ NeedQuotes = false;
+ break;
+ }
+ }
+
+ if (NeedQuotes)
+ Output.push_back('\'');
+
+ Output.append(S.begin(), S.end());
+
+ if (NeedQuotes)
+ Output.push_back('\'');
+}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
new file mode 100644
index 000000000000..dee0d2b342fc
--- /dev/null
+++ b/lib/AST/ASTImporter.cpp
@@ -0,0 +1,2394 @@
+//===--- ASTImporter.cpp - Importing ASTs from other Contexts ---*- 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 ASTImporter class which imports AST nodes from one
+// context into another context.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTImporter.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <deque>
+
+using namespace clang;
+
+namespace {
+ class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>,
+ public DeclVisitor<ASTNodeImporter, Decl *>,
+ public StmtVisitor<ASTNodeImporter, Stmt *> {
+ ASTImporter &Importer;
+
+ public:
+ explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { }
+
+ using TypeVisitor<ASTNodeImporter, QualType>::Visit;
+ using DeclVisitor<ASTNodeImporter, Decl *>::Visit;
+ using StmtVisitor<ASTNodeImporter, Stmt *>::Visit;
+
+ // Importing types
+ QualType VisitType(Type *T);
+ QualType VisitBuiltinType(BuiltinType *T);
+ QualType VisitComplexType(ComplexType *T);
+ QualType VisitPointerType(PointerType *T);
+ QualType VisitBlockPointerType(BlockPointerType *T);
+ QualType VisitLValueReferenceType(LValueReferenceType *T);
+ QualType VisitRValueReferenceType(RValueReferenceType *T);
+ QualType VisitMemberPointerType(MemberPointerType *T);
+ QualType VisitConstantArrayType(ConstantArrayType *T);
+ QualType VisitIncompleteArrayType(IncompleteArrayType *T);
+ QualType VisitVariableArrayType(VariableArrayType *T);
+ // FIXME: DependentSizedArrayType
+ // FIXME: DependentSizedExtVectorType
+ QualType VisitVectorType(VectorType *T);
+ QualType VisitExtVectorType(ExtVectorType *T);
+ QualType VisitFunctionNoProtoType(FunctionNoProtoType *T);
+ QualType VisitFunctionProtoType(FunctionProtoType *T);
+ // FIXME: UnresolvedUsingType
+ QualType VisitTypedefType(TypedefType *T);
+ QualType VisitTypeOfExprType(TypeOfExprType *T);
+ // FIXME: DependentTypeOfExprType
+ QualType VisitTypeOfType(TypeOfType *T);
+ QualType VisitDecltypeType(DecltypeType *T);
+ // FIXME: DependentDecltypeType
+ QualType VisitRecordType(RecordType *T);
+ QualType VisitEnumType(EnumType *T);
+ QualType VisitElaboratedType(ElaboratedType *T);
+ // FIXME: TemplateTypeParmType
+ // FIXME: SubstTemplateTypeParmType
+ // FIXME: TemplateSpecializationType
+ QualType VisitQualifiedNameType(QualifiedNameType *T);
+ // FIXME: TypenameType
+ QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
+ QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
+
+ // Importing declarations
+ bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
+ DeclContext *&LexicalDC, DeclarationName &Name,
+ SourceLocation &Loc);
+ bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord);
+ bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
+ Decl *VisitDecl(Decl *D);
+ Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitEnumDecl(EnumDecl *D);
+ Decl *VisitRecordDecl(RecordDecl *D);
+ Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D);
+ Decl *VisitFieldDecl(FieldDecl *D);
+ Decl *VisitVarDecl(VarDecl *D);
+ Decl *VisitParmVarDecl(ParmVarDecl *D);
+ Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+
+ // Importing statements
+ Stmt *VisitStmt(Stmt *S);
+
+ // Importing expressions
+ Expr *VisitExpr(Expr *E);
+ Expr *VisitIntegerLiteral(IntegerLiteral *E);
+ Expr *VisitImplicitCastExpr(ImplicitCastExpr *E);
+ };
+}
+
+//----------------------------------------------------------------------------
+// Structural Equivalence
+//----------------------------------------------------------------------------
+
+namespace {
+ struct StructuralEquivalenceContext {
+ /// \brief AST contexts for which we are checking structural equivalence.
+ ASTContext &C1, &C2;
+
+ /// \brief Diagnostic object used to emit diagnostics.
+ Diagnostic &Diags;
+
+ /// \brief The set of "tentative" equivalences between two canonical
+ /// declarations, mapping from a declaration in the first context to the
+ /// declaration in the second context that we believe to be equivalent.
+ llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
+
+ /// \brief Queue of declarations in the first context whose equivalence
+ /// with a declaration in the second context still needs to be verified.
+ std::deque<Decl *> DeclsToCheck;
+
+ /// \brief Declaration (from, to) pairs that are known not to be equivalent
+ /// (which we have already complained about).
+ llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls;
+
+ /// \brief Whether we're being strict about the spelling of types when
+ /// unifying two types.
+ bool StrictTypeSpelling;
+
+ StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
+ Diagnostic &Diags,
+ llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
+ bool StrictTypeSpelling = false)
+ : C1(C1), C2(C2), Diags(Diags), NonEquivalentDecls(NonEquivalentDecls),
+ StrictTypeSpelling(StrictTypeSpelling) { }
+
+ /// \brief Determine whether the two declarations are structurally
+ /// equivalent.
+ bool IsStructurallyEquivalent(Decl *D1, Decl *D2);
+
+ /// \brief Determine whether the two types are structurally equivalent.
+ bool IsStructurallyEquivalent(QualType T1, QualType T2);
+
+ private:
+ /// \brief Finish checking all of the structural equivalences.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool Finish();
+
+ public:
+ DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, C1.getSourceManager()), DiagID);
+ }
+
+ DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, C2.getSourceManager()), DiagID);
+ }
+ };
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2);
+
+/// \brief Determine if two APInts have the same value, after zero-extending
+/// one of them (if needed!) to ensure that the bit-widths match.
+static bool IsSameValue(const llvm::APInt &I1, const llvm::APInt &I2) {
+ if (I1.getBitWidth() == I2.getBitWidth())
+ return I1 == I2;
+
+ if (I1.getBitWidth() > I2.getBitWidth())
+ return I1 == llvm::APInt(I2).zext(I1.getBitWidth());
+
+ return llvm::APInt(I1).zext(I2.getBitWidth()) == I2;
+}
+
+/// \brief Determine if two APSInts have the same value, zero- or sign-extending
+/// as needed.
+static bool IsSameValue(const llvm::APSInt &I1, const llvm::APSInt &I2) {
+ if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned())
+ return I1 == I2;
+
+ // Check for a bit-width mismatch.
+ if (I1.getBitWidth() > I2.getBitWidth())
+ return IsSameValue(I1, llvm::APSInt(I2).extend(I1.getBitWidth()));
+ else if (I2.getBitWidth() > I1.getBitWidth())
+ return IsSameValue(llvm::APSInt(I1).extend(I2.getBitWidth()), I2);
+
+ // We have a signedness mismatch. Turn the signed value into an unsigned
+ // value.
+ if (I1.isSigned()) {
+ if (I1.isNegative())
+ return false;
+
+ return llvm::APSInt(I1, true) == I2;
+ }
+
+ if (I2.isNegative())
+ return false;
+
+ return I1 == llvm::APSInt(I2, true);
+}
+
+/// \brief Determine structural equivalence of two expressions.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Expr *E1, Expr *E2) {
+ if (!E1 || !E2)
+ return E1 == E2;
+
+ // FIXME: Actually perform a structural comparison!
+ return true;
+}
+
+/// \brief Determine whether two identifiers are equivalent.
+static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
+ const IdentifierInfo *Name2) {
+ if (!Name1 || !Name2)
+ return Name1 == Name2;
+
+ return Name1->getName() == Name2->getName();
+}
+
+/// \brief Determine whether two nested-name-specifiers are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NestedNameSpecifier *NNS1,
+ NestedNameSpecifier *NNS2) {
+ // FIXME: Implement!
+ return true;
+}
+
+/// \brief Determine whether two template arguments are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgument &Arg1,
+ const TemplateArgument &Arg2) {
+ // FIXME: Implement!
+ return true;
+}
+
+/// \brief Determine structural equivalence for the common part of array
+/// types.
+static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const ArrayType *Array1,
+ const ArrayType *Array2) {
+ if (!IsStructurallyEquivalent(Context,
+ Array1->getElementType(),
+ Array2->getElementType()))
+ return false;
+ if (Array1->getSizeModifier() != Array2->getSizeModifier())
+ return false;
+ if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
+ return false;
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two types.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2) {
+ if (T1.isNull() || T2.isNull())
+ return T1.isNull() && T2.isNull();
+
+ if (!Context.StrictTypeSpelling) {
+ // We aren't being strict about token-to-token equivalence of types,
+ // so map down to the canonical type.
+ T1 = Context.C1.getCanonicalType(T1);
+ T2 = Context.C2.getCanonicalType(T2);
+ }
+
+ if (T1.getQualifiers() != T2.getQualifiers())
+ return false;
+
+ Type::TypeClass TC = T1->getTypeClass();
+
+ if (T1->getTypeClass() != T2->getTypeClass()) {
+ // Compare function types with prototypes vs. without prototypes as if
+ // both did not have prototypes.
+ if (T1->getTypeClass() == Type::FunctionProto &&
+ T2->getTypeClass() == Type::FunctionNoProto)
+ TC = Type::FunctionNoProto;
+ else if (T1->getTypeClass() == Type::FunctionNoProto &&
+ T2->getTypeClass() == Type::FunctionProto)
+ TC = Type::FunctionNoProto;
+ else
+ return false;
+ }
+
+ switch (TC) {
+ case Type::Builtin:
+ // FIXME: Deal with Char_S/Char_U.
+ if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
+ return false;
+ break;
+
+ case Type::Complex:
+ if (!IsStructurallyEquivalent(Context,
+ cast<ComplexType>(T1)->getElementType(),
+ cast<ComplexType>(T2)->getElementType()))
+ return false;
+ break;
+
+ case Type::Pointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PointerType>(T1)->getPointeeType(),
+ cast<PointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::BlockPointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<BlockPointerType>(T1)->getPointeeType(),
+ cast<BlockPointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ const ReferenceType *Ref1 = cast<ReferenceType>(T1);
+ const ReferenceType *Ref2 = cast<ReferenceType>(T2);
+ if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
+ return false;
+ if (Ref1->isInnerRef() != Ref2->isInnerRef())
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Ref1->getPointeeTypeAsWritten(),
+ Ref2->getPointeeTypeAsWritten()))
+ return false;
+ break;
+ }
+
+ case Type::MemberPointer: {
+ const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1);
+ const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ MemPtr1->getPointeeType(),
+ MemPtr2->getPointeeType()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ QualType(MemPtr1->getClass(), 0),
+ QualType(MemPtr2->getClass(), 0)))
+ return false;
+ break;
+ }
+
+ case Type::ConstantArray: {
+ const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1);
+ const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2);
+ if (!IsSameValue(Array1->getSize(), Array2->getSize()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+ break;
+ }
+
+ case Type::IncompleteArray:
+ if (!IsArrayStructurallyEquivalent(Context,
+ cast<ArrayType>(T1),
+ cast<ArrayType>(T2)))
+ return false;
+ break;
+
+ case Type::VariableArray: {
+ const VariableArrayType *Array1 = cast<VariableArrayType>(T1);
+ const VariableArrayType *Array2 = cast<VariableArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Array1->getSizeExpr(), Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedArray: {
+ const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1);
+ const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Array1->getSizeExpr(), Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedExtVector: {
+ const DependentSizedExtVectorType *Vec1
+ = cast<DependentSizedExtVectorType>(T1);
+ const DependentSizedExtVectorType *Vec2
+ = cast<DependentSizedExtVectorType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Vec1->getSizeExpr(), Vec2->getSizeExpr()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ break;
+ }
+
+ case Type::Vector:
+ case Type::ExtVector: {
+ const VectorType *Vec1 = cast<VectorType>(T1);
+ const VectorType *Vec2 = cast<VectorType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ if (Vec1->getNumElements() != Vec2->getNumElements())
+ return false;
+ if (Vec1->isAltiVec() != Vec2->isAltiVec())
+ return false;
+ if (Vec1->isPixel() != Vec2->isPixel())
+ return false;
+ }
+
+ case Type::FunctionProto: {
+ const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1);
+ const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2);
+ if (Proto1->getNumArgs() != Proto2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Proto1->getArgType(I),
+ Proto2->getArgType(I)))
+ return false;
+ }
+ if (Proto1->isVariadic() != Proto2->isVariadic())
+ return false;
+ if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec())
+ 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 (!IsStructurallyEquivalent(Context,
+ Proto1->getExceptionType(I),
+ Proto2->getExceptionType(I)))
+ return false;
+ }
+ if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
+ return false;
+
+ // Fall through to check the bits common with FunctionNoProtoType.
+ }
+
+ case Type::FunctionNoProto: {
+ const FunctionType *Function1 = cast<FunctionType>(T1);
+ const FunctionType *Function2 = cast<FunctionType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Function1->getResultType(),
+ Function2->getResultType()))
+ return false;
+ if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr())
+ return false;
+ if (Function1->getCallConv() != Function2->getCallConv())
+ return false;
+ break;
+ }
+
+ case Type::UnresolvedUsing:
+ if (!IsStructurallyEquivalent(Context,
+ cast<UnresolvedUsingType>(T1)->getDecl(),
+ cast<UnresolvedUsingType>(T2)->getDecl()))
+ return false;
+
+ break;
+
+ case Type::Typedef:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypedefType>(T1)->getDecl(),
+ cast<TypedefType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::TypeOfExpr:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
+ cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::TypeOf:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypeOfType>(T1)->getUnderlyingType(),
+ cast<TypeOfType>(T2)->getUnderlyingType()))
+ return false;
+ break;
+
+ case Type::Decltype:
+ if (!IsStructurallyEquivalent(Context,
+ cast<DecltypeType>(T1)->getUnderlyingExpr(),
+ cast<DecltypeType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::Record:
+ case Type::Enum:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TagType>(T1)->getDecl(),
+ cast<TagType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::Elaborated: {
+ const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
+ const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
+ if (Elab1->getTagKind() != Elab2->getTagKind())
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Elab1->getUnderlyingType(),
+ Elab2->getUnderlyingType()))
+ return false;
+ break;
+ }
+
+ case Type::TemplateTypeParm: {
+ const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
+ const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
+ if (Parm1->getDepth() != Parm2->getDepth())
+ return false;
+ if (Parm1->getIndex() != Parm2->getIndex())
+ return false;
+ if (Parm1->isParameterPack() != Parm2->isParameterPack())
+ return false;
+
+ // Names of template type parameters are never significant.
+ break;
+ }
+
+ case Type::SubstTemplateTypeParm: {
+ const SubstTemplateTypeParmType *Subst1
+ = cast<SubstTemplateTypeParmType>(T1);
+ const SubstTemplateTypeParmType *Subst2
+ = cast<SubstTemplateTypeParmType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Subst1->getReplacedParameter(), 0),
+ QualType(Subst2->getReplacedParameter(), 0)))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Subst1->getReplacementType(),
+ Subst2->getReplacementType()))
+ return false;
+ break;
+ }
+
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *Spec1
+ = cast<TemplateSpecializationType>(T1);
+ const TemplateSpecializationType *Spec2
+ = cast<TemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Spec1->getTemplateName(),
+ Spec2->getTemplateName()))
+ return false;
+ if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Spec1->getArg(I), Spec2->getArg(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::QualifiedName: {
+ const QualifiedNameType *Qual1 = cast<QualifiedNameType>(T1);
+ const QualifiedNameType *Qual2 = cast<QualifiedNameType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Qual1->getQualifier(),
+ Qual2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Qual1->getNamedType(),
+ Qual2->getNamedType()))
+ return false;
+ break;
+ }
+
+ case Type::Typename: {
+ const TypenameType *Typename1 = cast<TypenameType>(T1);
+ const TypenameType *Typename2 = cast<TypenameType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Typename1->getQualifier(),
+ Typename2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
+ Typename2->getIdentifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Typename1->getTemplateId(), 0),
+ QualType(Typename2->getTemplateId(), 0)))
+ return false;
+
+ break;
+ }
+
+ case Type::ObjCInterface: {
+ const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
+ const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Iface1->getDecl(), Iface2->getDecl()))
+ return false;
+ if (Iface1->getNumProtocols() != Iface2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Iface1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Iface1->getProtocol(I),
+ Iface2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1);
+ const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Ptr1->getPointeeType(),
+ Ptr2->getPointeeType()))
+ return false;
+ if (Ptr1->getNumProtocols() != Ptr2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Ptr1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context,
+ Ptr1->getProtocol(I),
+ Ptr2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+
+ } // end switch
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two records.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ RecordDecl *D1, RecordDecl *D2) {
+ if (D1->isUnion() != D2->isUnion()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
+ << D1->getDeclName() << (unsigned)D1->getTagKind();
+ return false;
+ }
+
+ // Compare the definitions of these two records. If either or both are
+ // incomplete, we assume that they are equivalent.
+ D1 = D1->getDefinition();
+ D2 = D2->getDefinition();
+ if (!D1 || !D2)
+ return true;
+
+ if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
+ if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
+ if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+ << D2CXX->getNumBases();
+ Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
+ << D1CXX->getNumBases();
+ return false;
+ }
+
+ // Check the base classes.
+ for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
+ BaseEnd1 = D1CXX->bases_end(),
+ Base2 = D2CXX->bases_begin();
+ Base1 != BaseEnd1;
+ ++Base1, ++Base2) {
+ if (!IsStructurallyEquivalent(Context,
+ Base1->getType(), Base2->getType())) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base2->getType()
+ << Base2->getSourceRange();
+ Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ return false;
+ }
+
+ // Check virtual vs. non-virtual inheritance mismatch.
+ if (Base1->isVirtual() != Base2->isVirtual()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Base2->getSourceRange().getBegin(),
+ diag::note_odr_virtual_base)
+ << Base2->isVirtual() << Base2->getSourceRange();
+ Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base1->isVirtual()
+ << Base1->getSourceRange();
+ return false;
+ }
+ }
+ } else if (D1CXX->getNumBases() > 0) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
+ Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ << Base1->getType()
+ << Base1->getSourceRange();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ return false;
+ }
+ }
+
+ // Check the fields for consistency.
+ CXXRecordDecl::field_iterator Field2 = D2->field_begin(),
+ Field2End = D2->field_end();
+ for (CXXRecordDecl::field_iterator Field1 = D1->field_begin(),
+ Field1End = D1->field_end();
+ Field1 != Field1End;
+ ++Field1, ++Field2) {
+ if (Field2 == Field2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ return false;
+ }
+
+ if (!IsStructurallyEquivalent(Context,
+ Field1->getType(), Field2->getType())) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ return false;
+ }
+
+ if (Field1->isBitField() != Field2->isBitField()) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ if (Field1->isBitField()) {
+ llvm::APSInt Bits;
+ Field1->getBitWidth()->isIntegerConstantExpr(Bits, Context.C1);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Bits.toString(10, false);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
+ << Field2->getDeclName();
+ } else {
+ llvm::APSInt Bits;
+ Field2->getBitWidth()->isIntegerConstantExpr(Bits, Context.C2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Bits.toString(10, false);
+ Context.Diag1(Field1->getLocation(),
+ diag::note_odr_not_bit_field)
+ << Field1->getDeclName();
+ }
+ return false;
+ }
+
+ if (Field1->isBitField()) {
+ // Make sure that the bit-fields are the same length.
+ llvm::APSInt Bits1, Bits2;
+ if (!Field1->getBitWidth()->isIntegerConstantExpr(Bits1, Context.C1))
+ return false;
+ if (!Field2->getBitWidth()->isIntegerConstantExpr(Bits2, Context.C2))
+ return false;
+
+ if (!IsSameValue(Bits1, Bits2)) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Bits2.toString(10, false);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Bits1.toString(10, false);
+ return false;
+ }
+ }
+ }
+
+ if (Field2 != Field2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two enums.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ EnumDecl *D1, EnumDecl *D2) {
+ EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
+ EC2End = D2->enumerator_end();
+ for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
+ EC1End = D1->enumerator_end();
+ EC1 != EC1End; ++EC1, ++EC2) {
+ if (EC2 == EC2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ return false;
+ }
+
+ llvm::APSInt Val1 = EC1->getInitVal();
+ llvm::APSInt Val2 = EC2->getInitVal();
+ if (!IsSameValue(Val1, Val2) ||
+ !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName()
+ << EC2->getInitVal().toString(10);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName()
+ << EC1->getInitVal().toString(10);
+ return false;
+ }
+ }
+
+ if (EC2 != EC2End) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.C2.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName()
+ << EC2->getInitVal().toString(10);
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Determine structural equivalence of two declarations.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2) {
+ // FIXME: Check for known structural equivalences via a callback of some sort.
+
+ // Check whether we already know that these two declarations are not
+ // structurally equivalent.
+ if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(),
+ D2->getCanonicalDecl())))
+ return false;
+
+ // Determine whether we've already produced a tentative equivalence for D1.
+ Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
+ if (EquivToD1)
+ return EquivToD1 == D2->getCanonicalDecl();
+
+ // Produce a tentative equivalence D1 <-> D2, which will be checked later.
+ EquivToD1 = D2->getCanonicalDecl();
+ Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
+ return true;
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1,
+ Decl *D2) {
+ if (!::IsStructurallyEquivalent(*this, D1, D2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1,
+ QualType T2) {
+ if (!::IsStructurallyEquivalent(*this, T1, T2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::Finish() {
+ while (!DeclsToCheck.empty()) {
+ // Check the next declaration.
+ Decl *D1 = DeclsToCheck.front();
+ DeclsToCheck.pop_front();
+
+ Decl *D2 = TentativeEquivalences[D1];
+ assert(D2 && "Unrecorded tentative equivalence?");
+
+ bool Equivalent = true;
+
+ // FIXME: Switch on all declaration kinds. For now, we're just going to
+ // check the obvious ones.
+ if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) {
+ if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
+ // Check for equivalent structure names.
+ IdentifierInfo *Name1 = Record1->getIdentifier();
+ if (!Name1 && Record1->getTypedefForAnonDecl())
+ Name1 = Record1->getTypedefForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Record2->getIdentifier();
+ if (!Name2 && Record2->getTypedefForAnonDecl())
+ Name2 = Record2->getTypedefForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Record1, Record2))
+ Equivalent = false;
+ } else {
+ // Record/non-record mismatch.
+ Equivalent = false;
+ }
+ } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
+ if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
+ // Check for equivalent enum names.
+ IdentifierInfo *Name1 = Enum1->getIdentifier();
+ if (!Name1 && Enum1->getTypedefForAnonDecl())
+ Name1 = Enum1->getTypedefForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Enum2->getIdentifier();
+ if (!Name2 && Enum2->getTypedefForAnonDecl())
+ Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Enum1, Enum2))
+ Equivalent = false;
+ } else {
+ // Enum/non-enum mismatch
+ Equivalent = false;
+ }
+ } else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) {
+ if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
+ Typedef2->getIdentifier()) ||
+ !::IsStructurallyEquivalent(*this,
+ Typedef1->getUnderlyingType(),
+ Typedef2->getUnderlyingType()))
+ Equivalent = false;
+ } else {
+ // Typedef/non-typedef mismatch.
+ Equivalent = false;
+ }
+ }
+
+ if (!Equivalent) {
+ // Note that these two declarations are not equivalent (and we already
+ // know about it).
+ NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(),
+ D2->getCanonicalDecl()));
+ return true;
+ }
+ // FIXME: Check other declaration kinds!
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------------
+// Import Types
+//----------------------------------------------------------------------------
+
+QualType ASTNodeImporter::VisitType(Type *T) {
+ Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node)
+ << T->getTypeClassName();
+ return QualType();
+}
+
+QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) {
+ switch (T->getKind()) {
+ case BuiltinType::Void: return Importer.getToContext().VoidTy;
+ case BuiltinType::Bool: return Importer.getToContext().BoolTy;
+
+ case BuiltinType::Char_U:
+ // The context we're importing from has an unsigned 'char'. If we're
+ // importing into a context with a signed 'char', translate to
+ // 'unsigned char' instead.
+ if (Importer.getToContext().getLangOptions().CharIsSigned)
+ return Importer.getToContext().UnsignedCharTy;
+
+ return Importer.getToContext().CharTy;
+
+ case BuiltinType::UChar: return Importer.getToContext().UnsignedCharTy;
+
+ case BuiltinType::Char16:
+ // FIXME: Make sure that the "to" context supports C++!
+ return Importer.getToContext().Char16Ty;
+
+ case BuiltinType::Char32:
+ // FIXME: Make sure that the "to" context supports C++!
+ return Importer.getToContext().Char32Ty;
+
+ case BuiltinType::UShort: return Importer.getToContext().UnsignedShortTy;
+ case BuiltinType::UInt: return Importer.getToContext().UnsignedIntTy;
+ case BuiltinType::ULong: return Importer.getToContext().UnsignedLongTy;
+ case BuiltinType::ULongLong:
+ return Importer.getToContext().UnsignedLongLongTy;
+ case BuiltinType::UInt128: return Importer.getToContext().UnsignedInt128Ty;
+
+ case BuiltinType::Char_S:
+ // The context we're importing from has an unsigned 'char'. If we're
+ // importing into a context with a signed 'char', translate to
+ // 'unsigned char' instead.
+ if (!Importer.getToContext().getLangOptions().CharIsSigned)
+ return Importer.getToContext().SignedCharTy;
+
+ return Importer.getToContext().CharTy;
+
+ case BuiltinType::SChar: return Importer.getToContext().SignedCharTy;
+ case BuiltinType::WChar:
+ // FIXME: If not in C++, shall we translate to the C equivalent of
+ // wchar_t?
+ return Importer.getToContext().WCharTy;
+
+ case BuiltinType::Short : return Importer.getToContext().ShortTy;
+ case BuiltinType::Int : return Importer.getToContext().IntTy;
+ case BuiltinType::Long : return Importer.getToContext().LongTy;
+ case BuiltinType::LongLong : return Importer.getToContext().LongLongTy;
+ case BuiltinType::Int128 : return Importer.getToContext().Int128Ty;
+ case BuiltinType::Float: return Importer.getToContext().FloatTy;
+ case BuiltinType::Double: return Importer.getToContext().DoubleTy;
+ case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy;
+
+ case BuiltinType::NullPtr:
+ // FIXME: Make sure that the "to" context supports C++0x!
+ return Importer.getToContext().NullPtrTy;
+
+ case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
+ case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
+ case BuiltinType::UndeducedAuto:
+ // FIXME: Make sure that the "to" context supports C++0x!
+ return Importer.getToContext().UndeducedAutoTy;
+
+ case BuiltinType::ObjCId:
+ // FIXME: Make sure that the "to" context supports Objective-C!
+ return Importer.getToContext().ObjCBuiltinIdTy;
+
+ case BuiltinType::ObjCClass:
+ return Importer.getToContext().ObjCBuiltinClassTy;
+
+ case BuiltinType::ObjCSel:
+ return Importer.getToContext().ObjCBuiltinSelTy;
+ }
+
+ return QualType();
+}
+
+QualType ASTNodeImporter::VisitComplexType(ComplexType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getComplexType(ToElementType);
+}
+
+QualType ASTNodeImporter::VisitPointerType(PointerType *T) {
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getPointerType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) {
+ // FIXME: Check for blocks support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getBlockPointerType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) {
+ // FIXME: Check for C++ support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getLValueReferenceType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) {
+ // FIXME: Check for C++0x support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getRValueReferenceType(ToPointeeType);
+}
+
+QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) {
+ // FIXME: Check for C++ support in "to" context.
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ QualType ClassType = Importer.Import(QualType(T->getClass(), 0));
+ return Importer.getToContext().getMemberPointerType(ToPointeeType,
+ ClassType.getTypePtr());
+}
+
+QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getConstantArrayType(ToElementType,
+ T->getSize(),
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getIncompleteArrayType(ToElementType,
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
+}
+
+QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ Expr *Size = Importer.Import(T->getSizeExpr());
+ if (!Size)
+ return QualType();
+
+ SourceRange Brackets = Importer.Import(T->getBracketsRange());
+ return Importer.getToContext().getVariableArrayType(ToElementType, Size,
+ T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers(),
+ Brackets);
+}
+
+QualType ASTNodeImporter::VisitVectorType(VectorType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getVectorType(ToElementType,
+ T->getNumElements(),
+ T->isAltiVec(),
+ T->isPixel());
+}
+
+QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) {
+ QualType ToElementType = Importer.Import(T->getElementType());
+ if (ToElementType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getExtVectorType(ToElementType,
+ T->getNumElements());
+}
+
+QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) {
+ // FIXME: What happens if we're importing a function without a prototype
+ // into C++? Should we make it variadic?
+ QualType ToResultType = Importer.Import(T->getResultType());
+ if (ToResultType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getFunctionNoProtoType(ToResultType,
+ T->getNoReturnAttr(),
+ T->getCallConv());
+}
+
+QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
+ QualType ToResultType = Importer.Import(T->getResultType());
+ if (ToResultType.isNull())
+ return QualType();
+
+ // Import argument types
+ llvm::SmallVector<QualType, 4> ArgTypes;
+ for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
+ AEnd = T->arg_type_end();
+ A != AEnd; ++A) {
+ QualType ArgType = Importer.Import(*A);
+ if (ArgType.isNull())
+ return QualType();
+ ArgTypes.push_back(ArgType);
+ }
+
+ // Import exception types
+ llvm::SmallVector<QualType, 4> ExceptionTypes;
+ for (FunctionProtoType::exception_iterator E = T->exception_begin(),
+ EEnd = T->exception_end();
+ E != EEnd; ++E) {
+ QualType ExceptionType = Importer.Import(*E);
+ if (ExceptionType.isNull())
+ return QualType();
+ ExceptionTypes.push_back(ExceptionType);
+ }
+
+ return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
+ ArgTypes.size(),
+ T->isVariadic(),
+ T->getTypeQuals(),
+ T->hasExceptionSpec(),
+ T->hasAnyExceptionSpec(),
+ ExceptionTypes.size(),
+ ExceptionTypes.data(),
+ T->getNoReturnAttr(),
+ T->getCallConv());
+}
+
+QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) {
+ TypedefDecl *ToDecl
+ = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl()));
+ if (!ToDecl)
+ return QualType();
+
+ return Importer.getToContext().getTypeDeclType(ToDecl);
+}
+
+QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) {
+ Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
+ if (!ToExpr)
+ return QualType();
+
+ return Importer.getToContext().getTypeOfExprType(ToExpr);
+}
+
+QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) {
+ QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
+ if (ToUnderlyingType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getTypeOfType(ToUnderlyingType);
+}
+
+QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) {
+ Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
+ if (!ToExpr)
+ return QualType();
+
+ return Importer.getToContext().getDecltypeType(ToExpr);
+}
+
+QualType ASTNodeImporter::VisitRecordType(RecordType *T) {
+ RecordDecl *ToDecl
+ = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl()));
+ if (!ToDecl)
+ return QualType();
+
+ return Importer.getToContext().getTagDeclType(ToDecl);
+}
+
+QualType ASTNodeImporter::VisitEnumType(EnumType *T) {
+ EnumDecl *ToDecl
+ = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl()));
+ if (!ToDecl)
+ return QualType();
+
+ return Importer.getToContext().getTagDeclType(ToDecl);
+}
+
+QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) {
+ QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
+ if (ToUnderlyingType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getElaboratedType(ToUnderlyingType,
+ T->getTagKind());
+}
+
+QualType ASTNodeImporter::VisitQualifiedNameType(QualifiedNameType *T) {
+ NestedNameSpecifier *ToQualifier = Importer.Import(T->getQualifier());
+ if (!ToQualifier)
+ return QualType();
+
+ QualType ToNamedType = Importer.Import(T->getNamedType());
+ if (ToNamedType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getQualifiedNameType(ToQualifier, ToNamedType);
+}
+
+QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
+ ObjCInterfaceDecl *Class
+ = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl()));
+ if (!Class)
+ return QualType();
+
+ llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ for (ObjCInterfaceType::qual_iterator P = T->qual_begin(),
+ PEnd = T->qual_end();
+ P != PEnd; ++P) {
+ ObjCProtocolDecl *Protocol
+ = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P));
+ if (!Protocol)
+ return QualType();
+ Protocols.push_back(Protocol);
+ }
+
+ return Importer.getToContext().getObjCInterfaceType(Class,
+ Protocols.data(),
+ Protocols.size());
+}
+
+QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
+ QualType ToPointeeType = Importer.Import(T->getPointeeType());
+ if (ToPointeeType.isNull())
+ return QualType();
+
+ llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ for (ObjCObjectPointerType::qual_iterator P = T->qual_begin(),
+ PEnd = T->qual_end();
+ P != PEnd; ++P) {
+ ObjCProtocolDecl *Protocol
+ = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P));
+ if (!Protocol)
+ return QualType();
+ Protocols.push_back(Protocol);
+ }
+
+ return Importer.getToContext().getObjCObjectPointerType(ToPointeeType,
+ Protocols.data(),
+ Protocols.size());
+}
+
+//----------------------------------------------------------------------------
+// Import Declarations
+//----------------------------------------------------------------------------
+bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC,
+ DeclContext *&LexicalDC,
+ DeclarationName &Name,
+ SourceLocation &Loc) {
+ // Import the context of this declaration.
+ DC = Importer.ImportContext(D->getDeclContext());
+ if (!DC)
+ return true;
+
+ LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return true;
+ }
+
+ // Import the name of this declaration.
+ Name = Importer.Import(D->getDeclName());
+ if (D->getDeclName() && !Name)
+ return true;
+
+ // Import the location of this declaration.
+ Loc = Importer.Import(D->getLocation());
+ return false;
+}
+
+bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
+ RecordDecl *ToRecord) {
+ StructuralEquivalenceContext SEC(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getDiags(),
+ Importer.getNonEquivalentDecls());
+ return SEC.IsStructurallyEquivalent(FromRecord, ToRecord);
+}
+
+bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
+ StructuralEquivalenceContext SEC(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getDiags(),
+ Importer.getNonEquivalentDecls());
+ return SEC.IsStructurallyEquivalent(FromEnum, ToEnum);
+}
+
+Decl *ASTNodeImporter::VisitDecl(Decl *D) {
+ Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
+ << D->getDeclKindName();
+ return 0;
+}
+
+Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
+ // Import the major distinguishing characteristics of this typedef.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // If this typedef is not in block scope, determine whether we've
+ // seen a typedef with the same name (that we can merge with) or any
+ // other entity by that name (which name lookup could conflict with).
+ if (!DC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+ if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) {
+ if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(),
+ FoundTypedef->getUnderlyingType()))
+ return Importer.Imported(D, FoundTypedef);
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ // Import the underlying type of this typedef;
+ QualType T = Importer.Import(D->getUnderlyingType());
+ if (T.isNull())
+ return 0;
+
+ // Create the new typedef node.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(),
+ TInfo);
+ ToTypedef->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToTypedef);
+ LexicalDC->addDecl(ToTypedef);
+
+ return ToTypedef;
+}
+
+Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
+ // Import the major distinguishing characteristics of this enum.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // 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());
+ IDNS = Decl::IDNS_Ordinary;
+ } else if (Importer.getToContext().getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Ordinary;
+
+ // We may already have an enum of the same name; try to find and match it.
+ if (!DC->isFunctionOrMethod() && SearchName) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ Decl *Found = *Lookup.first;
+ if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
+ Found = Tag->getDecl();
+ }
+
+ if (EnumDecl *FoundEnum = dyn_cast<EnumDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundEnum))
+ return Importer.Imported(D, FoundEnum);
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+ }
+
+ // Create the enum declaration.
+ EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()),
+ 0);
+ D2->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, D2);
+ LexicalDC->addDecl(D2);
+
+ // Import the integer type.
+ QualType ToIntegerType = Importer.Import(D->getIntegerType());
+ if (ToIntegerType.isNull())
+ return 0;
+ D2->setIntegerType(ToIntegerType);
+
+ // Import the definition
+ if (D->isDefinition()) {
+ QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D));
+ if (T.isNull())
+ return 0;
+
+ QualType ToPromotionType = Importer.Import(D->getPromotionType());
+ if (ToPromotionType.isNull())
+ return 0;
+
+ D2->startDefinition();
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ D2->completeDefinition(T, ToPromotionType);
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
+ // If this record has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ TagDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ // Import the major distinguishing characteristics of this record.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // 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());
+ IDNS = Decl::IDNS_Ordinary;
+ } else if (Importer.getToContext().getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Ordinary;
+
+ // We may already have a record of the same name; try to find and match it.
+ RecordDecl *AdoptDecl = 0;
+ if (!DC->isFunctionOrMethod() && SearchName) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ Decl *Found = *Lookup.first;
+ if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
+ Found = Tag->getDecl();
+ }
+
+ if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
+ if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
+ if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) {
+ // The record types structurally match, or the "from" translation
+ // unit only had a forward declaration anyway; call it the same
+ // function.
+ // FIXME: For C++, we should also merge methods here.
+ return Importer.Imported(D, FoundDef);
+ }
+ } else {
+ // We have a forward declaration of this type, so adopt that forward
+ // declaration rather than building a new one.
+ AdoptDecl = FoundRecord;
+ continue;
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+ }
+
+ // Create the record declaration.
+ RecordDecl *D2 = AdoptDecl;
+ if (!D2) {
+ if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D)) {
+ CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(),
+ D->getTagKind(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()));
+ D2 = D2CXX;
+
+ if (D->isDefinition()) {
+ // Add base classes.
+ llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
+ for (CXXRecordDecl::base_class_iterator
+ Base1 = D1CXX->bases_begin(),
+ FromBaseEnd = D1CXX->bases_end();
+ Base1 != FromBaseEnd;
+ ++Base1) {
+ QualType T = Importer.Import(Base1->getType());
+ if (T.isNull())
+ return 0;
+
+ Bases.push_back(
+ new (Importer.getToContext())
+ CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
+ Base1->isVirtual(),
+ Base1->isBaseOfClass(),
+ Base1->getAccessSpecifierAsWritten(),
+ T));
+ }
+ if (!Bases.empty())
+ D2CXX->setBases(Bases.data(), Bases.size());
+ }
+ } else {
+ D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()));
+ }
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDecl(D2);
+ }
+
+ Importer.Imported(D, D2);
+
+ if (D->isDefinition()) {
+ D2->startDefinition();
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ D2->completeDefinition();
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ // Import the major distinguishing characteristics of this enumerator.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Determine whether there are any other declarations with the same name and
+ // in the same context.
+ if (!LexicalDC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ Expr *Init = Importer.Import(D->getInitExpr());
+ if (D->getInitExpr() && !Init)
+ return 0;
+
+ EnumConstantDecl *ToEnumerator
+ = EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc,
+ Name.getAsIdentifierInfo(), T,
+ Init, D->getInitVal());
+ ToEnumerator->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToEnumerator);
+ LexicalDC->addDecl(ToEnumerator);
+ return ToEnumerator;
+}
+
+Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
+ // Import the major distinguishing characteristics of this function.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Try to find a function in our own ("to") context with the same name, same
+ // type, and in the same context as the function we're importing.
+ if (!LexicalDC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) {
+ if (isExternalLinkage(FoundFunction->getLinkage()) &&
+ isExternalLinkage(D->getLinkage())) {
+ if (Importer.IsStructurallyEquivalent(D->getType(),
+ FoundFunction->getType())) {
+ // FIXME: Actually try to merge the body and other attributes.
+ return Importer.Imported(D, FoundFunction);
+ }
+
+ // FIXME: Check for overloading more carefully, e.g., by boosting
+ // Sema::IsOverload out to the AST library.
+
+ // Function overloading is okay in C++.
+ if (Importer.getToContext().getLangOptions().CPlusPlus)
+ continue;
+
+ // Complain about inconsistent function types.
+ Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent)
+ << Name << D->getType() << FoundFunction->getType();
+ Importer.ToDiag(FoundFunction->getLocation(),
+ diag::note_odr_value_here)
+ << FoundFunction->getType();
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Import the function parameters.
+ llvm::SmallVector<ParmVarDecl *, 8> Parameters;
+ for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
+ P != PEnd; ++P) {
+ ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P));
+ if (!ToP)
+ return 0;
+
+ Parameters.push_back(ToP);
+ }
+
+ // Create the imported function.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ FunctionDecl *ToEnumerator
+ = FunctionDecl::Create(Importer.getToContext(), DC, Loc,
+ Name, T, TInfo, D->getStorageClass(),
+ D->isInlineSpecified(),
+ D->hasWrittenPrototype());
+ ToEnumerator->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToEnumerator);
+ LexicalDC->addDecl(ToEnumerator);
+
+ // Set the parameters.
+ for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
+ Parameters[I]->setOwningFunction(ToEnumerator);
+ ToEnumerator->addDecl(Parameters[I]);
+ }
+ ToEnumerator->setParams(Parameters.data(), Parameters.size());
+
+ // FIXME: Other bits to merge?
+
+ return ToEnumerator;
+}
+
+Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
+ // Import the major distinguishing characteristics of a variable.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ Expr *BitWidth = Importer.Import(D->getBitWidth());
+ if (!BitWidth && D->getBitWidth())
+ return 0;
+
+ FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(),
+ T, TInfo, BitWidth, D->isMutable());
+ ToField->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToField);
+ LexicalDC->addDecl(ToField);
+ return ToField;
+}
+
+Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
+ // Import the major distinguishing characteristics of a variable.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Try to find a variable in our own ("to") context with the same name and
+ // in the same context as the variable we're importing.
+ if (D->isFileVarDecl()) {
+ VarDecl *MergeWithVar = 0;
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ if (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) {
+ // We have found a variable that we may need to merge with. Check it.
+ if (isExternalLinkage(FoundVar->getLinkage()) &&
+ isExternalLinkage(D->getLinkage())) {
+ if (Importer.IsStructurallyEquivalent(D->getType(),
+ FoundVar->getType())) {
+ MergeWithVar = FoundVar;
+ break;
+ }
+
+ const ArrayType *FoundArray
+ = Importer.getToContext().getAsArrayType(FoundVar->getType());
+ const ArrayType *TArray
+ = Importer.getToContext().getAsArrayType(D->getType());
+ if (FoundArray && TArray) {
+ if (isa<IncompleteArrayType>(FoundArray) &&
+ isa<ConstantArrayType>(TArray)) {
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ FoundVar->setType(T);
+ MergeWithVar = FoundVar;
+ break;
+ } else if (isa<IncompleteArrayType>(TArray) &&
+ isa<ConstantArrayType>(FoundArray)) {
+ MergeWithVar = FoundVar;
+ break;
+ }
+ }
+
+ Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent)
+ << Name << D->getType() << FoundVar->getType();
+ Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
+ << FoundVar->getType();
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (MergeWithVar) {
+ // An equivalent variable with external linkage has been found. Link
+ // the two declarations, then merge them.
+ Importer.Imported(D, MergeWithVar);
+
+ if (VarDecl *DDef = D->getDefinition()) {
+ if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) {
+ Importer.ToDiag(ExistingDef->getLocation(),
+ diag::err_odr_variable_multiple_def)
+ << Name;
+ Importer.FromDiag(DDef->getLocation(), diag::note_odr_defined_here);
+ } else {
+ Expr *Init = Importer.Import(DDef->getInit());
+ MergeWithVar->setInit(Init);
+ }
+ }
+
+ return MergeWithVar;
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the imported variable.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
+ Name.getAsIdentifierInfo(), T, TInfo,
+ D->getStorageClass());
+ ToVar->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToVar);
+ LexicalDC->addDecl(ToVar);
+
+ // Merge the initializer.
+ // FIXME: Can we really import any initializer? Alternatively, we could force
+ // ourselves to import every declaration of a variable and then only use
+ // getInit() here.
+ ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer())));
+
+ // FIXME: Other bits to merge?
+
+ return ToVar;
+}
+
+Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
+ // Parameters are created in the translation unit's context, then moved
+ // into the function declaration's context afterward.
+ DeclContext *DC = Importer.getToContext().getTranslationUnitDecl();
+
+ // Import the name of this declaration.
+ DeclarationName Name = Importer.Import(D->getDeclName());
+ if (D->getDeclName() && !Name)
+ return 0;
+
+ // Import the location of this declaration.
+ SourceLocation Loc = Importer.Import(D->getLocation());
+
+ // Import the parameter's type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the imported parameter.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(),
+ T, TInfo, D->getStorageClass(),
+ /*FIXME: Default argument*/ 0);
+ return Importer.Imported(D, ToParm);
+}
+
+Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // Import the major distinguishing characteristics of an @interface.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ ObjCInterfaceDecl *MergeWithIface = 0;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ continue;
+
+ if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(*Lookup.first)))
+ break;
+ }
+
+ ObjCInterfaceDecl *ToIface = MergeWithIface;
+ if (!ToIface || ToIface->isForwardDecl()) {
+ if (!ToIface) {
+ ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getClassLoc()),
+ D->isForwardDecl(),
+ D->isImplicitInterfaceDecl());
+ ToIface->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDecl(ToIface);
+ }
+ Importer.Imported(D, ToIface);
+
+ // Import superclass
+ // FIXME: If we're merging, make sure that both decls have the same
+ // superclass.
+ if (D->getSuperClass()) {
+ ObjCInterfaceDecl *Super
+ = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass()));
+ if (!Super)
+ return 0;
+
+ ToIface->setSuperClass(Super);
+ ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc()));
+ }
+
+ // Import protocols
+ llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ llvm::SmallVector<SourceLocation, 4> ProtocolLocs;
+ ObjCInterfaceDecl::protocol_loc_iterator
+ FromProtoLoc = D->protocol_loc_begin();
+ for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(),
+ FromProtoEnd = D->protocol_end();
+ FromProto != FromProtoEnd;
+ ++FromProto, ++FromProtoLoc) {
+ ObjCProtocolDecl *ToProto
+ = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
+ if (!ToProto)
+ return 0;
+ Protocols.push_back(ToProto);
+ ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+ }
+
+ // FIXME: If we're merging, make sure that the protocol list is the same.
+ ToIface->setProtocolList(Protocols.data(), Protocols.size(),
+ ProtocolLocs.data(), Importer.getToContext());
+
+ // FIXME: Import categories
+
+ // Import @end range
+ ToIface->setAtEndRange(Importer.Import(D->getAtEndRange()));
+ } else {
+ Importer.Imported(D, ToIface);
+ }
+
+ // Import all of the members of this class.
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ // If we have an @implementation, import it as well.
+ if (D->getImplementation()) {
+ ObjCImplementationDecl *Impl
+ = cast<ObjCImplementationDecl>(Importer.Import(D->getImplementation()));
+ if (!Impl)
+ return 0;
+
+ ToIface->setImplementation(Impl);
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+// Import Statements
+//----------------------------------------------------------------------------
+
+Stmt *ASTNodeImporter::VisitStmt(Stmt *S) {
+ Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node)
+ << S->getStmtClassName();
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+// Import Expressions
+//----------------------------------------------------------------------------
+Expr *ASTNodeImporter::VisitExpr(Expr *E) {
+ Importer.FromDiag(E->getLocStart(), diag::err_unsupported_ast_node)
+ << E->getStmtClassName();
+ return 0;
+}
+
+Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
+ QualType T = Importer.Import(E->getType());
+ if (T.isNull())
+ return 0;
+
+ return new (Importer.getToContext())
+ IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation()));
+}
+
+Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ QualType T = Importer.Import(E->getType());
+ if (T.isNull())
+ return 0;
+
+ Expr *SubExpr = Importer.Import(E->getSubExpr());
+ if (!SubExpr)
+ return 0;
+
+ return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(),
+ SubExpr,
+ E->isLvalueCast());
+}
+
+ASTImporter::ASTImporter(Diagnostic &Diags,
+ ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager)
+ : ToContext(ToContext), FromContext(FromContext),
+ ToFileManager(ToFileManager), FromFileManager(FromFileManager),
+ Diags(Diags) {
+ ImportedDecls[FromContext.getTranslationUnitDecl()]
+ = ToContext.getTranslationUnitDecl();
+}
+
+ASTImporter::~ASTImporter() { }
+
+QualType ASTImporter::Import(QualType FromT) {
+ if (FromT.isNull())
+ return QualType();
+
+ // Check whether we've already imported this type.
+ llvm::DenseMap<Type *, Type *>::iterator Pos
+ = ImportedTypes.find(FromT.getTypePtr());
+ if (Pos != ImportedTypes.end())
+ return ToContext.getQualifiedType(Pos->second, FromT.getQualifiers());
+
+ // Import the type
+ ASTNodeImporter Importer(*this);
+ QualType ToT = Importer.Visit(FromT.getTypePtr());
+ if (ToT.isNull())
+ return ToT;
+
+ // Record the imported type.
+ ImportedTypes[FromT.getTypePtr()] = ToT.getTypePtr();
+
+ return ToContext.getQualifiedType(ToT, FromT.getQualifiers());
+}
+
+TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
+ if (!FromTSI)
+ return FromTSI;
+
+ // FIXME: For now we just create a "trivial" type source info based
+ // on the type and a seingle location. Implement a real version of
+ // this.
+ QualType T = Import(FromTSI->getType());
+ if (T.isNull())
+ return 0;
+
+ return ToContext.getTrivialTypeSourceInfo(T,
+ FromTSI->getTypeLoc().getFullSourceRange().getBegin());
+}
+
+Decl *ASTImporter::Import(Decl *FromD) {
+ if (!FromD)
+ return 0;
+
+ // Check whether we've already imported this declaration.
+ llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD);
+ if (Pos != ImportedDecls.end())
+ return Pos->second;
+
+ // Import the type
+ ASTNodeImporter Importer(*this);
+ Decl *ToD = Importer.Visit(FromD);
+ if (!ToD)
+ return 0;
+
+ // Record the imported declaration.
+ ImportedDecls[FromD] = ToD;
+
+ if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) {
+ // Keep track of anonymous tags that have an associated typedef.
+ if (FromTag->getTypedefForAnonDecl())
+ AnonTagsWithPendingTypedefs.push_back(FromTag);
+ } else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(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 (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) {
+ // We found the typedef for an anonymous tag; link them.
+ ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD));
+ AnonTagsWithPendingTypedefs.erase(FromTag);
+ break;
+ }
+ }
+ }
+ }
+
+ return ToD;
+}
+
+DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) {
+ if (!FromDC)
+ return FromDC;
+
+ return cast_or_null<DeclContext>(Import(cast<Decl>(FromDC)));
+}
+
+Expr *ASTImporter::Import(Expr *FromE) {
+ if (!FromE)
+ return 0;
+
+ return cast_or_null<Expr>(Import(cast<Stmt>(FromE)));
+}
+
+Stmt *ASTImporter::Import(Stmt *FromS) {
+ if (!FromS)
+ return 0;
+
+ // Check whether we've already imported this declaration.
+ llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS);
+ if (Pos != ImportedStmts.end())
+ return Pos->second;
+
+ // Import the type
+ ASTNodeImporter Importer(*this);
+ Stmt *ToS = Importer.Visit(FromS);
+ if (!ToS)
+ return 0;
+
+ // Record the imported declaration.
+ ImportedStmts[FromS] = ToS;
+ return ToS;
+}
+
+NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
+ if (!FromNNS)
+ return 0;
+
+ // FIXME: Implement!
+ return 0;
+}
+
+SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
+ if (FromLoc.isInvalid())
+ return SourceLocation();
+
+ SourceManager &FromSM = FromContext.getSourceManager();
+
+ // For now, map everything down to its spelling location, so that we
+ // don't have to import macro instantiations.
+ // FIXME: Import macro instantiations!
+ FromLoc = FromSM.getSpellingLoc(FromLoc);
+ std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc);
+ SourceManager &ToSM = ToContext.getSourceManager();
+ return ToSM.getLocForStartOfFile(Import(Decomposed.first))
+ .getFileLocWithOffset(Decomposed.second);
+}
+
+SourceRange ASTImporter::Import(SourceRange FromRange) {
+ return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd()));
+}
+
+FileID ASTImporter::Import(FileID FromID) {
+ llvm::DenseMap<unsigned, FileID>::iterator Pos
+ = ImportedFileIDs.find(FromID.getHashValue());
+ if (Pos != ImportedFileIDs.end())
+ return Pos->second;
+
+ SourceManager &FromSM = FromContext.getSourceManager();
+ SourceManager &ToSM = ToContext.getSourceManager();
+ const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID);
+ assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet");
+
+ // Include location of this file.
+ SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc());
+
+ // Map the FileID for to the "to" source manager.
+ FileID ToID;
+ const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache();
+ if (Cache->Entry) {
+ // 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());
+ ToID = ToSM.createFileID(Entry, ToIncludeLoc,
+ FromSLoc.getFile().getFileCharacteristic());
+ } else {
+ // FIXME: We want to re-use the existing MemoryBuffer!
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer();
+ llvm::MemoryBuffer *ToBuf
+ = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(),
+ FromBuf->getBufferEnd(),
+ FromBuf->getBufferIdentifier());
+ ToID = ToSM.createFileIDForMemBuffer(ToBuf);
+ }
+
+
+ ImportedFileIDs[FromID.getHashValue()] = ToID;
+ return ToID;
+}
+
+DeclarationName ASTImporter::Import(DeclarationName FromName) {
+ if (!FromName)
+ return DeclarationName();
+
+ switch (FromName.getNameKind()) {
+ case DeclarationName::Identifier:
+ return Import(FromName.getAsIdentifierInfo());
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return Import(FromName.getObjCSelector());
+
+ case DeclarationName::CXXConstructorName: {
+ QualType T = Import(FromName.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return ToContext.DeclarationNames.getCXXConstructorName(
+ ToContext.getCanonicalType(T));
+ }
+
+ case DeclarationName::CXXDestructorName: {
+ QualType T = Import(FromName.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return ToContext.DeclarationNames.getCXXDestructorName(
+ ToContext.getCanonicalType(T));
+ }
+
+ case DeclarationName::CXXConversionFunctionName: {
+ QualType T = Import(FromName.getCXXNameType());
+ if (T.isNull())
+ return DeclarationName();
+
+ return ToContext.DeclarationNames.getCXXConversionFunctionName(
+ ToContext.getCanonicalType(T));
+ }
+
+ case DeclarationName::CXXOperatorName:
+ return ToContext.DeclarationNames.getCXXOperatorName(
+ FromName.getCXXOverloadedOperator());
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return ToContext.DeclarationNames.getCXXLiteralOperatorName(
+ Import(FromName.getCXXLiteralIdentifier()));
+
+ case DeclarationName::CXXUsingDirective:
+ // FIXME: STATICS!
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ // Silence bogus GCC warning
+ return DeclarationName();
+}
+
+IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) {
+ if (!FromId)
+ return 0;
+
+ return &ToContext.Idents.get(FromId->getName());
+}
+
+DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
+ DeclContext *DC,
+ unsigned IDNS,
+ NamedDecl **Decls,
+ unsigned NumDecls) {
+ return Name;
+}
+
+DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()),
+ DiagID);
+}
+
+DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()),
+ DiagID);
+}
+
+Decl *ASTImporter::Imported(Decl *From, Decl *To) {
+ ImportedDecls[From] = To;
+ return To;
+}
+
+bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) {
+ llvm::DenseMap<Type *, Type *>::iterator Pos
+ = ImportedTypes.find(From.getTypePtr());
+ if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To))
+ return true;
+
+ StructuralEquivalenceContext SEC(FromContext, ToContext, Diags,
+ NonEquivalentDecls);
+ return SEC.IsStructurallyEquivalent(From, To);
+}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index 02c70b651119..d81979734b3a 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -11,11 +11,61 @@
//
//===----------------------------------------------------------------------===//
-
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
using namespace clang;
+void Attr::Destroy(ASTContext &C) {
+ if (Next) {
+ Next->Destroy(C);
+ Next = 0;
+ }
+ this->~Attr();
+ C.Deallocate((void*)this);
+}
+
+AttrWithString::AttrWithString(Attr::Kind AK, ASTContext &C, llvm::StringRef s)
+ : Attr(AK) {
+ assert(!s.empty());
+ StrLen = s.size();
+ Str = new (C) char[StrLen];
+ memcpy(const_cast<char*>(Str), s.data(), StrLen);
+}
+
+void AttrWithString::Destroy(ASTContext &C) {
+ C.Deallocate(const_cast<char*>(Str));
+ Attr::Destroy(C);
+}
+
+void AttrWithString::ReplaceString(ASTContext &C, llvm::StringRef newS) {
+ if (newS.size() > StrLen) {
+ C.Deallocate(const_cast<char*>(Str));
+ Str = new (C) char[newS.size()];
+ }
+ StrLen = newS.size();
+ memcpy(const_cast<char*>(Str), newS.data(), StrLen);
+}
+
+void FormatAttr::setType(ASTContext &C, llvm::StringRef type) {
+ ReplaceString(C, type);
+}
+
+NonNullAttr::NonNullAttr(ASTContext &C, unsigned* arg_nums, unsigned size)
+ : Attr(NonNull), ArgNums(0), Size(0) {
+ if (size == 0)
+ return;
+ assert(arg_nums);
+ ArgNums = new (C) unsigned[size];
+ Size = size;
+ memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
+}
+
+void NonNullAttr::Destroy(ASTContext &C) {
+ if (ArgNums)
+ C.Deallocate(ArgNums);
+ Attr::Destroy(C);
+}
+
#define DEF_SIMPLE_ATTR_CLONE(ATTR) \
Attr *ATTR##Attr::clone(ASTContext &C) const { \
return ::new (C) ATTR##Attr; \
@@ -55,6 +105,7 @@ DEF_SIMPLE_ATTR_CLONE(Hiding)
DEF_SIMPLE_ATTR_CLONE(Override)
DEF_SIMPLE_ATTR_CLONE(DLLImport)
DEF_SIMPLE_ATTR_CLONE(DLLExport)
+DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer)
Attr* PragmaPackAttr::clone(ASTContext &C) const {
return ::new (C) PragmaPackAttr(Alignment);
@@ -65,15 +116,15 @@ Attr* AlignedAttr::clone(ASTContext &C) const {
}
Attr* AnnotateAttr::clone(ASTContext &C) const {
- return ::new (C) AnnotateAttr(Annotation);
+ return ::new (C) AnnotateAttr(C, getAnnotation());
}
Attr *AsmLabelAttr::clone(ASTContext &C) const {
- return ::new (C) AsmLabelAttr(Label);
+ return ::new (C) AsmLabelAttr(C, getLabel());
}
Attr *AliasAttr::clone(ASTContext &C) const {
- return ::new (C) AliasAttr(Aliasee);
+ return ::new (C) AliasAttr(C, getAliasee());
}
Attr *ConstructorAttr::clone(ASTContext &C) const {
@@ -93,15 +144,15 @@ Attr *GNUInlineAttr::clone(ASTContext &C) const {
}
Attr *SectionAttr::clone(ASTContext &C) const {
- return ::new (C) SectionAttr(Name);
+ return ::new (C) SectionAttr(C, getName());
}
Attr *NonNullAttr::clone(ASTContext &C) const {
- return ::new (C) NonNullAttr(ArgNums, Size);
+ return ::new (C) NonNullAttr(C, ArgNums, Size);
}
Attr *FormatAttr::clone(ASTContext &C) const {
- return ::new (C) FormatAttr(Type, formatIdx, firstArg);
+ return ::new (C) FormatAttr(C, getType(), formatIdx, firstArg);
}
Attr *FormatArgAttr::clone(ASTContext &C) const {
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index dea96e7866ec..e5bd9b7722c5 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -4,6 +4,8 @@ add_clang_library(clangAST
APValue.cpp
ASTConsumer.cpp
ASTContext.cpp
+ ASTImporter.cpp
+ ASTDiagnostic.cpp
AttrImpl.cpp
CXXInheritance.cpp
Decl.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 720832869266..99f908caeab6 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -102,7 +102,6 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
void *OpaqueData,
bool AllowShortCircuit) const {
- ASTContext &Context = getASTContext();
llvm::SmallVector<const CXXRecordDecl*, 8> Queue;
const CXXRecordDecl *Record = this;
@@ -118,7 +117,7 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
}
CXXRecordDecl *Base =
- cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition(Context));
+ cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
if (!Base) {
if (AllowShortCircuit) return false;
AllMatches = false;
@@ -215,10 +214,13 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
Paths.ScratchPath.Access
= MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier());
}
-
+
+ // Track whether there's a path involving this specific base.
+ bool FoundPathThroughBase = false;
+
if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
// We've found a path that terminates at this base.
- FoundPath = true;
+ FoundPath = FoundPathThroughBase = true;
if (Paths.isRecordingPaths()) {
// We have a path. Make a copy of it before moving on.
Paths.Paths.push_back(Paths.ScratchPath);
@@ -240,7 +242,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
// There is a path to a base class that meets the criteria. If we're
// not collecting paths or finding ambiguities, we're done.
- FoundPath = true;
+ FoundPath = FoundPathThroughBase = true;
if (!Paths.isFindingAmbiguities())
return FoundPath;
}
@@ -253,7 +255,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
}
// If we set a virtual earlier, and this isn't a path, forget it again.
- if (SetVirtual && !FoundPath) {
+ if (SetVirtual && !FoundPathThroughBase) {
Paths.DetectedVirtual = 0;
}
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 794b14a1f4a1..5acb82f31a29 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -29,224 +29,81 @@
using namespace clang;
-void Attr::Destroy(ASTContext &C) {
- if (Next) {
- Next->Destroy(C);
- Next = 0;
- }
- this->~Attr();
- C.Deallocate((void*)this);
-}
-
/// \brief Return the TypeLoc wrapper for the type source info.
TypeLoc TypeSourceInfo::getTypeLoc() const {
return TypeLoc(Ty, (void*)(this + 1));
}
//===----------------------------------------------------------------------===//
-// Decl Allocation/Deallocation Method Implementations
+// NamedDecl Implementation
//===----------------------------------------------------------------------===//
+/// \brief Get the most restrictive linkage for the types in the given
+/// template parameter list.
+static Linkage
+getLinkageForTemplateParameterList(const TemplateParameterList *Params) {
+ Linkage L = ExternalLinkage;
+ for (TemplateParameterList::const_iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P))
+ if (!NTTP->getType()->isDependentType()) {
+ L = minLinkage(L, NTTP->getType()->getLinkage());
+ continue;
+ }
-TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
- return new (C) TranslationUnitDecl(C);
-}
-
-NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
- return new (C) NamespaceDecl(DC, L, Id);
-}
-
-void NamespaceDecl::Destroy(ASTContext& C) {
- // NamespaceDecl uses "NextDeclarator" to chain namespace declarations
- // together. They are all top-level Decls.
-
- this->~NamespaceDecl();
- C.Deallocate((void *)this);
-}
-
-
-ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id, QualType T) {
- return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
-}
-
-const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
- switch (SC) {
- case VarDecl::None: break;
- case VarDecl::Auto: return "auto"; break;
- case VarDecl::Extern: return "extern"; break;
- case VarDecl::PrivateExtern: return "__private_extern__"; break;
- case VarDecl::Register: return "register"; break;
- case VarDecl::Static: return "static"; break;
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(*P)) {
+ L = minLinkage(L,
+ getLinkageForTemplateParameterList(TTP->getTemplateParameters()));
+ }
}
- assert(0 && "Invalid storage class");
- return 0;
-}
-
-ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass S, Expr *DefArg) {
- return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
-}
-
-Expr *ParmVarDecl::getDefaultArg() {
- assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
- assert(!hasUninstantiatedDefaultArg() &&
- "Default argument is not yet instantiated!");
-
- Expr *Arg = getInit();
- if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg))
- return E->getSubExpr();
-
- return Arg;
-}
-
-unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
- if (const CXXExprWithTemporaries *E =
- dyn_cast<CXXExprWithTemporaries>(getInit()))
- return E->getNumTemporaries();
-
- return 0;
+ return L;
}
-CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
- assert(getNumDefaultArgTemporaries() &&
- "Default arguments does not have any temporaries!");
-
- CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit());
- return E->getTemporary(i);
-}
+/// \brief Get the most restrictive linkage for the types and
+/// declarations in the given template argument list.
+static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ Linkage L = ExternalLinkage;
-SourceRange ParmVarDecl::getDefaultArgRange() const {
- if (const Expr *E = getInit())
- return E->getSourceRange();
-
- if (hasUninstantiatedDefaultArg())
- return getUninstantiatedDefaultArg()->getSourceRange();
-
- return SourceRange();
-}
-
-void VarDecl::setInit(ASTContext &C, Expr *I) {
- if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
- Eval->~EvaluatedStmt();
- C.Deallocate(Eval);
- }
-
- Init = I;
-}
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ switch (Args[I].getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Expression:
+ break;
+
+ case TemplateArgument::Type:
+ L = minLinkage(L, Args[I].getAsType()->getLinkage());
+ break;
-bool VarDecl::isExternC() const {
- ASTContext &Context = getASTContext();
- if (!Context.getLangOptions().CPlusPlus)
- return (getDeclContext()->isTranslationUnit() &&
- getStorageClass() != Static) ||
- (getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
+ case TemplateArgument::Declaration:
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
+ L = minLinkage(L, ND->getLinkage());
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(Args[I].getAsDecl()))
+ L = minLinkage(L, VD->getType()->getLinkage());
+ break;
- for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
- DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
- if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
- return getStorageClass() != Static;
+ case TemplateArgument::Template:
+ if (TemplateDecl *Template
+ = Args[I].getAsTemplate().getAsTemplateDecl())
+ L = minLinkage(L, Template->getLinkage());
+ break;
+ case TemplateArgument::Pack:
+ L = minLinkage(L,
+ getLinkageForTemplateArgumentList(Args[I].pack_begin(),
+ Args[I].pack_size()));
break;
}
-
- if (DC->isFunctionOrMethod())
- return false;
}
- return false;
+ return L;
}
-FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- DeclarationName N, QualType T,
- TypeSourceInfo *TInfo,
- StorageClass S, bool isInline,
- bool hasWrittenPrototype) {
- FunctionDecl *New
- = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline);
- New->HasWrittenPrototype = hasWrittenPrototype;
- return New;
-}
-
-BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
- return new (C) BlockDecl(DC, L);
-}
-
-FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
- return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
-}
-
-bool FieldDecl::isAnonymousStructOrUnion() const {
- if (!isImplicit() || getDeclName())
- return false;
-
- if (const RecordType *Record = getType()->getAs<RecordType>())
- return Record->getDecl()->isAnonymousStructOrUnion();
-
- return false;
-}
-
-EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
- SourceLocation L,
- IdentifierInfo *Id, QualType T,
- Expr *E, const llvm::APSInt &V) {
- return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
-}
-
-void EnumConstantDecl::Destroy(ASTContext& C) {
- if (Init) Init->Destroy(C);
- Decl::Destroy(C);
-}
-
-TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- TypeSourceInfo *TInfo) {
- return new (C) TypedefDecl(DC, L, Id, TInfo);
-}
-
-// Anchor TypedefDecl's vtable here.
-TypedefDecl::~TypedefDecl() {}
-
-EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, SourceLocation TKL,
- EnumDecl *PrevDecl) {
- EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
- C.getTypeDeclType(Enum, PrevDecl);
- return Enum;
-}
-
-void EnumDecl::Destroy(ASTContext& C) {
- Decl::Destroy(C);
-}
-
-void EnumDecl::completeDefinition(ASTContext &C,
- QualType NewType,
- QualType NewPromotionType) {
- assert(!isDefinition() && "Cannot redefine enums!");
- IntegerType = NewType;
- PromotionType = NewPromotionType;
- TagDecl::completeDefinition();
-}
-
-FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- StringLiteral *Str) {
- return new (C) FileScopeAsmDecl(DC, L, Str);
-}
-
-//===----------------------------------------------------------------------===//
-// NamedDecl Implementation
-//===----------------------------------------------------------------------===//
-
-static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
assert(D->getDeclContext()->getLookupContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -260,7 +117,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
// Explicitly declared static.
if (Var->getStorageClass() == VarDecl::Static)
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
// - an object or reference that is explicitly declared const
// and neither explicitly declared extern nor previously
@@ -274,13 +131,16 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
for (const VarDecl *PrevVar = Var->getPreviousDeclaration();
PrevVar && !FoundExtern;
PrevVar = PrevVar->getPreviousDeclaration())
- if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage)
+ if (isExternalLinkage(PrevVar->getLinkage()))
FoundExtern = true;
if (!FoundExtern)
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ // C++ [temp]p4:
+ // A non-member function template can have internal linkage; any
+ // other template name shall have external linkage.
const FunctionDecl *Function = 0;
if (const FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>(D))
@@ -290,11 +150,11 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// Explicitly declared static.
if (Function->getStorageClass() == FunctionDecl::Static)
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
} else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// - a data member of an anonymous union.
if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- return NamedDecl::InternalLinkage;
+ return InternalLinkage;
}
// C++ [basic.link]p4:
@@ -317,7 +177,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
- if (NamedDecl::Linkage L = PrevVar->getLinkage())
+ if (Linkage L = PrevVar->getLinkage())
return L;
}
}
@@ -326,7 +186,10 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// If the declaration of an identifier for an object has file
// scope and no storage-class specifier, its linkage is
// external.
- return NamedDecl::ExternalLinkage;
+ if (Var->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ return ExternalLinkage;
}
// - a function, unless it has internal linkage; or
@@ -350,12 +213,26 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
- if (NamedDecl::Linkage L = PrevFunc->getLinkage())
+ if (Linkage L = PrevFunc->getLinkage())
return L;
}
}
- return NamedDecl::ExternalLinkage;
+ if (Function->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ if (FunctionTemplateSpecializationInfo *SpecInfo
+ = Function->getTemplateSpecializationInfo()) {
+ Linkage L = SpecInfo->getTemplate()->getLinkage();
+ const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments;
+ L = minLinkage(L,
+ getLinkageForTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size()));
+ return L;
+ }
+
+ return ExternalLinkage;
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -365,29 +242,50 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// defined in a typedef declaration in which the enumeration
// has the typedef name for linkage purposes (7.1.3); or
if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
- if (Tag->getDeclName() || Tag->getTypedefForAnonDecl())
- return NamedDecl::ExternalLinkage;
+ if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) {
+ if (Tag->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ // If this is a class template specialization, consider the
+ // linkage of the template and template arguments.
+ if (const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ Linkage L = getLinkageForTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size());
+ return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage());
+ }
+
+ return ExternalLinkage;
+ }
// - an enumerator belonging to an enumeration with external linkage;
- if (isa<EnumConstantDecl>(D))
- if (cast<NamedDecl>(D->getDeclContext())->getLinkage()
- == NamedDecl::ExternalLinkage)
- return NamedDecl::ExternalLinkage;
+ if (isa<EnumConstantDecl>(D)) {
+ Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage();
+ if (isExternalLinkage(L))
+ return L;
+ }
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
- if (isa<TemplateDecl>(D))
- return NamedDecl::ExternalLinkage;
+ if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
+ if (D->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
+ return getLinkageForTemplateParameterList(
+ Template->getTemplateParameters());
+ }
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
- return NamedDecl::ExternalLinkage;
+ return ExternalLinkage;
- return NamedDecl::NoLinkage;
+ return NoLinkage;
}
-NamedDecl::Linkage NamedDecl::getLinkage() const {
+Linkage NamedDecl::getLinkage() const {
// Handle linkage for namespace-scope names.
if (getDeclContext()->getLookupContext()->isFileContext())
if (Linkage L = getLinkageForNamespaceScopeDecl(this))
@@ -403,9 +301,11 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
if (getDeclContext()->isRecord() &&
(isa<CXXMethodDecl>(this) || isa<VarDecl>(this) ||
(isa<TagDecl>(this) &&
- (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) &&
- cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage)
- return ExternalLinkage;
+ (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl())))) {
+ Linkage L = cast<RecordDecl>(getDeclContext())->getLinkage();
+ if (isExternalLinkage(L))
+ return L;
+ }
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
@@ -424,6 +324,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
return L;
+ if (Function->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
return ExternalLinkage;
}
@@ -434,6 +337,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
return L;
+ if (Var->isInAnonymousNamespace())
+ return UniqueExternalLinkage;
+
return ExternalLinkage;
}
}
@@ -441,7 +347,7 @@ NamedDecl::Linkage NamedDecl::getLinkage() const {
// C++ [basic.link]p6:
// Names not covered by these rules have no linkage.
return NoLinkage;
-}
+ }
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getLangOptions());
@@ -606,6 +512,20 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
// VarDecl Implementation
//===----------------------------------------------------------------------===//
+const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
+ switch (SC) {
+ case VarDecl::None: break;
+ case VarDecl::Auto: return "auto"; break;
+ case VarDecl::Extern: return "extern"; break;
+ case VarDecl::PrivateExtern: return "__private_extern__"; break;
+ case VarDecl::Register: return "register"; break;
+ case VarDecl::Static: return "static"; break;
+ }
+
+ assert(0 && "Invalid storage class");
+ return 0;
+}
+
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S) {
@@ -638,6 +558,127 @@ SourceRange VarDecl::getSourceRange() const {
return SourceRange(Start, getLocation());
}
+bool VarDecl::isExternC() const {
+ ASTContext &Context = getASTContext();
+ if (!Context.getLangOptions().CPlusPlus)
+ return (getDeclContext()->isTranslationUnit() &&
+ getStorageClass() != Static) ||
+ (getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
+
+ for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
+ DC = DC->getParent()) {
+ if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
+ if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
+ return getStorageClass() != Static;
+
+ break;
+ }
+
+ if (DC->isFunctionOrMethod())
+ return false;
+ }
+
+ return false;
+}
+
+VarDecl *VarDecl::getCanonicalDecl() {
+ return getFirstDeclaration();
+}
+
+VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
+ // C++ [basic.def]p2:
+ // A declaration is a definition unless [...] it contains the 'extern'
+ // specifier or a linkage-specification and neither an initializer [...],
+ // it declares a static data member in a class declaration [...].
+ // C++ [temp.expl.spec]p15:
+ // An explicit specialization of a static data member of a template is a
+ // definition if the declaration includes an initializer; otherwise, it is
+ // a declaration.
+ if (isStaticDataMember()) {
+ if (isOutOfLine() && (hasInit() ||
+ getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+ return Definition;
+ else
+ return DeclarationOnly;
+ }
+ // C99 6.7p5:
+ // A definition of an identifier is a declaration for that identifier that
+ // [...] causes storage to be reserved for that object.
+ // Note: that applies for all non-file-scope objects.
+ // C99 6.9.2p1:
+ // If the declaration of an identifier for an object has file scope and an
+ // initializer, the declaration is an external definition for the identifier
+ if (hasInit())
+ return Definition;
+ // AST for 'extern "C" int foo;' is annotated with 'extern'.
+ if (hasExternalStorage())
+ return DeclarationOnly;
+
+ // C99 6.9.2p2:
+ // A declaration of an object that has file scope without an initializer,
+ // and without a storage class specifier or the scs 'static', constitutes
+ // a tentative definition.
+ // No such thing in C++.
+ if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl())
+ return TentativeDefinition;
+
+ // What's left is (in C, block-scope) declarations without initializers or
+ // external storage. These are definitions.
+ return Definition;
+}
+
+VarDecl *VarDecl::getActingDefinition() {
+ DefinitionKind Kind = isThisDeclarationADefinition();
+ if (Kind != TentativeDefinition)
+ return 0;
+
+ VarDecl *LastTentative = false;
+ VarDecl *First = getFirstDeclaration();
+ for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+ I != E; ++I) {
+ Kind = (*I)->isThisDeclarationADefinition();
+ if (Kind == Definition)
+ return 0;
+ else if (Kind == TentativeDefinition)
+ LastTentative = *I;
+ }
+ return LastTentative;
+}
+
+bool VarDecl::isTentativeDefinitionNow() const {
+ DefinitionKind Kind = isThisDeclarationADefinition();
+ if (Kind != TentativeDefinition)
+ return false;
+
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if ((*I)->isThisDeclarationADefinition() == Definition)
+ return false;
+ }
+ return true;
+}
+
+VarDecl *VarDecl::getDefinition() {
+ VarDecl *First = getFirstDeclaration();
+ for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+ I != E; ++I) {
+ if ((*I)->isThisDeclarationADefinition() == Definition)
+ return *I;
+ }
+ return 0;
+}
+
+const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const {
+ redecl_iterator I = redecls_begin(), E = redecls_end();
+ while (I != E && !I->getInit())
+ ++I;
+
+ if (I != E) {
+ D = *I;
+ return I->getInit();
+ }
+ return 0;
+}
+
bool VarDecl::isOutOfLine() const {
if (!isStaticDataMember())
return false;
@@ -667,6 +708,15 @@ VarDecl *VarDecl::getOutOfLineDefinition() {
return 0;
}
+void VarDecl::setInit(Expr *I) {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
+ Eval->~EvaluatedStmt();
+ getASTContext().Deallocate(Eval);
+ }
+
+ Init = I;
+}
+
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
@@ -675,8 +725,7 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
- if (MemberSpecializationInfo *MSI
- = getASTContext().getInstantiatedFromStaticDataMember(this))
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
return TSK_Undeclared;
@@ -697,29 +746,53 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
MSI->setPointOfInstantiation(PointOfInstantiation);
}
-bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
- if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
- return false;
+//===----------------------------------------------------------------------===//
+// ParmVarDecl Implementation
+//===----------------------------------------------------------------------===//
- const VarDecl *Def = 0;
- return (!getDefinition(Def) &&
- (getStorageClass() == None || getStorageClass() == Static));
+ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, Expr *DefArg) {
+ return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
}
-const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
- redecl_iterator I = redecls_begin(), E = redecls_end();
- while (I != E && !I->getInit())
- ++I;
+Expr *ParmVarDecl::getDefaultArg() {
+ assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!");
+ assert(!hasUninstantiatedDefaultArg() &&
+ "Default argument is not yet instantiated!");
+
+ Expr *Arg = getInit();
+ if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg))
+ return E->getSubExpr();
+
+ return Arg;
+}
+
+unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
+ if (const CXXExprWithTemporaries *E =
+ dyn_cast<CXXExprWithTemporaries>(getInit()))
+ return E->getNumTemporaries();
- if (I != E) {
- Def = *I;
- return I->getInit();
- }
return 0;
}
-VarDecl *VarDecl::getCanonicalDecl() {
- return getFirstDeclaration();
+CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
+ assert(getNumDefaultArgTemporaries() &&
+ "Default arguments does not have any temporaries!");
+
+ CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit());
+ return E->getTemporary(i);
+}
+
+SourceRange ParmVarDecl::getDefaultArgRange() const {
+ if (const Expr *E = getInit())
+ return E->getSourceRange();
+
+ if (hasUninstantiatedDefaultArg())
+ return getUninstantiatedDefaultArg()->getSourceRange();
+
+ return SourceRange();
}
//===----------------------------------------------------------------------===//
@@ -826,6 +899,26 @@ bool FunctionDecl::isGlobal() const {
return true;
}
+void
+FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
+ redeclarable_base::setPreviousDeclaration(PrevDecl);
+
+ if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
+ FunctionTemplateDecl *PrevFunTmpl
+ = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
+ assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
+ FunTmpl->setPreviousDeclaration(PrevFunTmpl);
+ }
+}
+
+const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
+ return getFirstDeclaration();
+}
+
+FunctionDecl *FunctionDecl::getCanonicalDecl() {
+ return getFirstDeclaration();
+}
+
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
///
@@ -882,14 +975,13 @@ unsigned FunctionDecl::getNumParams() const {
}
-void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
- unsigned NumParams) {
+void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
assert(ParamInfo == 0 && "Already has param info!");
assert(NumParams == getNumParams() && "Parameter count mismatch!");
// Zero params -> null pointer.
if (NumParams) {
- void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
+ void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams);
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
@@ -1014,26 +1106,6 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
return false;
}
-void
-FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
- redeclarable_base::setPreviousDeclaration(PrevDecl);
-
- if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
- FunctionTemplateDecl *PrevFunTmpl
- = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
- assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
- FunTmpl->setPreviousDeclaration(PrevFunTmpl);
- }
-}
-
-const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
- return getFirstDeclaration();
-}
-
-FunctionDecl *FunctionDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
-
/// getOverloadedOperator - Which C++ overloaded operator this
/// function represents, if any.
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
@@ -1146,8 +1218,7 @@ FunctionDecl::getTemplateSpecializationArgs() const {
}
void
-FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
- FunctionTemplateDecl *Template,
+FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK) {
@@ -1156,7 +1227,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (!Info)
- Info = new (Context) FunctionTemplateSpecializationInfo;
+ Info = new (getASTContext()) FunctionTemplateSpecializationInfo;
Info->Function = this;
Info->Template.setPointer(Template);
@@ -1254,6 +1325,26 @@ bool FunctionDecl::isOutOfLine() const {
}
//===----------------------------------------------------------------------===//
+// FieldDecl Implementation
+//===----------------------------------------------------------------------===//
+
+FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
+ return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
+}
+
+bool FieldDecl::isAnonymousStructOrUnion() const {
+ if (!isImplicit() || getDeclName())
+ return false;
+
+ if (const RecordType *Record = getType()->getAs<RecordType>())
+ return Record->getDecl()->isAnonymousStructOrUnion();
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1271,9 +1362,23 @@ void TagDecl::startDefinition() {
TagT->decl.setPointer(this);
TagT->decl.setInt(1);
}
+
+ if (isa<CXXRecordDecl>(this)) {
+ CXXRecordDecl *D = cast<CXXRecordDecl>(this);
+ struct CXXRecordDecl::DefinitionData *Data =
+ new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
+ do {
+ D->DefinitionData = Data;
+ D = cast_or_null<CXXRecordDecl>(D->getPreviousDeclaration());
+ } while (D);
+ }
}
void TagDecl::completeDefinition() {
+ assert((!isa<CXXRecordDecl>(this) ||
+ cast<CXXRecordDecl>(this)->hasDefinition()) &&
+ "definition completed but not started");
+
IsDefinition = true;
if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
assert(TagT->decl.getPointer() == this &&
@@ -1282,7 +1387,7 @@ void TagDecl::completeDefinition() {
}
}
-TagDecl* TagDecl::getDefinition(ASTContext& C) const {
+TagDecl* TagDecl::getDefinition() const {
if (isDefinition())
return const_cast<TagDecl *>(this);
@@ -1305,6 +1410,30 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
}
//===----------------------------------------------------------------------===//
+// EnumDecl Implementation
+//===----------------------------------------------------------------------===//
+
+EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, SourceLocation TKL,
+ EnumDecl *PrevDecl) {
+ EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
+ C.getTypeDeclType(Enum, PrevDecl);
+ return Enum;
+}
+
+void EnumDecl::Destroy(ASTContext& C) {
+ Decl::Destroy(C);
+}
+
+void EnumDecl::completeDefinition(QualType NewType,
+ QualType NewPromotionType) {
+ assert(!isDefinition() && "Cannot redefine enums!");
+ IntegerType = NewType;
+ PromotionType = NewPromotionType;
+ TagDecl::completeDefinition();
+}
+
+//===----------------------------------------------------------------------===//
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1341,7 +1470,7 @@ bool RecordDecl::isInjectedClassName() const {
/// completeDefinition - Notes that the definition of this type is now
/// complete.
-void RecordDecl::completeDefinition(ASTContext& C) {
+void RecordDecl::completeDefinition() {
assert(!isDefinition() && "Cannot redefine record!");
TagDecl::completeDefinition();
}
@@ -1364,14 +1493,14 @@ void BlockDecl::Destroy(ASTContext& C) {
Decl::Destroy(C);
}
-void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
+void BlockDecl::setParams(ParmVarDecl **NewParamInfo,
unsigned NParms) {
assert(ParamInfo == 0 && "Already has param info!");
// Zero params -> null pointer.
if (NParms) {
NumParams = NParms;
- void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
+ void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams);
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
}
@@ -1380,3 +1509,74 @@ void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
unsigned BlockDecl::getNumParams() const {
return NumParams;
}
+
+
+//===----------------------------------------------------------------------===//
+// Other Decl Allocation/Deallocation Method Implementations
+//===----------------------------------------------------------------------===//
+
+TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
+ return new (C) TranslationUnitDecl(C);
+}
+
+NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id) {
+ return new (C) NamespaceDecl(DC, L, Id);
+}
+
+void NamespaceDecl::Destroy(ASTContext& C) {
+ // NamespaceDecl uses "NextDeclarator" to chain namespace declarations
+ // together. They are all top-level Decls.
+
+ this->~NamespaceDecl();
+ C.Deallocate((void *)this);
+}
+
+
+ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id, QualType T) {
+ return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
+}
+
+FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ DeclarationName N, QualType T,
+ TypeSourceInfo *TInfo,
+ StorageClass S, bool isInline,
+ bool hasWrittenPrototype) {
+ FunctionDecl *New
+ = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline);
+ New->HasWrittenPrototype = hasWrittenPrototype;
+ return New;
+}
+
+BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+ return new (C) BlockDecl(DC, L);
+}
+
+EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
+ SourceLocation L,
+ IdentifierInfo *Id, QualType T,
+ Expr *E, const llvm::APSInt &V) {
+ return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
+}
+
+void EnumConstantDecl::Destroy(ASTContext& C) {
+ if (Init) Init->Destroy(C);
+ Decl::Destroy(C);
+}
+
+TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ TypeSourceInfo *TInfo) {
+ return new (C) TypedefDecl(DC, L, Id, TInfo);
+}
+
+// Anchor TypedefDecl's vtable here.
+TypedefDecl::~TypedefDecl() {}
+
+FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ StringLiteral *Str) {
+ return new (C) FileScopeAsmDecl(DC, L, Str);
+}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 84aa81ca76db..863a1cbd03c4 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -448,7 +448,10 @@ bool DeclContext::classof(const Decl *D) {
}
DeclContext::~DeclContext() {
- delete static_cast<StoredDeclsMap*>(LookupPtr);
+ // FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because
+ // ~DeclContext() is not guaranteed to be called when ASTContext uses
+ // a BumpPtrAllocator.
+ // delete static_cast<StoredDeclsMap*>(LookupPtr);
}
void DeclContext::DestroyDecls(ASTContext &C) {
@@ -622,7 +625,8 @@ DeclContext::LoadVisibleDeclsFromExternalStorage() const {
// Load the declaration IDs for all of the names visible in this
// context.
assert(!LookupPtr && "Have a lookup map before de-serialization?");
- StoredDeclsMap *Map = new StoredDeclsMap;
+ StoredDeclsMap *Map =
+ (StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap();
LookupPtr = Map;
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
(*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
@@ -830,8 +834,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
if (isa<ClassTemplateSpecializationDecl>(D))
return;
- if (!LookupPtr)
- LookupPtr = new StoredDeclsMap;
+ ASTContext *C = 0;
+ if (!LookupPtr) {
+ C = &getParentASTContext();
+ LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap();
+ }
// Insert this declaration into the map.
StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr);
@@ -844,7 +851,10 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
// If it is possible that this is a redeclaration, check to see if there is
// already a decl for which declarationReplaces returns true. If there is
// one, just replace it and return.
- if (DeclNameEntries.HandleRedeclaration(getParentASTContext(), D))
+ if (!C)
+ C = &getParentASTContext();
+
+ if (DeclNameEntries.HandleRedeclaration(*C, D))
return;
// Put this declaration into the appropriate slot.
@@ -896,3 +906,18 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) {
}
}
}
+
+//===----------------------------------------------------------------------===//
+// Creation and Destruction of StoredDeclsMaps. //
+//===----------------------------------------------------------------------===//
+
+void *ASTContext::CreateStoredDeclsMap() {
+ StoredDeclsMap *M = new StoredDeclsMap();
+ SDMs.push_back(M);
+ return M;
+}
+
+void ASTContext::ReleaseDeclContextMaps() {
+ for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I)
+ delete (StoredDeclsMap*) *I;
+}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index fe6064df325a..b0569d68015f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -25,18 +25,23 @@ using namespace clang;
// Decl Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
-CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- CXXRecordDecl *PrevDecl,
- SourceLocation TKL)
- : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL),
- UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
+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),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
+ Definition(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),
+ DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
@@ -57,31 +62,35 @@ CXXRecordDecl::~CXXRecordDecl() {
}
void CXXRecordDecl::Destroy(ASTContext &C) {
- C.Deallocate(Bases);
- C.Deallocate(VBases);
+ if (data().Definition == this) {
+ C.Deallocate(data().Bases);
+ C.Deallocate(data().VBases);
+ C.Deallocate(&data());
+ }
this->RecordDecl::Destroy(C);
}
void
-CXXRecordDecl::setBases(ASTContext &C,
- CXXBaseSpecifier const * const *Bases,
+CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
unsigned NumBases) {
+ ASTContext &C = getASTContext();
+
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class (clause 9) with [...]
// no base classes [...].
- Aggregate = false;
+ data().Aggregate = false;
- if (this->Bases)
- C.Deallocate(this->Bases);
+ if (data().Bases)
+ C.Deallocate(data().Bases);
int vbaseCount = 0;
llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
bool hasDirectVirtualBase = false;
- this->Bases = new(C) CXXBaseSpecifier [NumBases];
- this->NumBases = NumBases;
+ data().Bases = new(C) CXXBaseSpecifier [NumBases];
+ data().NumBases = NumBases;
for (unsigned i = 0; i < NumBases; ++i) {
- this->Bases[i] = *Bases[i];
+ data().Bases[i] = *Bases[i];
// Keep track of inherited vbases for this base class.
const CXXBaseSpecifier *Base = Bases[i];
QualType BaseType = Base->getType();
@@ -130,13 +139,13 @@ CXXRecordDecl::setBases(ASTContext &C,
}
if (vbaseCount > 0) {
// build AST for inhireted, direct or indirect, virtual bases.
- this->VBases = new (C) CXXBaseSpecifier [vbaseCount];
- this->NumVBases = vbaseCount;
+ data().VBases = new (C) CXXBaseSpecifier [vbaseCount];
+ data().NumVBases = vbaseCount;
for (int i = 0; i < vbaseCount; i++) {
QualType QT = UniqueVbases[i]->getType();
CXXRecordDecl *VBaseClassDecl
= cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
- this->VBases[i] =
+ data().VBases[i] =
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
UniqueVbases[i]->getAccessSpecifier(), QT);
@@ -239,32 +248,32 @@ CXXRecordDecl::addedConstructor(ASTContext &Context,
CXXConstructorDecl *ConDecl) {
assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl");
// Note that we have a user-declared constructor.
- UserDeclaredConstructor = true;
+ data().UserDeclaredConstructor = true;
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class (clause 9) with no
// user-declared constructors (12.1) [...].
- Aggregate = false;
+ data().Aggregate = false;
// C++ [class]p4:
// A POD-struct is an aggregate class [...]
- PlainOldData = false;
+ data().PlainOldData = false;
// C++ [class.ctor]p5:
// A constructor is trivial if it is an implicitly-declared default
// constructor.
// FIXME: C++0x: don't do this for "= default" default constructors.
- HasTrivialConstructor = false;
+ data().HasTrivialConstructor = false;
// Note when we have a user-declared copy constructor, which will
// suppress the implicit declaration of a copy constructor.
if (ConDecl->isCopyConstructor()) {
- UserDeclaredCopyConstructor = true;
+ data().UserDeclaredCopyConstructor = 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.
- HasTrivialCopyConstructor = false;
+ data().HasTrivialCopyConstructor = false;
}
}
@@ -295,17 +304,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
OpDecl->setCopyAssignment(true);
// Suppress the implicit declaration of a copy constructor.
- UserDeclaredCopyAssignment = true;
+ data().UserDeclaredCopyAssignment = 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.
- HasTrivialCopyAssignment = false;
+ data().HasTrivialCopyAssignment = false;
// C++ [class]p4:
// A POD-struct is an aggregate class that [...] has no user-defined copy
// assignment operator [...].
- PlainOldData = false;
+ data().PlainOldData = false;
}
void
@@ -415,42 +424,42 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
- return &Conversions;
+ return &data().Conversions;
// If visible conversion list is already evaluated, return it.
- if (ComputedVisibleConversions)
- return &VisibleConversions;
+ if (data().ComputedVisibleConversions)
+ return &data().VisibleConversions;
llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet;
collectConversionFunctions(TopConversionsTypeSet);
getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
TopConversionsTypeSet);
- ComputedVisibleConversions = true;
- return &VisibleConversions;
+ data().ComputedVisibleConversions = true;
+ return &data().VisibleConversions;
}
void CXXRecordDecl::addVisibleConversionFunction(
CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- VisibleConversions.addDecl(ConvDecl);
+ data().VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addVisibleConversionFunction(
FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- VisibleConversions.addDecl(ConvDecl);
+ data().VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- Conversions.addDecl(ConvDecl);
+ data().Conversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- Conversions.addDecl(ConvDecl);
+ data().Conversions.addDecl(ConvDecl);
}
@@ -579,7 +588,8 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
// then this function is a usual deallocation function.
ASTContext &Context = getASTContext();
if (getNumParams() != 2 ||
- !Context.hasSameType(getParamDecl(1)->getType(), Context.getSizeType()))
+ !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(),
+ Context.getSizeType()))
return false;
// This function is a usual deallocation function if there are no
@@ -604,7 +614,9 @@ static OverriddenMethodsMapTy *OverriddenMethods = 0;
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
-
+ assert(!MD->getParent()->isDependentContext() &&
+ "Can't add an overridden method to a class template!");
+
// FIXME: The CXXMethodDecl dtor needs to remove and free the entry.
if (!OverriddenMethods)
@@ -671,42 +683,25 @@ bool CXXMethodDecl::hasInlineBody() const {
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
- TypeSourceInfo *TInfo, CXXConstructorDecl *C,
- SourceLocation L,
- Expr **Args, unsigned NumArgs,
- SourceLocation R)
- : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C),
+ TypeSourceInfo *TInfo,
+ SourceLocation L, Expr *Init, SourceLocation R)
+ : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
LParenLoc(L), RParenLoc(R)
{
- if (NumArgs > 0) {
- this->NumArgs = NumArgs;
- this->Args = new (Context) Stmt*[NumArgs];
- for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
- this->Args[Idx] = Args[Idx];
- }
}
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
FieldDecl *Member, SourceLocation MemberLoc,
- CXXConstructorDecl *C, SourceLocation L,
- Expr **Args, unsigned NumArgs,
- SourceLocation R)
- : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0),
- CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R)
+ SourceLocation L, Expr *Init, SourceLocation R)
+ : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
+ AnonUnionMember(0), LParenLoc(L), RParenLoc(R)
{
- if (NumArgs > 0) {
- this->NumArgs = NumArgs;
- this->Args = new (Context) Stmt*[NumArgs];
- for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
- this->Args[Idx] = Args[Idx];
- }
}
void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) {
- for (unsigned I = 0; I != NumArgs; ++I)
- Args[I]->Destroy(Context);
- Context.Deallocate(Args);
+ if (Init)
+ Init->Destroy(Context);
this->~CXXBaseOrMemberInitializer();
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index ffda505aaab1..131e098d0467 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -111,8 +111,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
// Look through categories.
for (ObjCCategoryDecl *Category = OID->getCategoryList();
Category; Category = Category->getNextClassCategory()) {
- if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
- return P;
+ if (!Category->IsClassExtension())
+ if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
+ return P;
}
// Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
@@ -124,10 +125,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
return OID->getSuperClass()->FindPropertyDeclaration(PropertyId);
} else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) {
// Look through protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
- E = OCD->protocol_end(); I != E; ++I) {
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
- return P;
+ if (!OCD->IsClassExtension())
+ for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
+ E = OCD->protocol_end(); I != E; ++I) {
+ if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+ return P;
}
}
return 0;
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 32ac53d85be8..a625865ecdb3 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -403,32 +404,51 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
CXXBaseOrMemberInitializer * BMInitializer = (*B);
if (B != CDecl->init_begin())
Out << ", ";
- bool hasArguments = (BMInitializer->arg_begin() !=
- BMInitializer->arg_end());
if (BMInitializer->isMemberInitializer()) {
FieldDecl *FD = BMInitializer->getMember();
Out << FD->getNameAsString();
+ } else {
+ Out << QualType(BMInitializer->getBaseClass(), 0).getAsString();
}
- else // FIXME. skip dependent types for now.
- if (const RecordType *RT =
- BMInitializer->getBaseClass()->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(RT->getDecl());
- Out << BaseDecl->getNameAsString();
- }
- if (hasArguments) {
- Out << "(";
- for (CXXBaseOrMemberInitializer::const_arg_iterator BE =
- BMInitializer->const_arg_begin(),
- EE = BMInitializer->const_arg_end(); BE != EE; ++BE) {
- if (BE != BMInitializer->const_arg_begin())
- Out<< ", ";
- const Expr *Exp = (*BE);
- Exp->printPretty(Out, Context, 0, Policy, Indentation);
+
+ Out << "(";
+ if (!BMInitializer->getInit()) {
+ // Nothing to print
+ } else {
+ Expr *Init = BMInitializer->getInit();
+ if (CXXExprWithTemporaries *Tmp
+ = dyn_cast<CXXExprWithTemporaries>(Init))
+ Init = Tmp->getSubExpr();
+
+ Init = Init->IgnoreParens();
+
+ Expr *SimpleInit = 0;
+ Expr **Args = 0;
+ unsigned NumArgs = 0;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ } else if (CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(Init)) {
+ Args = Construct->getArgs();
+ NumArgs = Construct->getNumArgs();
+ } else
+ SimpleInit = Init;
+
+ if (SimpleInit)
+ SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
+ else {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (isa<CXXDefaultArgExpr>(Args[I]))
+ break;
+
+ if (I)
+ Out << ", ";
+ Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
+ }
}
- Out << ")";
- } else
- Out << "()";
+ }
+ Out << ")";
}
}
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 75b3975322b2..d80db45f4557 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -213,7 +213,8 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
TemplateArgs.push_back(TemplateArgument(ParamType));
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
+ Expr *E = new (Context) DeclRefExpr(NTTP,
+ NTTP->getType().getNonReferenceType(),
NTTP->getLocation());
TemplateArgs.push_back(TemplateArgument(E));
} else {
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index ff810735bc81..19b58bcbaf03 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -66,27 +66,33 @@ public:
}
};
-bool operator<(DeclarationName LHS, DeclarationName RHS) {
+static int compareInt(unsigned A, unsigned B) {
+ return (A < B ? -1 : (A > B ? 1 : 0));
+}
+
+int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
if (LHS.getNameKind() != RHS.getNameKind())
- return LHS.getNameKind() < RHS.getNameKind();
+ return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1);
switch (LHS.getNameKind()) {
- case DeclarationName::Identifier:
- return LHS.getAsIdentifierInfo()->getName() <
- RHS.getAsIdentifierInfo()->getName();
+ case DeclarationName::Identifier: {
+ IdentifierInfo *LII = LHS.getAsIdentifierInfo();
+ IdentifierInfo *RII = RHS.getAsIdentifierInfo();
+ if (!LII) return RII ? -1 : 0;
+ if (!RII) return 1;
+
+ return LII->getName().compare(RII->getName());
+ }
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector: {
Selector LHSSelector = LHS.getObjCSelector();
Selector RHSSelector = RHS.getObjCSelector();
- for (unsigned I = 0,
- N = std::min(LHSSelector.getNumArgs(), RHSSelector.getNumArgs());
- I != N; ++I) {
+ unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs();
+ for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) {
IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I);
IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I);
- if (!LHSId || !RHSId)
- return LHSId && !RHSId;
switch (LHSId->getName().compare(RHSId->getName())) {
case -1: return true;
@@ -94,27 +100,32 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) {
default: break;
}
}
-
- return LHSSelector.getNumArgs() < RHSSelector.getNumArgs();
+
+ return compareInt(LN, RN);
}
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
- return QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType());
+ if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType()))
+ return -1;
+ if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType()))
+ return 1;
+ return 0;
case DeclarationName::CXXOperatorName:
- return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator();
+ return compareInt(LHS.getCXXOverloadedOperator(),
+ RHS.getCXXOverloadedOperator());
case DeclarationName::CXXLiteralOperatorName:
- return LHS.getCXXLiteralIdentifier()->getName() <
- RHS.getCXXLiteralIdentifier()->getName();
+ return LHS.getCXXLiteralIdentifier()->getName().compare(
+ RHS.getCXXLiteralIdentifier()->getName());
case DeclarationName::CXXUsingDirective:
- return false;
+ return 0;
}
- return false;
+ return 0;
}
} // end namespace clang
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index fa44b510e99a..4cb0aa4560de 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -99,8 +99,7 @@ void DeclRefExpr::computeDependence() {
else if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
if (Var->getType()->isIntegralType() &&
Var->getType().getCVRQualifiers() == Qualifiers::Const) {
- const VarDecl *Def = 0;
- if (const Expr *Init = Var->getDefinition(Def))
+ if (const Expr *Init = Var->getAnyInitializer())
if (Init->isValueDependent())
ValueDependent = true;
}
@@ -164,17 +163,18 @@ SourceRange DeclRefExpr::getSourceRange() const {
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
// expr" policy instead.
-std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT,
- const Decl *CurrentDecl) {
+std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
+ ASTContext &Context = CurrentDecl->getASTContext();
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
- if (IT != PrettyFunction)
+ if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
return FD->getNameAsString();
llvm::SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- if (MD->isVirtual())
+ if (MD->isVirtual() && IT != PrettyFunctionNoVirtual)
Out << "virtual ";
if (MD->isStatic())
Out << "static ";
@@ -827,9 +827,17 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(this);
// Consider comma to have side effects if the LHS or RHS does.
- if (BO->getOpcode() == BinaryOperator::Comma)
+ if (BO->getOpcode() == BinaryOperator::Comma) {
+ // ((foo = <blah>), 0) is an idiom for hiding the result (and
+ // lvalue-ness) of an assignment written in a macro.
+ if (IntegerLiteral *IE =
+ dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens()))
+ if (IE->getValue() == 0)
+ return false;
+
return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
+ }
if (BO->isAssignmentOp())
return false;
@@ -1068,9 +1076,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (isa<FieldDecl>(Member)) {
if (m->isArrow())
return LV_Valid;
- Expr *BaseExp = m->getBase();
- return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ?
- LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx);
+ return m->getBase()->isLvalue(Ctx);
}
// -- If it refers to a static member function [...], then
@@ -1093,8 +1099,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
if (m->isArrow())
return LV_Valid;
Expr *BaseExp = m->getBase();
- return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ?
- LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx);
+ if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass)
+ return LV_SubObjCPropertySetting;
+ return
+ (BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ?
+ LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx);
}
case UnaryOperatorClass:
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
@@ -1205,6 +1214,9 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
case CXXBindTemporaryExprClass:
return cast<CXXBindTemporaryExpr>(this)->getSubExpr()->
isLvalueInternal(Ctx);
+ case CXXBindReferenceExprClass:
+ // Something that's bound to a reference is always an lvalue.
+ return LV_Valid;
case ConditionalOperatorClass: {
// Complicated handling is only for C++.
if (!Ctx.getLangOptions().CPlusPlus)
@@ -1281,7 +1293,9 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
}
return MLV_InvalidExpression;
case LV_MemberFunction: return MLV_MemberFunction;
- case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
+ case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
+ case LV_SubObjCPropertyGetterSetting:
+ return MLV_SubObjCPropertyGetterSetting;
}
// The following is illegal:
@@ -1594,6 +1608,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
case Expr::CXXBindTemporaryExprClass:
+ case Expr::CXXBindReferenceExprClass:
case Expr::CXXExprWithTemporariesClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXUnresolvedConstructExprClass:
@@ -1613,7 +1628,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::BlockExprClass:
case Expr::BlockDeclRefExprClass:
case Expr::NoStmtClass:
- case Expr::ExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::GNUNullExprClass:
@@ -1650,30 +1664,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Quals.hasVolatile() || !Quals.hasConst())
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- // Look for the definition of this variable, which will actually have
- // an initializer.
- const VarDecl *Def = 0;
- const Expr *Init = Dcl->getDefinition(Def);
+ // Look for a declaration of this variable that has an initializer.
+ const VarDecl *ID = 0;
+ const Expr *Init = Dcl->getAnyInitializer(ID);
if (Init) {
- if (Def->isInitKnownICE()) {
+ if (ID->isInitKnownICE()) {
// We have already checked whether this subexpression is an
// integral constant expression.
- if (Def->isInitICE())
+ if (ID->isInitICE())
return NoDiag();
else
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
}
- // C++ [class.static.data]p4:
- // If a static data member is of const integral or const
- // enumeration type, its declaration in the class definition can
- // specify a constant-initializer which shall be an integral
- // constant expression (5.19). In that case, the member can appear
- // in integral constant expressions.
- if (Def->isOutOfLine()) {
- Dcl->setInitKnownICE(false);
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
+ // It's an ICE whether or not the definition we found is
+ // out-of-line. See DR 721 and the discussion in Clang PR
+ // 6206 for details.
if (Dcl->isCheckingICE()) {
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
@@ -1810,9 +1816,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
}
}
- case Expr::CastExprClass:
case Expr::ImplicitCastExprClass:
- case Expr::ExplicitCastExprClass:
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:
case Expr::CXXNamedCastExprClass:
@@ -1954,6 +1958,13 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx,
FieldDecl *Expr::getBitField() {
Expr *E = this->IgnoreParens();
+ while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr()->IgnoreParens();
+ else
+ break;
+ }
+
if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl()))
if (Field->isBitField())
@@ -1966,6 +1977,25 @@ FieldDecl *Expr::getBitField() {
return 0;
}
+bool Expr::refersToVectorElement() const {
+ const Expr *E = this->IgnoreParens();
+
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp)
+ E = ICE->getSubExpr()->IgnoreParens();
+ else
+ break;
+ }
+
+ if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E))
+ return ASE->getBase()->getType()->isVectorType();
+
+ if (isa<ExtVectorElementExpr>(E))
+ return true;
+
+ return false;
+}
+
/// isArrow - Return true if the base expression is a pointer to vector,
/// return false if the base expression is a vector.
bool ExtVectorElementExpr::isArrow() const {
@@ -2030,14 +2060,15 @@ void ExtVectorElementExpr::getEncodedElementAccess(
}
// constructor for instance messages.
-ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
+ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver,
+ Selector selInfo,
+ QualType retType, ObjCMethodDecl *mproto,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
- SubExprs = new Stmt*[NumArgs+1];
+ SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = receiver;
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2049,14 +2080,15 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
// constructor for class messages.
// FIXME: clsName should be typed to ObjCInterfaceType
-ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
+ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName,
+ Selector selInfo, QualType retType,
+ ObjCMethodDecl *mproto,
+ SourceLocation LBrac, SourceLocation RBrac,
+ Expr **ArgExprs, unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
- SubExprs = new Stmt*[NumArgs+1];
+ SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown);
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2067,14 +2099,15 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
}
// constructor for class messages.
-ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
+ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls,
+ Selector selInfo, QualType retType,
+ ObjCMethodDecl *mproto, SourceLocation LBrac,
+ SourceLocation RBrac, Expr **ArgExprs,
+ unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
- SubExprs = new Stmt*[NumArgs+1];
+ SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown);
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2109,6 +2142,13 @@ void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) {
SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown);
}
+void ObjCMessageExpr::DoDestroy(ASTContext &C) {
+ DestroyChildren(C);
+ if (SubExprs)
+ C.Deallocate(SubExprs);
+ this->~ObjCMessageExpr();
+ C.Deallocate((void*) this);
+}
bool ChooseExpr::isConditionTrue(ASTContext &C) const {
return getCond()->EvaluateAsInt(C) != 0;
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index a6574efda8ee..f4b8333dd3ae 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -73,7 +73,7 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() {
}
// CXXNewExpr
-CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
+CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
Expr **placementArgs, unsigned numPlaceArgs,
bool parenTypeId, Expr *arraySize,
CXXConstructorDecl *constructor, bool initializer,
@@ -87,7 +87,7 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
OperatorDelete(operatorDelete), Constructor(constructor),
StartLoc(startLoc), EndLoc(endLoc) {
unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
- SubExprs = new Stmt*[TotalSize];
+ SubExprs = new (C) Stmt*[TotalSize];
unsigned i = 0;
if (Array)
SubExprs[i++] = arraySize;
@@ -98,6 +98,14 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
assert(i == TotalSize);
}
+void CXXNewExpr::DoDestroy(ASTContext &C) {
+ DestroyChildren(C);
+ if (SubExprs)
+ C.Deallocate(SubExprs);
+ this->~CXXNewExpr();
+ C.Deallocate((void*)this);
+}
+
Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator CXXNewExpr::child_end() {
return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs();
@@ -116,6 +124,7 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
// UnresolvedLookupExpr
UnresolvedLookupExpr *
UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
+ CXXRecordDecl *NamingClass,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange, DeclarationName Name,
SourceLocation NameLoc, bool ADL,
@@ -125,7 +134,8 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
ExplicitTemplateArgumentList::sizeFor(Args));
UnresolvedLookupExpr *ULE
= new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy,
- Dependent, Qualifier, QualifierRange,
+ Dependent, NamingClass,
+ Qualifier, QualifierRange,
Name, NameLoc, ADL,
/*Overload*/ true,
/*ExplicitTemplateArgs*/ true);
@@ -135,10 +145,9 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
return ULE;
}
-bool UnresolvedLookupExpr::
- ComputeDependence(UnresolvedSetImpl::const_iterator Begin,
- UnresolvedSetImpl::const_iterator End,
- const TemplateArgumentListInfo *Args) {
+bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End,
+ const TemplateArgumentListInfo *Args) {
for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I)
if ((*I)->getDeclContext()->isDependentContext())
return true;
@@ -393,6 +402,19 @@ void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) {
C.Deallocate(this);
}
+CXXBindReferenceExpr *CXXBindReferenceExpr::Create(ASTContext &C, Expr *SubExpr,
+ bool ExtendsLifetime,
+ bool RequiresTemporaryCopy) {
+ return new (C) CXXBindReferenceExpr(SubExpr,
+ ExtendsLifetime,
+ RequiresTemporaryCopy);
+}
+
+void CXXBindReferenceExpr::DoDestroy(ASTContext &C) {
+ this->~CXXBindReferenceExpr();
+ C.Deallocate(this);
+}
+
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
CXXConstructorDecl *Cons,
QualType writtenTy,
@@ -409,22 +431,26 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
- bool ZeroInitialization) {
+ bool ZeroInitialization,
+ bool BaseInitialization) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
- Elidable, Args, NumArgs, ZeroInitialization);
+ Elidable, Args, NumArgs, ZeroInitialization,
+ BaseInitialization);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
Expr **args, unsigned numargs,
- bool ZeroInitialization)
+ bool ZeroInitialization,
+ bool BaseInitialization)
: Expr(SC, T,
T->isDependentType(),
(T->isDependentType() ||
CallExpr::hasAnyValueDependentArguments(args, numargs))),
Constructor(D), Loc(Loc), Elidable(elidable),
- ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs)
+ ZeroInitialization(ZeroInitialization),
+ BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs)
{
if (NumArgs) {
Args = new (C) Stmt*[NumArgs];
@@ -491,6 +517,15 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_end() {
return &SubExpr + 1;
}
+// CXXBindReferenceExpr
+Stmt::child_iterator CXXBindReferenceExpr::child_begin() {
+ return &SubExpr;
+}
+
+Stmt::child_iterator CXXBindReferenceExpr::child_end() {
+ return &SubExpr + 1;
+}
+
// CXXConstructExpr
Stmt::child_iterator CXXConstructExpr::child_begin() {
return &Args[0];
@@ -618,15 +653,13 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
DeclarationName MemberName,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs)
- : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent),
- Base(Base), BaseType(BaseType), IsArrow(IsArrow),
- HasUnresolvedUsing(HasUnresolvedUsing),
- HasExplicitTemplateArgs(TemplateArgs != 0),
- OperatorLoc(OperatorLoc),
- Qualifier(Qualifier), QualifierRange(QualifierRange),
- MemberName(MemberName), MemberLoc(MemberLoc) {
+ : OverloadExpr(UnresolvedMemberExprClass, T, Dependent,
+ Qualifier, QualifierRange, MemberName, MemberLoc,
+ TemplateArgs != 0),
+ IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
+ Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) {
if (TemplateArgs)
- getExplicitTemplateArgs()->initializeFrom(*TemplateArgs);
+ getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
}
UnresolvedMemberExpr *
@@ -651,6 +684,35 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
Member, MemberLoc, TemplateArgs);
}
+CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
+ // Unlike for UnresolvedLookupExpr, it is very easy to re-derive this.
+
+ // If there was a nested name specifier, it names the naming class.
+ // It can't be dependent: after all, we were actually able to do the
+ // lookup.
+ const RecordType *RT;
+ if (getQualifier()) {
+ Type *T = getQualifier()->getAsType();
+ assert(T && "qualifier in member expression does not name type");
+ RT = T->getAs<RecordType>();
+ assert(RT && "qualifier in member expression does not name record");
+
+ // Otherwise the naming class must have been the base class.
+ } else {
+ QualType BaseType = getBaseType().getNonReferenceType();
+ if (isArrow()) {
+ const PointerType *PT = BaseType->getAs<PointerType>();
+ assert(PT && "base of arrow member access is not pointer");
+ BaseType = PT->getPointeeType();
+ }
+
+ RT = BaseType->getAs<RecordType>();
+ assert(RT && "base of member expression does not name record");
+ }
+
+ return cast<CXXRecordDecl>(RT->getDecl());
+}
+
Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
return child_iterator(&Base);
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 086249c811f9..1a44cd02d9c1 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -263,8 +263,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
if (!VD->getType()->isReferenceType())
return APValue(E);
// FIXME: Check whether VD might be overridden!
- const VarDecl *Def = 0;
- if (const Expr *Init = VD->getDefinition(Def))
+ if (const Expr *Init = VD->getAnyInitializer())
return Visit(const_cast<Expr *>(Init));
}
@@ -813,7 +812,7 @@ public:
return false;
}
- bool VisitCallExpr(const CallExpr *E);
+ bool VisitCallExpr(CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitConditionalOperator(const ConditionalOperator *E);
@@ -849,8 +848,8 @@ public:
bool VisitUnaryImag(const UnaryOperator *E);
private:
- unsigned GetAlignOfExpr(const Expr *E);
- unsigned GetAlignOfType(QualType T);
+ CharUnits GetAlignOfExpr(const Expr *E);
+ CharUnits GetAlignOfType(QualType T);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
@@ -879,9 +878,12 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
// In C, they can also be folded, although they are not ICEs.
if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers()
== Qualifiers::Const) {
+
+ if (isa<ParmVarDecl>(D))
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- const VarDecl *Def = 0;
- if (const Expr *Init = VD->getDefinition(Def)) {
+ if (const Expr *Init = VD->getAnyInitializer()) {
if (APValue *V = VD->getEvaluatedValue()) {
if (V->isInt())
return Success(V->getInt(), E);
@@ -965,7 +967,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
return -1;
}
-bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
+bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
default:
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
@@ -1020,6 +1022,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand);
return Success(Operand, E);
}
+
+ case Builtin::BI__builtin_expect:
+ return Visit(E->getArg(0));
}
}
@@ -1288,7 +1293,7 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
}
-unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
+CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
// 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
@@ -1300,20 +1305,22 @@ unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
unsigned CharSize = Info.Ctx.Target.getCharWidth();
// __alignof is defined to return the preferred alignment.
- return Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize;
+ return CharUnits::fromQuantity(
+ Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize);
}
-unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
+CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
E = E->IgnoreParens();
// alignof decl is always accepted, even if it doesn't make sense: we default
// to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true);
+ return Info.Ctx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(),
- /*RefAsPointee*/true);
+ return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/true);
return GetAlignOfType(E->getType());
}
@@ -1325,9 +1332,9 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
// Handle alignof separately.
if (!E->isSizeOf()) {
if (E->isArgumentType())
- return Success(GetAlignOfType(E->getArgumentType()), E);
+ return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E);
else
- return Success(GetAlignOfExpr(E->getArgumentExpr()), E);
+ return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E);
}
QualType SrcTy = E->getTypeOfArgument();
diff --git a/lib/AST/Makefile b/lib/AST/Makefile
index f7d4e9f62d5f..8afc629d6b3b 100644
--- a/lib/AST/Makefile
+++ b/lib/AST/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangAST
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 0aa01801959c..50acd15fde05 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -119,11 +119,10 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
return;
}
}
- if (i->isVirtual()) {
- SelectPrimaryVBase(Base, FirstPrimary);
- if (PrimaryBase.getBase())
- return;
- }
+ assert(i->isVirtual());
+ SelectPrimaryVBase(Base, FirstPrimary);
+ if (PrimaryBase.getBase())
+ return;
}
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 104e3361892f..8347249a466b 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -35,6 +35,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
// Intialize the table on the first use.
Initialized = true;
+#define ABSTRACT_EXPR(CLASS, PARENT)
#define STMT(CLASS, PARENT) \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
@@ -132,9 +133,8 @@ Expr *AsmStmt::getOutputExpr(unsigned i) {
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
-std::string AsmStmt::getOutputConstraint(unsigned i) const {
- return std::string(Constraints[i]->getStrData(),
- Constraints[i]->getByteLength());
+llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const {
+ return getOutputConstraintLiteral(i)->getString();
}
/// getNumPlusOperands - Return the number of output operands that have a "+"
@@ -147,40 +147,52 @@ unsigned AsmStmt::getNumPlusOperands() const {
return Res;
}
-
-
Expr *AsmStmt::getInputExpr(unsigned i) {
return cast<Expr>(Exprs[i + NumOutputs]);
}
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
-std::string AsmStmt::getInputConstraint(unsigned i) const {
- return std::string(Constraints[i + NumOutputs]->getStrData(),
- Constraints[i + NumOutputs]->getByteLength());
+llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const {
+ return getInputConstraintLiteral(i)->getString();
}
-void AsmStmt::setOutputsAndInputs(unsigned NumOutputs,
- unsigned NumInputs,
- const std::string *Names,
- StringLiteral **Constraints,
- Stmt **Exprs) {
+void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
+ IdentifierInfo **Names,
+ StringLiteral **Constraints,
+ Stmt **Exprs,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ StringLiteral **Clobbers,
+ unsigned NumClobbers) {
this->NumOutputs = NumOutputs;
this->NumInputs = NumInputs;
- this->Names.clear();
- this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs);
- this->Constraints.clear();
- this->Constraints.insert(this->Constraints.end(),
- Constraints, Constraints + NumOutputs + NumInputs);
- this->Exprs.clear();
- this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs);
+ this->NumClobbers = NumClobbers;
+
+ unsigned NumExprs = NumOutputs + NumInputs;
+
+ C.Deallocate(this->Names);
+ this->Names = new (C) IdentifierInfo*[NumExprs];
+ std::copy(Names, Names + NumExprs, this->Names);
+
+ C.Deallocate(this->Exprs);
+ this->Exprs = new (C) Stmt*[NumExprs];
+ std::copy(Exprs, Exprs + NumExprs, this->Exprs);
+
+ C.Deallocate(this->Constraints);
+ this->Constraints = new (C) StringLiteral*[NumExprs];
+ std::copy(Constraints, Constraints + NumExprs, this->Constraints);
+
+ C.Deallocate(this->Clobbers);
+ this->Clobbers = new (C) StringLiteral*[NumClobbers];
+ std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers);
}
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
-int AsmStmt::getNamedOperand(const std::string &SymbolicName) const {
+int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const {
unsigned NumPlusOperands = 0;
// Check if this is an output operand.
@@ -197,11 +209,6 @@ int AsmStmt::getNamedOperand(const std::string &SymbolicName) const {
return -1;
}
-void AsmStmt::setClobbers(StringLiteral **Clobbers, unsigned NumClobbers) {
- this->Clobbers.clear();
- this->Clobbers.insert(this->Clobbers.end(), Clobbers, Clobbers + NumClobbers);
-}
-
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
@@ -313,7 +320,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
if (NameEnd == CurPtr)
return diag::err_asm_empty_symbolic_operand_name;
- std::string SymbolicName(CurPtr, NameEnd);
+ llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
int N = getNamedOperand(SymbolicName);
if (N == -1) {
@@ -332,26 +339,39 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
}
}
+QualType CXXCatchStmt::getCaughtType() const {
+ if (ExceptionDecl)
+ return ExceptionDecl->getType();
+ return QualType();
+}
+
//===----------------------------------------------------------------------===//
// Constructors
//===----------------------------------------------------------------------===//
-AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
- bool msasm, unsigned numoutputs, unsigned numinputs,
- std::string *names, StringLiteral **constraints,
+AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
+ bool isvolatile, bool msasm,
+ unsigned numoutputs, unsigned numinputs,
+ IdentifierInfo **names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc)
: Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
, IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
- , NumOutputs(numoutputs), NumInputs(numinputs) {
- for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
- Names.push_back(names[i]);
- Exprs.push_back(exprs[i]);
- Constraints.push_back(constraints[i]);
- }
+ , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) {
- for (unsigned i = 0; i != numclobbers; i++)
- Clobbers.push_back(clobbers[i]);
+ unsigned NumExprs = NumOutputs +NumInputs;
+
+ Names = new (C) IdentifierInfo*[NumExprs];
+ std::copy(names, names + NumExprs, Names);
+
+ Exprs = new (C) Stmt*[NumExprs];
+ std::copy(exprs, exprs + NumExprs, Exprs);
+
+ Constraints = new (C) StringLiteral*[NumExprs];
+ std::copy(constraints, constraints + NumExprs, Constraints);
+
+ Clobbers = new (C) StringLiteral*[NumClobbers];
+ std::copy(clobbers, clobbers + NumClobbers, Clobbers);
}
ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
@@ -387,6 +407,24 @@ ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
RParenLoc = rparenloc;
}
+CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
+ Stmt *tryBlock, Stmt **handlers,
+ unsigned numHandlers) {
+ std::size_t Size = sizeof(CXXTryStmt);
+ Size += ((numHandlers + 1) * sizeof(Stmt));
+
+ void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>());
+ return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
+}
+
+CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
+ Stmt **handlers, unsigned numHandlers)
+ : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) {
+ Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
+ Stmts[0] = tryBlock;
+ std::copy(handlers, handlers + NumHandlers, Stmts + 1);
+}
+
//===----------------------------------------------------------------------===//
// AST Destruction.
//===----------------------------------------------------------------------===//
@@ -453,6 +491,18 @@ void WhileStmt::DoDestroy(ASTContext &C) {
BranchDestroy(C, this, SubExprs, END_EXPR);
}
+void AsmStmt::DoDestroy(ASTContext &C) {
+ DestroyChildren(C);
+
+ C.Deallocate(Names);
+ C.Deallocate(Constraints);
+ C.Deallocate(Exprs);
+ C.Deallocate(Clobbers);
+
+ this->~AsmStmt();
+ C.Deallocate((void *)this);
+}
+
//===----------------------------------------------------------------------===//
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
@@ -566,10 +616,10 @@ Stmt::child_iterator ReturnStmt::child_end() {
// AsmStmt
Stmt::child_iterator AsmStmt::child_begin() {
- return Exprs.empty() ? 0 : &Exprs[0];
+ return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0];
}
Stmt::child_iterator AsmStmt::child_end() {
- return Exprs.empty() ? 0 : &Exprs[0] + Exprs.size();
+ return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs;
}
// ObjCAtCatchStmt
@@ -615,19 +665,11 @@ Stmt::child_iterator CXXCatchStmt::child_end() {
return &HandlerBlock + 1;
}
-QualType CXXCatchStmt::getCaughtType() const {
- if (ExceptionDecl)
- return ExceptionDecl->getType();
- return QualType();
-}
-
// CXXTryStmt
-Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; }
-Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); }
+Stmt::child_iterator CXXTryStmt::child_begin() {
+ return reinterpret_cast<Stmt **>(this + 1);
+}
-CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
- Stmt **handlers, unsigned numHandlers)
- : Stmt(CXXTryStmtClass), TryLoc(tryLoc) {
- Stmts.push_back(tryBlock);
- Stmts.insert(Stmts.end(), handlers, handlers + numHandlers);
+Stmt::child_iterator CXXTryStmt::child_end() {
+ return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1;
}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index ae76526b7939..ba6218be1426 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -472,6 +472,8 @@ void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
DumpExpr(Node);
+ CXXConstructorDecl *Ctor = Node->getConstructor();
+ DumpType(Ctor->getType());
if (Node->isElidable())
OS << " elidable";
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index bbb904de79b3..3ae306d3c7ac 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1038,6 +1038,10 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
PrintExpr(Node->getSubExpr());
}
+void StmtPrinter::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *Node) {
+ PrintExpr(Node->getSubExpr());
+}
+
void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
OS << Node->getType().getAsString();
OS << "(";
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b74e1ef0bab4..3a19ec212c14 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -465,6 +465,10 @@ void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) {
const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor()));
}
+void StmtProfiler::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) {
VisitExpr(S);
VisitDecl(S->getConstructor());
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index edfb580cc35f..76cc38292064 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -339,21 +339,18 @@ const RecordType *Type::getAsUnionType() const {
return 0;
}
-ObjCInterfaceType::ObjCInterfaceType(ASTContext &Ctx, QualType Canonical,
+ObjCInterfaceType::ObjCInterfaceType(QualType Canonical,
ObjCInterfaceDecl *D,
ObjCProtocolDecl **Protos, unsigned NumP) :
Type(ObjCInterface, Canonical, /*Dependent=*/false),
- Decl(D), Protocols(0), NumProtocols(NumP)
+ Decl(D), NumProtocols(NumP)
{
- if (NumProtocols) {
- Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols];
- memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols));
- }
+ if (NumProtocols)
+ memcpy(reinterpret_cast<ObjCProtocolDecl**>(this + 1), Protos,
+ NumProtocols * sizeof(*Protos));
}
void ObjCInterfaceType::Destroy(ASTContext& C) {
- if (Protocols)
- C.Deallocate(Protocols);
this->~ObjCInterfaceType();
C.Deallocate(this);
}
@@ -372,22 +369,18 @@ bool Type::isObjCQualifiedInterfaceType() const {
return getAsObjCQualifiedInterfaceType() != 0;
}
-ObjCObjectPointerType::ObjCObjectPointerType(ASTContext &Ctx,
- QualType Canonical, QualType T,
+ObjCObjectPointerType::ObjCObjectPointerType(QualType Canonical, QualType T,
ObjCProtocolDecl **Protos,
unsigned NumP) :
Type(ObjCObjectPointer, Canonical, /*Dependent=*/false),
- PointeeType(T), Protocols(NULL), NumProtocols(NumP)
+ PointeeType(T), NumProtocols(NumP)
{
- if (NumProtocols) {
- Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols];
- memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols));
- }
+ if (NumProtocols)
+ memcpy(reinterpret_cast<ObjCProtocolDecl **>(this + 1), Protos,
+ NumProtocols * sizeof(*Protos));
}
void ObjCObjectPointerType::Destroy(ASTContext& C) {
- if (Protocols)
- C.Deallocate(Protocols);
this->~ObjCObjectPointerType();
C.Deallocate(this);
}
@@ -720,6 +713,19 @@ bool Type::isPromotableIntegerType() const {
default:
return false;
}
+
+ // Enumerated types are promotable to their compatible integer types
+ // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2).
+ if (const EnumType *ET = getAs<EnumType>()){
+ if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull())
+ return false;
+
+ const BuiltinType *BT
+ = ET->getDecl()->getPromotionType()->getAs<BuiltinType>();
+ return BT->getKind() == BuiltinType::Int
+ || BT->getKind() == BuiltinType::UInt;
+ }
+
return false;
}
@@ -797,12 +803,24 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
}
}
+llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
+ switch (CC) {
+ case CC_Default: llvm_unreachable("no name for default cc");
+ default: return "";
+
+ case CC_C: return "cdecl";
+ case CC_X86StdCall: return "stdcall";
+ case CC_X86FastCall: return "fastcall";
+ }
+}
+
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool anyExceptionSpec, unsigned NumExceptions,
- exception_iterator Exs, bool NoReturn) {
+ exception_iterator Exs, bool NoReturn,
+ CallingConv CallConv) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@@ -815,16 +833,19 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
ID.AddPointer(Exs[i].getAsOpaquePtr());
}
ID.AddInteger(NoReturn);
+ ID.AddInteger(CallConv);
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
- getNumExceptions(), exception_begin(), getNoReturnAttr());
+ getNumExceptions(), exception_begin(), getNoReturnAttr(),
+ getCallConv());
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
- QualType OIT, ObjCProtocolDecl **protocols,
+ QualType OIT,
+ ObjCProtocolDecl * const *protocols,
unsigned NumProtocols) {
ID.AddPointer(OIT.getAsOpaquePtr());
for (unsigned i = 0; i != NumProtocols; i++)
@@ -832,10 +853,7 @@ void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) {
- if (getNumProtocols())
- Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols());
- else
- Profile(ID, getPointeeType(), 0, 0);
+ Profile(ID, getPointeeType(), qual_begin(), getNumProtocols());
}
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
@@ -894,8 +912,9 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
E->Profile(ID, Context, true);
}
-TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
- : Type(TC, can, D->isDependentType()), decl(D, 0) {}
+TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
+ : Type(TC, can, D->isDependentType()),
+ decl(const_cast<TagDecl*>(D), 0) {}
bool RecordType::classof(const TagType *TT) {
return isa<RecordDecl>(TT->getDecl());
@@ -1023,7 +1042,7 @@ QualType QualifierCollector::apply(const Type *T) const {
void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
const ObjCInterfaceDecl *Decl,
- ObjCProtocolDecl **protocols,
+ ObjCProtocolDecl * const *protocols,
unsigned NumProtocols) {
ID.AddPointer(Decl);
for (unsigned i = 0; i != NumProtocols; i++)
@@ -1031,8 +1050,81 @@ void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
}
void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
- if (getNumProtocols())
- Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
- else
- Profile(ID, getDecl(), 0, 0);
+ Profile(ID, getDecl(), qual_begin(), getNumProtocols());
+}
+
+Linkage Type::getLinkage() const {
+ // C++ [basic.link]p8:
+ // Names not covered by these rules have no linkage.
+ if (this != CanonicalType.getTypePtr())
+ return CanonicalType->getLinkage();
+
+ return NoLinkage;
+}
+
+Linkage BuiltinType::getLinkage() const {
+ // C++ [basic.link]p8:
+ // A type is said to have linkage if and only if:
+ // - it is a fundamental type (3.9.1); or
+ return ExternalLinkage;
+}
+
+Linkage TagType::getLinkage() const {
+ // C++ [basic.link]p8:
+ // - it is a class or enumeration type that is named (or has a name for
+ // linkage purposes (7.1.3)) and the name has linkage; or
+ // - it is a specialization of a class template (14); or
+ return getDecl()->getLinkage();
+}
+
+// C++ [basic.link]p8:
+// - it is a compound type (3.9.2) other than a class or enumeration,
+// compounded exclusively from types that have linkage; or
+Linkage ComplexType::getLinkage() const {
+ return ElementType->getLinkage();
+}
+
+Linkage PointerType::getLinkage() const {
+ return PointeeType->getLinkage();
+}
+
+Linkage BlockPointerType::getLinkage() const {
+ return PointeeType->getLinkage();
+}
+
+Linkage ReferenceType::getLinkage() const {
+ return PointeeType->getLinkage();
+}
+
+Linkage MemberPointerType::getLinkage() const {
+ return minLinkage(Class->getLinkage(), PointeeType->getLinkage());
+}
+
+Linkage ArrayType::getLinkage() const {
+ return ElementType->getLinkage();
+}
+
+Linkage VectorType::getLinkage() const {
+ return ElementType->getLinkage();
+}
+
+Linkage FunctionNoProtoType::getLinkage() const {
+ return getResultType()->getLinkage();
+}
+
+Linkage FunctionProtoType::getLinkage() const {
+ Linkage L = getResultType()->getLinkage();
+ for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end();
+ A != AEnd; ++A)
+ L = minLinkage(L, (*A)->getLinkage());
+
+ return L;
+}
+
+Linkage ObjCInterfaceType::getLinkage() const {
+ return ExternalLinkage;
+}
+
+Linkage ObjCObjectPointerType::getLinkage() const {
+ return ExternalLinkage;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 00b74bc21a14..5b621cf7280d 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -225,15 +225,24 @@ void TypePrinter::PrintDependentSizedExtVector(
}
void TypePrinter::PrintVector(const VectorType *T, std::string &S) {
- // FIXME: We prefer to print the size directly here, but have no way
- // to get the size of the type.
- Print(T->getElementType(), S);
- std::string V = "__attribute__((__vector_size__(";
- V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
- std::string ET;
- Print(T->getElementType(), ET);
- V += " * sizeof(" + ET + ")))) ";
- S = V + S;
+ if (T->isAltiVec()) {
+ if (T->isPixel())
+ S = "__vector __pixel " + S;
+ else {
+ Print(T->getElementType(), S);
+ S = "__vector " + S;
+ }
+ } else {
+ // FIXME: We prefer to print the size directly here, but have no way
+ // to get the size of the type.
+ Print(T->getElementType(), S);
+ std::string V = "__attribute__((__vector_size__(";
+ V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
+ std::string ET;
+ Print(T->getElementType(), ET);
+ V += " * sizeof(" + ET + ")))) ";
+ S = V + S;
+ }
}
void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) {
@@ -271,6 +280,19 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
+ switch(T->getCallConv()) {
+ case CC_Default:
+ default: break;
+ case CC_C:
+ S += " __attribute__((cdecl))";
+ break;
+ case CC_X86StdCall:
+ S += " __attribute__((stdcall))";
+ break;
+ case CC_X86FastCall:
+ S += " __attribute__((fastcall))";
+ break;
+ }
if (T->getNoReturnAttr())
S += " __attribute__((noreturn))";
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index ad9f6dd19413..ccd5088f2ec7 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -12,10 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -87,12 +86,6 @@ AnalysisContext *AnalysisContextManager::getContext(const Decl *D) {
return AC;
}
-const BlockDecl *BlockInvocationContext::getBlockDecl() const {
- return Data.is<const BlockDataRegion*>() ?
- Data.get<const BlockDataRegion*>()->getDecl()
- : Data.get<const BlockDecl*>();
-}
-
//===----------------------------------------------------------------------===//
// FoldingSet profiling.
//===----------------------------------------------------------------------===//
@@ -117,11 +110,7 @@ void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
}
void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
- if (const BlockDataRegion *BR = getBlockRegion())
- Profile(ID, getAnalysisContext(), getParent(), BR);
- else
- Profile(ID, getAnalysisContext(), getParent(),
- Data.get<const BlockDecl*>());
+ Profile(ID, getAnalysisContext(), getParent(), BD);
}
//===----------------------------------------------------------------------===//
@@ -170,15 +159,6 @@ LocationContextManager::getScope(AnalysisContext *ctx,
return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
}
-const BlockInvocationContext *
-LocationContextManager::getBlockInvocation(AnalysisContext *ctx,
- const LocationContext *parent,
- const BlockDataRegion *BR) {
- return getLocationContext<BlockInvocationContext, BlockDataRegion>(ctx,
- parent,
- BR);
-}
-
//===----------------------------------------------------------------------===//
// LocationContext methods.
//===----------------------------------------------------------------------===//
@@ -214,6 +194,7 @@ namespace {
class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{
BumpVector<const VarDecl*> &BEVals;
BumpVectorContext &BC;
+ llvm::DenseMap<const VarDecl*, unsigned> Visited;
public:
FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals,
BumpVectorContext &bc)
@@ -224,10 +205,27 @@ public:
if (Stmt *child = *I)
Visit(child);
}
+
+ void VisitDeclRefExpr(const DeclRefExpr *DR) {
+ // Non-local variables are also directly modified.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ if (!VD->hasLocalStorage()) {
+ unsigned &flag = Visited[VD];
+ if (!flag) {
+ flag = 1;
+ BEVals.push_back(VD, BC);
+ }
+ }
+ }
void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
- BEVals.push_back(VD, BC);
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ unsigned &flag = Visited[VD];
+ if (!flag) {
+ flag = 1;
+ BEVals.push_back(VD, BC);
+ }
+ }
}
};
} // end anonymous namespace
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 521f1be6ec8b..4f8259e44939 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -2,67 +2,10 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangAnalysis
AnalysisContext.cpp
- ArrayBoundChecker.cpp
- AttrNonNullChecker.cpp
- BasicConstraintManager.cpp
- BasicObjCFoundationChecks.cpp
- BasicStore.cpp
- BasicValueFactory.cpp
- BugReporter.cpp
- BugReporterVisitors.cpp
- BuiltinFunctionChecker.cpp
CFG.cpp
- CFRefCount.cpp
- CallAndMessageChecker.cpp
- CallInliner.cpp
- CastToStructChecker.cpp
- CheckDeadStores.cpp
- CheckObjCDealloc.cpp
- CheckObjCInstMethSignature.cpp
- CheckObjCUnusedIVars.cpp
- CheckSecuritySyntaxOnly.cpp
- CheckSizeofPointer.cpp
- Checker.cpp
- DereferenceChecker.cpp
- DivZeroChecker.cpp
- Environment.cpp
- ExplodedGraph.cpp
- FixedAddressChecker.cpp
- GRBlockCounter.cpp
- GRCoreEngine.cpp
- GRExprEngine.cpp
- GRExprEngineExperimentalChecks.cpp
- GRState.cpp
LiveVariables.cpp
- MallocChecker.cpp
- ManagerRegistry.cpp
- MemRegion.cpp
- NoReturnFunctionChecker.cpp
- NSAutoreleasePoolChecker.cpp
- NSErrorChecker.cpp
- OSAtomicChecker.cpp
- PathDiagnostic.cpp
- PointerArithChecker.cpp
- PointerSubChecker.cpp
- PthreadLockChecker.cpp
- RangeConstraintManager.cpp
- RegionStore.cpp
- ReturnPointerRangeChecker.cpp
- ReturnStackAddressChecker.cpp
- ReturnUndefChecker.cpp
- SVals.cpp
- SValuator.cpp
- SimpleConstraintManager.cpp
- SimpleSValuator.cpp
- Store.cpp
- SymbolManager.cpp
- UndefBranchChecker.cpp
- UndefResultChecker.cpp
- UndefinedArraySubscriptChecker.cpp
- UndefinedAssignmentChecker.cpp
+ PrintfFormatString.cpp
UninitializedValues.cpp
- VLASizeChecker.cpp
- ValueManager.cpp
)
add_dependencies(clangAnalysis ClangDiagnosticAnalysis)
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 0b2620e609c2..94ed75286dee 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -19,7 +19,7 @@
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Analysis/Makefile b/lib/Analysis/Makefile
index c597254fd2d7..d6411122e322 100644
--- a/lib/Analysis/Makefile
+++ b/lib/Analysis/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangAnalysis
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
new file mode 100644
index 000000000000..55abd1077150
--- /dev/null
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -0,0 +1,436 @@
+//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handling of format string in printf and friends. The structure of format
+// strings for fprintf() are described in C99 7.19.6.1.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/PrintfFormatString.h"
+#include "clang/AST/ASTContext.h"
+
+using clang::analyze_printf::FormatSpecifier;
+using clang::analyze_printf::OptionalAmount;
+using clang::analyze_printf::ArgTypeResult;
+using clang::analyze_printf::FormatStringHandler;
+using namespace clang;
+
+namespace {
+class FormatSpecifierResult {
+ FormatSpecifier FS;
+ const char *Start;
+ bool Stop;
+public:
+ FormatSpecifierResult(bool stop = false)
+ : Start(0), Stop(stop) {}
+ FormatSpecifierResult(const char *start,
+ const FormatSpecifier &fs)
+ : FS(fs), Start(start), Stop(false) {}
+
+
+ const char *getStart() const { return Start; }
+ bool shouldStop() const { return Stop; }
+ bool hasValue() const { return Start != 0; }
+ const FormatSpecifier &getValue() const {
+ assert(hasValue());
+ return FS;
+ }
+ const FormatSpecifier &getValue() { return FS; }
+};
+} // end anonymous namespace
+
+template <typename T>
+class UpdateOnReturn {
+ T &ValueToUpdate;
+ const T &ValueToCopy;
+public:
+ UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
+ : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
+
+ ~UpdateOnReturn() {
+ ValueToUpdate = ValueToCopy;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Methods for parsing format strings.
+//===----------------------------------------------------------------------===//
+
+static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
+ const char *I = Beg;
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+ bool foundDigits = false;
+ unsigned accumulator = 0;
+
+ for ( ; I != E; ++I) {
+ char c = *I;
+ if (c >= '0' && c <= '9') {
+ foundDigits = true;
+ accumulator += (accumulator * 10) + (c - '0');
+ continue;
+ }
+
+ if (foundDigits)
+ return OptionalAmount(accumulator, Beg);
+
+ if (c == '*') {
+ ++I;
+ return OptionalAmount(OptionalAmount::Arg, Beg);
+ }
+
+ break;
+ }
+
+ return OptionalAmount();
+}
+
+static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
+ const char *&Beg,
+ const char *E) {
+
+ using namespace clang::analyze_printf;
+
+ const char *I = Beg;
+ const char *Start = 0;
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+ // Look for a '%' character that indicates the start of a format specifier.
+ for ( ; I != E ; ++I) {
+ char c = *I;
+ if (c == '\0') {
+ // Detect spurious null characters, which are likely errors.
+ H.HandleNullChar(I);
+ return true;
+ }
+ if (c == '%') {
+ Start = I++; // Record the start of the format specifier.
+ break;
+ }
+ }
+
+ // No format specifier found?
+ if (!Start)
+ return false;
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ FormatSpecifier FS;
+
+ // Look for flags (if any).
+ bool hasMore = true;
+ for ( ; I != E; ++I) {
+ switch (*I) {
+ default: hasMore = false; break;
+ case '-': FS.setIsLeftJustified(); break;
+ case '+': FS.setHasPlusPrefix(); break;
+ case ' ': FS.setHasSpacePrefix(); break;
+ case '#': FS.setHasAlternativeForm(); break;
+ case '0': FS.setHasLeadingZeros(); break;
+ }
+ if (!hasMore)
+ break;
+ }
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ // Look for the field width (if any).
+ FS.setFieldWidth(ParseAmount(I, E));
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ // Look for the precision (if any).
+ if (*I == '.') {
+ ++I;
+ if (I == E) {
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ FS.setPrecision(ParseAmount(I, E));
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+ }
+
+ // Look for the length modifier.
+ LengthModifier lm = None;
+ switch (*I) {
+ default:
+ break;
+ case 'h':
+ ++I;
+ lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
+ break;
+ case 'l':
+ ++I;
+ lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
+ break;
+ case 'j': lm = AsIntMax; ++I; break;
+ case 'z': lm = AsSizeT; ++I; break;
+ case 't': lm = AsPtrDiff; ++I; break;
+ case 'L': lm = AsLongDouble; ++I; break;
+ case 'q': lm = AsLongLong; ++I; break;
+ }
+ FS.setLengthModifier(lm);
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ if (*I == '\0') {
+ // Detect spurious null characters, which are likely errors.
+ H.HandleNullChar(I);
+ return true;
+ }
+
+ // Finally, look for the conversion specifier.
+ const char *conversionPosition = I++;
+ ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
+ switch (*conversionPosition) {
+ default:
+ break;
+ // C99: 7.19.6.1 (section 8).
+ case 'd': k = ConversionSpecifier::dArg; break;
+ case 'i': k = ConversionSpecifier::iArg; break;
+ case 'o': k = ConversionSpecifier::oArg; break;
+ case 'u': k = ConversionSpecifier::uArg; break;
+ case 'x': k = ConversionSpecifier::xArg; break;
+ case 'X': k = ConversionSpecifier::XArg; break;
+ case 'f': k = ConversionSpecifier::fArg; break;
+ case 'F': k = ConversionSpecifier::FArg; break;
+ case 'e': k = ConversionSpecifier::eArg; break;
+ case 'E': k = ConversionSpecifier::EArg; break;
+ case 'g': k = ConversionSpecifier::gArg; break;
+ case 'G': k = ConversionSpecifier::GArg; break;
+ case 'a': k = ConversionSpecifier::aArg; break;
+ case 'A': k = ConversionSpecifier::AArg; break;
+ case 'c': k = ConversionSpecifier::IntAsCharArg; break;
+ case 's': k = ConversionSpecifier::CStrArg; break;
+ case 'p': k = ConversionSpecifier::VoidPtrArg; break;
+ case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
+ case '%': k = ConversionSpecifier::PercentArg; break;
+ // Objective-C.
+ case '@': k = ConversionSpecifier::ObjCObjArg; break;
+ // Glibc specific.
+ case 'm': k = ConversionSpecifier::PrintErrno; break;
+ }
+ FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k));
+
+ if (k == ConversionSpecifier::InvalidSpecifier) {
+ H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
+ return false; // Keep processing format specifiers.
+ }
+ return FormatSpecifierResult(Start, FS);
+}
+
+bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
+ const char *I, const char *E) {
+ // Keep looking for a format specifier until we have exhausted the string.
+ while (I != E) {
+ const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E);
+ // Did a fail-stop error of any kind occur when parsing the specifier?
+ // If so, don't do any more processing.
+ if (FSR.shouldStop())
+ return true;;
+ // Did we exhaust the string or encounter an error that
+ // we can recover from?
+ if (!FSR.hasValue())
+ continue;
+ // We have a format specifier. Pass it to the callback.
+ if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
+ I - FSR.getStart()))
+ return true;
+ }
+ assert(I == E && "Format string not exhausted");
+ return false;
+}
+
+FormatStringHandler::~FormatStringHandler() {}
+
+//===----------------------------------------------------------------------===//
+// Methods on ArgTypeResult.
+//===----------------------------------------------------------------------===//
+
+bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
+ assert(isValid());
+
+ if (K == UnknownTy)
+ return true;
+
+ if (K == SpecificTy) {
+ argTy = C.getCanonicalType(argTy).getUnqualifiedType();
+
+ if (T == argTy)
+ return true;
+
+ if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ default:
+ break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return T == C.UnsignedCharTy;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ return T == C.SignedCharTy;
+ case BuiltinType::Short:
+ return T == C.UnsignedShortTy;
+ case BuiltinType::UShort:
+ return T == C.ShortTy;
+ case BuiltinType::Int:
+ return T == C.UnsignedIntTy;
+ case BuiltinType::UInt:
+ return T == C.IntTy;
+ case BuiltinType::Long:
+ return T == C.UnsignedLongTy;
+ case BuiltinType::ULong:
+ return T == C.LongTy;
+ case BuiltinType::LongLong:
+ return T == C.UnsignedLongLongTy;
+ case BuiltinType::ULongLong:
+ return T == C.LongLongTy;
+ }
+
+ return false;
+ }
+
+ if (K == CStrTy) {
+ const PointerType *PT = argTy->getAs<PointerType>();
+ if (!PT)
+ return false;
+
+ QualType pointeeTy = PT->getPointeeType();
+
+ if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Void:
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ if (K == WCStrTy) {
+ const PointerType *PT = argTy->getAs<PointerType>();
+ if (!PT)
+ return false;
+
+ QualType pointeeTy = PT->getPointeeType();
+ return pointeeTy == C.WCharTy;
+ }
+
+ return false;
+}
+
+QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
+ assert(isValid());
+ if (K == SpecificTy)
+ return T;
+ if (K == CStrTy)
+ return C.getPointerType(C.CharTy);
+ if (K == WCStrTy)
+ return C.getPointerType(C.WCharTy);
+ if (K == ObjCPointerTy)
+ return C.ObjCBuiltinIdTy;
+
+ return QualType();
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on OptionalAmount.
+//===----------------------------------------------------------------------===//
+
+ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
+ return Ctx.IntTy;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on FormatSpecifier.
+//===----------------------------------------------------------------------===//
+
+ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
+ if (!CS.consumesDataArgument())
+ return ArgTypeResult::Invalid();
+
+ if (CS.isIntArg())
+ switch (LM) {
+ case AsLongDouble:
+ return ArgTypeResult::Invalid();
+ case None: return Ctx.IntTy;
+ case AsChar: return Ctx.SignedCharTy;
+ case AsShort: return Ctx.ShortTy;
+ case AsLong: return Ctx.LongTy;
+ case AsLongLong: return Ctx.LongLongTy;
+ case AsIntMax:
+ // FIXME: Return unknown for now.
+ return ArgTypeResult();
+ case AsSizeT: return Ctx.getSizeType();
+ case AsPtrDiff: return Ctx.getPointerDiffType();
+ }
+
+ if (CS.isUIntArg())
+ switch (LM) {
+ case AsLongDouble:
+ return ArgTypeResult::Invalid();
+ case None: return Ctx.UnsignedIntTy;
+ case AsChar: return Ctx.UnsignedCharTy;
+ case AsShort: return Ctx.UnsignedShortTy;
+ case AsLong: return Ctx.UnsignedLongTy;
+ case AsLongLong: return Ctx.UnsignedLongLongTy;
+ case AsIntMax:
+ // FIXME: Return unknown for now.
+ return ArgTypeResult();
+ case AsSizeT:
+ // FIXME: How to get the corresponding unsigned
+ // version of size_t?
+ return ArgTypeResult();
+ case AsPtrDiff:
+ // FIXME: How to get the corresponding unsigned
+ // version of ptrdiff_t?
+ return ArgTypeResult();
+ }
+
+ if (CS.isDoubleArg()) {
+ if (LM == AsLongDouble)
+ return Ctx.LongDoubleTy;
+ return Ctx.DoubleTy;
+ }
+
+ if (CS.getKind() == ConversionSpecifier::CStrArg)
+ return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy
+ : ArgTypeResult::CStrTy);
+
+ // FIXME: Handle other cases.
+ return ArgTypeResult();
+}
+
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
deleted file mode 100644
index 4d7e8ade98f7..000000000000
--- a/lib/Analysis/ReturnStackAddressChecker.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-//== ReturnStackAddressChecker.cpp ------------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines ReturnStackAddressChecker, which is a path-sensitive
-// check which looks for the addresses of stack variables being returned to
-// callers.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
-
-using namespace clang;
-
-namespace {
-class ReturnStackAddressChecker :
- public CheckerVisitor<ReturnStackAddressChecker> {
- BuiltinBug *BT;
-public:
- ReturnStackAddressChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
-};
-}
-
-void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new ReturnStackAddressChecker());
-}
-
-void *ReturnStackAddressChecker::getTag() {
- static int x = 0; return &x;
-}
-
-void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
-
- const Expr *RetE = RS->getRetValue();
- if (!RetE)
- return;
-
- SVal V = C.getState()->getSVal(RetE);
- const MemRegion *R = V.getAsRegion();
-
- if (!R || !R->hasStackStorage())
- return;
-
- ExplodedNode *N = C.GenerateSink();
-
- if (!N)
- return;
-
- if (!BT)
- BT = new BuiltinBug("Return of address to stack-allocated memory");
-
- // Generate a report for this bug.
- llvm::SmallString<100> buf;
- llvm::raw_svector_ostream os(buf);
- SourceRange range;
-
- // Get the base region, stripping away fields and elements.
- R = R->getBaseRegion();
-
- // Check if the region is a compound literal.
- if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
- const CompoundLiteralExpr* CL = CR->getLiteralExpr();
- os << "Address of stack memory associated with a compound literal "
- "declared on line "
- << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart())
- << " returned to caller";
- range = CL->getSourceRange();
- }
- else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
- const Expr* ARE = AR->getExpr();
- SourceLocation L = ARE->getLocStart();
- range = ARE->getSourceRange();
- os << "Address of stack memory allocated by call to alloca() on line "
- << C.getSourceManager().getInstantiationLineNumber(L)
- << " returned to caller";
- }
- else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
- const BlockDecl *BD = BR->getCodeRegion()->getDecl();
- SourceLocation L = BD->getLocStart();
- range = BD->getSourceRange();
- os << "Address of stack-allocated block declared on line "
- << C.getSourceManager().getInstantiationLineNumber(L)
- << " returned to caller";
- }
- else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Address of stack memory associated with local variable '"
- << VR->getString() << "' returned";
- range = VR->getDecl()->getSourceRange();
- }
- else {
- assert(false && "Invalid region in ReturnStackAddressChecker.");
- return;
- }
-
- RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(RetE->getSourceRange());
- if (range.isValid())
- report->addRange(range);
-
- C.EmitReport(report);
-}
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 6fa4b539dc40..bdc0e7c621f7 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -13,7 +13,6 @@
#include "clang/Analysis/Analyses/UninitializedValues.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Analysis/LocalCheckers.h"
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index abbf6f9b6e41..094f7760a8ec 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -21,8 +21,10 @@
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -385,6 +387,123 @@ Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const {
return Result;
}
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+ unsigned &Value) {
+ if (Memory + sizeof(unsigned) > MemoryEnd)
+ return true;
+
+ memmove(&Value, Memory, sizeof(unsigned));
+ Memory += sizeof(unsigned);
+ return false;
+}
+
+static bool ReadSourceLocation(FileManager &FM, SourceManager &SM,
+ const char *&Memory, const char *MemoryEnd,
+ SourceLocation &Location) {
+ // Read the filename.
+ unsigned FileNameLen = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) ||
+ Memory + FileNameLen > MemoryEnd)
+ return true;
+
+ llvm::StringRef FileName(Memory, FileNameLen);
+ Memory += FileNameLen;
+
+ // Read the line, column.
+ unsigned Line = 0, Column = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, Line) ||
+ ReadUnsigned(Memory, MemoryEnd, Column))
+ return true;
+
+ if (FileName.empty()) {
+ Location = SourceLocation();
+ return false;
+ }
+
+ const FileEntry *File = FM.getFile(FileName);
+ if (!File)
+ return true;
+
+ // Make sure that this file has an entry in the source manager.
+ if (!SM.hasFileInfo(File))
+ SM.createFileID(File, SourceLocation(), SrcMgr::C_User);
+
+ Location = SM.getLocation(File, Line, Column);
+ return false;
+}
+
+DiagnosticBuilder Diagnostic::Deserialize(FileManager &FM, SourceManager &SM,
+ const char *&Memory,
+ const char *MemoryEnd) {
+ if (Memory == MemoryEnd)
+ return DiagnosticBuilder(0);
+
+ // Read the severity level.
+ unsigned Level = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Fatal)
+ return DiagnosticBuilder(0);
+
+ // Read the source location.
+ SourceLocation Location;
+ if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location))
+ return DiagnosticBuilder(0);
+
+ // Read the diagnostic text.
+ if (Memory == MemoryEnd)
+ return DiagnosticBuilder(0);
+
+ unsigned MessageLen = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, MessageLen) ||
+ Memory + MessageLen > MemoryEnd)
+ return DiagnosticBuilder(0);
+
+ llvm::StringRef Message(Memory, MessageLen);
+ Memory += MessageLen;
+
+ // At this point, we have enough information to form a diagnostic. Do so.
+ unsigned DiagID = getCustomDiagID((enum Level)Level, Message);
+ DiagnosticBuilder DB = Report(FullSourceLoc(Location, SM), DiagID);
+ if (Memory == MemoryEnd)
+ return DB;
+
+ // Read the source ranges.
+ unsigned NumSourceRanges = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges))
+ return DB;
+ for (unsigned I = 0; I != NumSourceRanges; ++I) {
+ SourceLocation Begin, End;
+ if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) ||
+ ReadSourceLocation(FM, SM, Memory, MemoryEnd, End))
+ return DB;
+
+ DB << SourceRange(Begin, End);
+ }
+
+ // Read the fix-it hints.
+ unsigned NumFixIts = 0;
+ if (ReadUnsigned(Memory, MemoryEnd, NumFixIts))
+ return DB;
+ for (unsigned I = 0; I != NumFixIts; ++I) {
+ SourceLocation RemoveBegin, RemoveEnd, InsertionLoc;
+ unsigned InsertLen = 0;
+ if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) ||
+ ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) ||
+ ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) ||
+ ReadUnsigned(Memory, MemoryEnd, InsertLen) ||
+ Memory + InsertLen > MemoryEnd)
+ return DB;
+
+ CodeModificationHint Hint;
+ Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
+ Hint.InsertionLoc = InsertionLoc;
+ Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
+ Memory += InsertLen;
+ DB << Hint;
+ }
+
+ return DB;
+}
+
struct WarningOption {
const char *Name;
const short *Members;
@@ -510,7 +629,7 @@ bool Diagnostic::ProcessDiag() {
// it.
if (SuppressSystemWarnings && !ShouldEmitInSystemHeader &&
Info.getLocation().isValid() &&
- Info.getLocation().getSpellingLoc().isInSystemHeader() &&
+ Info.getLocation().getInstantiationLoc().isInSystemHeader() &&
(DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) {
LastDiagLevel = Diagnostic::Ignored;
return false;
@@ -917,6 +1036,104 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
}
+static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
+ OS.write((const char *)&Value, sizeof(unsigned));
+}
+
+static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) {
+ WriteUnsigned(OS, String.size());
+ OS.write(String.data(), String.size());
+}
+
+static void WriteSourceLocation(llvm::raw_ostream &OS,
+ SourceManager *SM,
+ SourceLocation Location) {
+ if (!SM || Location.isInvalid()) {
+ // If we don't have a source manager or this location is invalid,
+ // just write an invalid location.
+ WriteUnsigned(OS, 0);
+ WriteUnsigned(OS, 0);
+ WriteUnsigned(OS, 0);
+ return;
+ }
+
+ Location = SM->getInstantiationLoc(Location);
+ std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location);
+
+ WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName());
+ WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second));
+ WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
+}
+
+void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel,
+ llvm::raw_ostream &OS) const {
+ SourceManager *SM = 0;
+ if (getLocation().isValid())
+ SM = &const_cast<SourceManager &>(getLocation().getManager());
+
+ // Write the diagnostic level and location.
+ WriteUnsigned(OS, (unsigned)DiagLevel);
+ WriteSourceLocation(OS, SM, getLocation());
+
+ // Write the diagnostic message.
+ llvm::SmallString<64> Message;
+ FormatDiagnostic(Message);
+ WriteString(OS, Message);
+
+ // Count the number of ranges that don't point into macros, since
+ // only simple file ranges serialize well.
+ unsigned NumNonMacroRanges = 0;
+ for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
+ SourceRange R = getRange(I);
+ if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
+ continue;
+
+ ++NumNonMacroRanges;
+ }
+
+ // Write the ranges.
+ WriteUnsigned(OS, NumNonMacroRanges);
+ if (NumNonMacroRanges) {
+ for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
+ SourceRange R = getRange(I);
+ if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
+ continue;
+
+ WriteSourceLocation(OS, SM, R.getBegin());
+ WriteSourceLocation(OS, SM, R.getEnd());
+ }
+ }
+
+ // Determine if all of the fix-its involve rewrites with simple file
+ // locations (not in macro instantiations). If so, we can write
+ // fix-it information.
+ unsigned NumFixIts = getNumCodeModificationHints();
+ for (unsigned I = 0; I != NumFixIts; ++I) {
+ const CodeModificationHint &Hint = getCodeModificationHint(I);
+ if (Hint.RemoveRange.isValid() &&
+ (Hint.RemoveRange.getBegin().isMacroID() ||
+ Hint.RemoveRange.getEnd().isMacroID())) {
+ NumFixIts = 0;
+ break;
+ }
+
+ if (Hint.InsertionLoc.isValid() && Hint.InsertionLoc.isMacroID()) {
+ NumFixIts = 0;
+ break;
+ }
+ }
+
+ // Write the fix-its.
+ WriteUnsigned(OS, NumFixIts);
+ for (unsigned I = 0; I != NumFixIts; ++I) {
+ const CodeModificationHint &Hint = getCodeModificationHint(I);
+ WriteSourceLocation(OS, SM, Hint.RemoveRange.getBegin());
+ WriteSourceLocation(OS, SM, Hint.RemoveRange.getEnd());
+ WriteSourceLocation(OS, SM, Hint.InsertionLoc);
+ WriteString(OS, Hint.CodeToInsert);
+ }
+}
+
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticClient should be included in the number of diagnostics
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 401e6cba0692..16a61b7156fa 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -68,7 +68,8 @@ namespace {
KEYCXX0X = 8,
KEYGNU = 16,
KEYMS = 32,
- BOOLSUPPORT = 64
+ BOOLSUPPORT = 64,
+ KEYALTIVEC = 128
};
}
@@ -91,6 +92,7 @@ static void AddKeyword(const char *Keyword, unsigned KWLen,
else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
+ else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile
index f7335789384f..58ac7eb86e75 100644
--- a/lib/Basic/Makefile
+++ b/lib/Basic/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangBasic
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
ifdef CLANG_VENDOR
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 354bf7befbb3..b91671ad17b1 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -560,10 +560,14 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const {
SourceLocation SourceManager::
getInstantiationLocSlowCase(SourceLocation Loc) const {
do {
- std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc);
- Loc = getSLocEntry(LocInfo.first).getInstantiation()
+ // Note: If Loc indicates an offset into a token that came from a macro
+ // expansion (e.g. the 5th character of the token) we do not want to add
+ // this offset when going to the instantiation location. The instatiation
+ // location is the macro invocation, which the offset has nothing to do
+ // with. This is unlike when we get the spelling loc, because the offset
+ // directly correspond to the token whose spelling we're inspecting.
+ Loc = getSLocEntry(getFileID(Loc)).getInstantiation()
.getInstantiationLocStart();
- Loc = Loc.getFileLocWithOffset(LocInfo.second);
} while (!Loc.isFileID());
return Loc;
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 493beeea6dc5..136089fe90c2 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -150,39 +150,41 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
//===----------------------------------------------------------------------===//
-static void removeGCCRegisterPrefix(const char *&Name) {
+static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) {
if (Name[0] == '%' || Name[0] == '#')
- Name++;
+ Name = Name.substr(1);
+
+ return Name;
}
/// isValidGCCRegisterName - Returns whether the passed in string
/// is a valid register name according to GCC. This is used by Sema for
/// inline asm statements.
-bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
+bool TargetInfo::isValidGCCRegisterName(llvm::StringRef Name) const {
+ if (Name.empty())
+ return false;
+
const char * const *Names;
unsigned NumNames;
// Get rid of any register prefix.
- removeGCCRegisterPrefix(Name);
+ Name = removeGCCRegisterPrefix(Name);
-
- if (strcmp(Name, "memory") == 0 ||
- strcmp(Name, "cc") == 0)
+ if (Name == "memory" || Name == "cc")
return true;
getGCCRegNames(Names, NumNames);
// If we have a number it maps to an entry in the register name array.
if (isdigit(Name[0])) {
- char *End;
- int n = (int)strtol(Name, &End, 0);
- if (*End == 0)
+ int n;
+ if (!Name.getAsInteger(0, n))
return n >= 0 && (unsigned)n < NumNames;
}
// Check register names.
for (unsigned i = 0; i < NumNames; i++) {
- if (strcmp(Name, Names[i]) == 0)
+ if (Name == Names[i])
return true;
}
@@ -195,7 +197,7 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
if (!Aliases[i].Aliases[j])
break;
- if (strcmp(Aliases[i].Aliases[j], Name) == 0)
+ if (Aliases[i].Aliases[j] == Name)
return true;
}
}
@@ -203,10 +205,12 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
return false;
}
-const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
+llvm::StringRef
+TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const {
assert(isValidGCCRegisterName(Name) && "Invalid register passed in");
- removeGCCRegisterPrefix(Name);
+ // Get rid of any register prefix.
+ Name = removeGCCRegisterPrefix(Name);
const char * const *Names;
unsigned NumNames;
@@ -215,9 +219,8 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
// First, check if we have a number.
if (isdigit(Name[0])) {
- char *End;
- int n = (int)strtol(Name, &End, 0);
- if (*End == 0) {
+ int n;
+ if (!Name.getAsInteger(0, n)) {
assert(n >= 0 && (unsigned)n < NumNames &&
"Out of bounds register number!");
return Names[n];
@@ -233,7 +236,7 @@ const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const {
for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
if (!Aliases[i].Aliases[j])
break;
- if (strcmp(Aliases[i].Aliases[j], Name) == 0)
+ if (Aliases[i].Aliases[j] == Name)
return Aliases[i].Register;
}
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index ea076ae0bbfc..c1cd96e361ed 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -74,7 +74,8 @@ public:
} // end anonymous namespace
-static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) {
+static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
+ const llvm::Triple &Triple) {
Builder.defineMacro("__APPLE_CC__", "5621");
Builder.defineMacro("__APPLE__");
Builder.defineMacro("__MACH__");
@@ -96,51 +97,45 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) {
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
-}
-
-static void getDarwinOSXDefines(MacroBuilder &Builder,
- const llvm::Triple &Triple) {
- if (Triple.getOS() != llvm::Triple::Darwin)
- return;
-
- // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5.
- unsigned Maj, Min, Rev;
- Triple.getDarwinNumber(Maj, Min, Rev);
-
- char MacOSXStr[] = "1000";
- if (Maj >= 4 && Maj <= 13) { // 10.0-10.9
- // darwin7 -> 1030, darwin8 -> 1040, darwin9 -> 1050, etc.
- MacOSXStr[2] = '0' + Maj-4;
- }
-
- // Handle minor version: 10.4.9 -> darwin8.9 -> "1049"
- // Cap 10.4.11 -> darwin8.11 -> "1049"
- MacOSXStr[3] = std::min(Min, 9U)+'0';
- Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__",
- MacOSXStr);
-}
-
-static void getDarwinIPhoneOSDefines(MacroBuilder &Builder,
- const llvm::Triple &Triple) {
- if (Triple.getOS() != llvm::Triple::Darwin)
- return;
- // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5.
+ // Get the OS version number from the triple.
unsigned Maj, Min, Rev;
- Triple.getDarwinNumber(Maj, Min, Rev);
- // When targetting iPhone OS, interpret the minor version and
- // revision as the iPhone OS version
- char iPhoneOSStr[] = "10000";
- if (Min >= 2 && Min <= 9) { // iPhone OS 2.0-9.0
- // darwin9.2.0 -> 20000, darwin9.3.0 -> 30000, etc.
- iPhoneOSStr[0] = '0' + Min;
+ // If no version was given, default to to 10.4.0, for simplifying tests.
+ if (Triple.getOSName() == "darwin") {
+ Min = Rev = 0;
+ Maj = 8;
+ } else
+ Triple.getDarwinNumber(Maj, Min, Rev);
+
+ // Set the appropriate OS version define.
+ if (Triple.getEnvironmentName() == "iphoneos") {
+ assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!");
+ char Str[6];
+ Str[0] = '0' + Maj;
+ Str[1] = '0' + (Min / 10);
+ Str[2] = '0' + (Min % 10);
+ Str[3] = '0' + (Rev / 10);
+ Str[4] = '0' + (Rev % 10);
+ Str[5] = '\0';
+ Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str);
+ } else {
+ // 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;
+
+ assert(Triple.getEnvironmentName().empty() && "Invalid environment!");
+ assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!");
+ char Str[5];
+ Str[0] = '0' + (Maj / 10);
+ Str[1] = '0' + (Maj % 10);
+ Str[2] = '0' + Min;
+ Str[3] = '0' + Rev;
+ Str[4] = '\0';
+ Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
}
-
- // Handle minor version: 2.2 -> darwin9.2.2 -> 20200
- iPhoneOSStr[2] = std::min(Rev, 9U)+'0';
- Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
- iPhoneOSStr);
}
namespace {
@@ -149,8 +144,7 @@ class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts);
- getDarwinOSXDefines(Builder, Triple);
+ getDarwinDefines(Builder, Opts, Triple);
}
public:
@@ -159,11 +153,7 @@ public:
this->TLSSupported = false;
}
- virtual const char *getUnicodeStringSection() const {
- return "__TEXT,__ustring";
- }
-
- virtual std::string isValidSectionSpecifier(const llvm::StringRef &SR) const {
+ virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const {
// Let MCSectionMachO validate this.
llvm::StringRef Segment, Section;
unsigned TAA, StubSize;
@@ -201,16 +191,10 @@ protected:
// FreeBSD defines; list based off of gcc output
// FIXME: Move version number handling to llvm::Triple.
- const char *FreeBSD = strstr(Triple.getTriple().c_str(),
- "-freebsd");
- FreeBSD += strlen("-freebsd");
- char release[] = "X";
- release[0] = FreeBSD[0];
- char version[] = "X00001";
- version[0] = FreeBSD[0];
-
- Builder.defineMacro("__FreeBSD__", release);
- Builder.defineMacro("__FreeBSD_cc_version", version);
+ llvm::StringRef Release = Triple.getOSName().substr(strlen("freebsd"), 1);
+
+ Builder.defineMacro("__FreeBSD__", Release);
+ Builder.defineMacro("__FreeBSD_cc_version", Release + "00001");
Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
DefineStd(Builder, "unix", Opts);
Builder.defineMacro("__ELF__");
@@ -643,9 +627,13 @@ class X86TargetInfo : public TargetInfo {
enum X86SSEEnum {
NoMMXSSE, MMX, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42
} SSELevel;
+ enum AMD3DNowEnum {
+ NoAMD3DNow, AMD3DNow, AMD3DNowAthlon
+ } AMD3DNowLevel;
+
public:
X86TargetInfo(const std::string& triple)
- : TargetInfo(triple), SSELevel(NoMMXSSE) {
+ : TargetInfo(triple), SSELevel(NoMMXSSE), AMD3DNowLevel(NoAMD3DNow) {
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -810,6 +798,14 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
.Case("mmx", MMX)
.Default(NoMMXSSE);
SSELevel = std::max(SSELevel, Level);
+
+ AMD3DNowEnum ThreeDNowLevel =
+ llvm::StringSwitch<AMD3DNowEnum>(Features[i].substr(1))
+ .Case("3dnowa", AMD3DNowAthlon)
+ .Case("3dnow", AMD3DNow)
+ .Default(NoAMD3DNow);
+
+ AMD3DNowLevel = std::max(AMD3DNowLevel, ThreeDNowLevel);
}
}
@@ -864,6 +860,16 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case NoMMXSSE:
break;
}
+
+ // Each case falls through to the previous one here.
+ switch (AMD3DNowLevel) {
+ case AMD3DNowAthlon:
+ Builder.defineMacro("__3dNOW_A__");
+ case AMD3DNow:
+ Builder.defineMacro("__3dNOW__");
+ case NoAMD3DNow:
+ break;
+ }
}
@@ -1224,7 +1230,7 @@ public:
// FIXME: We need support for -meabi... we could just mangle it into the
// name.
if (Name == "apcs-gnu") {
- DoubleAlign = LongLongAlign = 32;
+ DoubleAlign = LongLongAlign = LongDoubleAlign = 32;
SizeType = UnsignedLong;
if (IsThumb) {
@@ -1379,9 +1385,6 @@ public:
// when Neon instructions are actually available.
if (FPU == NeonFPU && !SoftFloat && IsThumb2)
Builder.defineMacro("__ARM_NEON__");
-
- if (getTriple().getOS() == llvm::Triple::Darwin)
- Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1461,8 +1464,7 @@ class DarwinARMTargetInfo :
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
- getDarwinDefines(Builder, Opts);
- getDarwinIPhoneOSDefines(Builder, Triple);
+ getDarwinDefines(Builder, Opts, Triple);
}
public:
@@ -1617,23 +1619,25 @@ namespace {
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__pic16");
+ Builder.defineMacro("__PIC16");
Builder.defineMacro("rom", "__attribute__((address_space(1)))");
Builder.defineMacro("ram", "__attribute__((address_space(0)))");
- Builder.defineMacro("_section(SectName)",
+ Builder.defineMacro("__section(SectName)",
"__attribute__((section(SectName)))");
Builder.defineMacro("near",
"__attribute__((section(\"Address=NEAR\")))");
- Builder.defineMacro("_address(Addr)",
+ Builder.defineMacro("__address(Addr)",
"__attribute__((section(\"Address=\"#Addr)))");
- Builder.defineMacro("_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
- Builder.defineMacro("_interrupt",
+ Builder.defineMacro("__config(conf)", "asm(\"CONFIG \"#conf)");
+ Builder.defineMacro("__idlocs(value)", "asm(\"__IDLOCS \"#value)");
+ Builder.defineMacro("interrupt",
"__attribute__((section(\"interrupt=0x4\"))) \
__attribute__((used))");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {}
virtual const char *getVAListDeclaration() const {
- return "";
+ return "typedef char* __builtin_va_list;";
}
virtual const char *getClobbers() const {
return "";
@@ -1656,13 +1660,10 @@ namespace {
public:
MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
TLSSupported = false;
- IntWidth = 16;
- LongWidth = 32;
- LongLongWidth = 64;
- PointerWidth = 16;
- IntAlign = 8;
- LongAlign = LongLongAlign = 8;
- PointerAlign = 8;
+ IntWidth = 16; IntAlign = 16;
+ LongWidth = 32; LongLongWidth = 64;
+ LongAlign = LongLongAlign = 16;
+ PointerWidth = 16; PointerAlign = 16;
SizeType = UnsignedInt;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index b1b250f82933..98cf42b8c3d9 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -21,67 +21,55 @@ using namespace std;
namespace clang {
llvm::StringRef getClangRepositoryPath() {
- static const char *Path = 0;
- if (Path)
- return Path;
-
- static char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $";
- char *End = strstr(URL, "/lib/Basic");
+ static const char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $";
+ const char *URLEnd = URL + strlen(URL);
+
+ const char *End = strstr(URL, "/lib/Basic");
if (End)
- *End = 0;
-
+ URLEnd = End;
+
End = strstr(URL, "/clang/tools/clang");
if (End)
- *End = 0;
-
- char *Begin = strstr(URL, "cfe/");
- if (Begin) {
- Path = Begin + 4;
- return Path;
- }
-
- Path = URL;
- return Path;
-}
+ URLEnd = End;
+
+ const char *Begin = strstr(URL, "cfe/");
+ if (Begin)
+ return llvm::StringRef(Begin + 4, URLEnd - Begin - 4);
+ return llvm::StringRef(URL, URLEnd - URL);
+}
-llvm::StringRef getClangRevision() {
+std::string getClangRevision() {
#ifndef SVN_REVISION
// Subversion was not available at build time?
- return llvm::StringRef();
+ return "";
#else
- static std::string revision;
- if (revision.empty()) {
- llvm::raw_string_ostream OS(revision);
- OS << strtol(SVN_REVISION, 0, 10);
- }
+ std::string revision;
+ llvm::raw_string_ostream OS(revision);
+ OS << strtol(SVN_REVISION, 0, 10);
return revision;
#endif
}
-llvm::StringRef getClangFullRepositoryVersion() {
- static std::string buf;
- if (buf.empty()) {
- llvm::raw_string_ostream OS(buf);
- OS << getClangRepositoryPath();
- llvm::StringRef Revision = getClangRevision();
- if (!Revision.empty())
- OS << ' ' << Revision;
- }
+std::string getClangFullRepositoryVersion() {
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
+ OS << getClangRepositoryPath();
+ const std::string &Revision = getClangRevision();
+ if (!Revision.empty())
+ OS << ' ' << Revision;
return buf;
}
-const char *getClangFullVersion() {
- static std::string buf;
- if (buf.empty()) {
- llvm::raw_string_ostream OS(buf);
+std::string getClangFullVersion() {
+ std::string buf;
+ llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
- OS << CLANG_VENDOR;
+ OS << CLANG_VENDOR;
#endif
- OS << "clang version " CLANG_VERSION_STRING " ("
- << getClangFullRepositoryVersion() << ')';
- }
- return buf.c_str();
+ OS << "clang version " CLANG_VERSION_STRING " ("
+ << getClangFullRepositoryVersion() << ')';
+ return buf;
}
-
+
} // end namespace clang
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 2bfaa445e568..bc2cd460d92b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -10,3 +10,4 @@ add_subdirectory(Rewrite)
add_subdirectory(Driver)
add_subdirectory(Frontend)
add_subdirectory(Index)
+add_subdirectory(Checker)
diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp
new file mode 100644
index 000000000000..e95a86b838b6
--- /dev/null
+++ b/lib/Checker/AdjustedReturnValueChecker.cpp
@@ -0,0 +1,98 @@
+//== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines AdjustedReturnValueChecker, a simple check to see if the
+// return value of a function call is different than the one the caller thinks
+// it is.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class AdjustedReturnValueChecker :
+ public CheckerVisitor<AdjustedReturnValueChecker> {
+public:
+ AdjustedReturnValueChecker() {}
+
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+
+ static void *getTag() {
+ static int x = 0; return &x;
+ }
+};
+}
+
+void clang::RegisterAdjustedReturnValueChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new AdjustedReturnValueChecker());
+}
+
+void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+
+ // Get the result type of the call.
+ QualType expectedResultTy = CE->getType();
+
+ // Fetch the signature of the called function.
+ const GRState *state = C.getState();
+
+ SVal V = state->getSVal(CE);
+
+ if (V.isUnknown())
+ return;
+
+ // Casting to void? Discard the value.
+ if (expectedResultTy->isVoidType()) {
+ C.GenerateNode(state->BindExpr(CE, UnknownVal()));
+ return;
+ }
+
+ const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
+ if (!callee)
+ return;
+
+ QualType actualResultTy;
+
+ if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
+ const FunctionDecl *FD = FT->getDecl();
+ actualResultTy = FD->getResultType();
+ }
+ else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
+ const BlockTextRegion *BR = BD->getCodeRegion();
+ const BlockPointerType *BT =
+ BR->getLocationType(C.getASTContext())->getAs<BlockPointerType>();
+ const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+ actualResultTy = FT->getResultType();
+ }
+
+ // Can this happen?
+ if (actualResultTy.isNull())
+ return;
+
+ // For now, ignore references.
+ if (actualResultTy->getAs<ReferenceType>())
+ return;
+
+
+ // Are they the same?
+ if (expectedResultTy != actualResultTy) {
+ // FIXME: Do more checking and actual emit an error. At least performing
+ // the cast avoids some assertion failures elsewhere.
+ SValuator &SVator = C.getSValuator();
+ V = SVator.EvalCast(V, expectedResultTy, actualResultTy);
+ C.GenerateNode(state->BindExpr(CE, V));
+ }
+}
diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp
index 49c86068265b..74fb06f45564 100644
--- a/lib/Analysis/ArrayBoundChecker.cpp
+++ b/lib/Checker/ArrayBoundChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Checker/AttrNonNullChecker.cpp
index aa21700c2483..83dc13e92b63 100644
--- a/lib/Analysis/AttrNonNullChecker.cpp
+++ b/lib/Checker/AttrNonNullChecker.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Checker/BasicConstraintManager.cpp
index 6dfc470530a4..e89546ecb018 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Checker/BasicConstraintManager.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index 67483d979291..d6c09a2e04a6 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -15,15 +15,15 @@
#include "BasicObjCFoundationChecks.h"
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
@@ -163,61 +163,22 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
// FIXME: This is going to be really slow doing these checks with
// lexical comparisons.
- std::string name = S.getAsString();
- assert (!name.empty());
- const char* cstr = &name[0];
- unsigned len = name.size();
-
- switch (len) {
- default:
- break;
- case 8:
- if (!strcmp(cstr, "compare:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 15:
- // FIXME: Checking for initWithFormat: will not work in most cases
- // yet because [NSString alloc] returns id, not NSString*. We will
- // need support for tracking expected-type information in the analyzer
- // to find these errors.
- if (!strcmp(cstr, "initWithFormat:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 16:
- if (!strcmp(cstr, "compare:options:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 22:
- if (!strcmp(cstr, "compare:options:range:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 23:
-
- if (!strcmp(cstr, "caseInsensitiveCompare:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 29:
- if (!strcmp(cstr, "compare:options:range:locale:"))
- return CheckNilArg(N, 0);
-
- break;
-
- case 37:
- if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
- return CheckNilArg(N, 0);
-
- break;
- }
+ std::string NameStr = S.getAsString();
+ llvm::StringRef Name(NameStr);
+ assert(!Name.empty());
+
+ // FIXME: Checking for initWithFormat: will not work in most cases
+ // yet because [NSString alloc] returns id, not NSString*. We will
+ // need support for tracking expected-type information in the analyzer
+ // to find these errors.
+ if (Name == "caseInsensitiveCompare:" ||
+ Name == "compare:" ||
+ Name == "compare:options:" ||
+ Name == "compare:options:range:" ||
+ Name == "compare:options:range:locale:" ||
+ Name == "componentsSeparatedByCharactersInSet:" ||
+ Name == "initWithFormat:")
+ return CheckNilArg(N, 0);
return false;
}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Checker/BasicObjCFoundationChecks.h
index 679c6dc1df2d..679c6dc1df2d 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.h
+++ b/lib/Checker/BasicObjCFoundationChecks.h
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 224281b17770..6ef29429f681 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -13,8 +13,8 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -40,25 +40,19 @@ public:
~BasicStoreManager() {}
- SubRegionMap *getSubRegionMap(const GRState *state) {
+ SubRegionMap *getSubRegionMap(Store store) {
return new BasicStoreSubRegionMap();
}
- SValuator::CastResult Retrieve(const GRState *state, Loc loc,
- QualType T = QualType());
+ SVal Retrieve(Store store, Loc loc, QualType T = QualType());
- const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS);
-
- const GRState *Bind(const GRState *state, Loc L, SVal V) {
- return state->makeWithStore(BindInternal(state->getStore(), L, V));
- }
+ Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS);
Store scanForIvars(Stmt *B, const Decl* SelfDecl,
const MemRegion *SelfRegion, Store St);
- Store BindInternal(Store St, Loc loc, SVal V);
+ Store Bind(Store St, Loc loc, SVal V);
Store Remove(Store St, Loc loc);
Store getInitialStore(const LocationContext *InitLoc);
@@ -67,38 +61,28 @@ public:
return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
}
- const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr*,
- const LocationContext*,
- SVal val) {
- return state;
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr*,
+ const LocationContext*, SVal val) {
+ return store;
}
- SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
- SVal getLValueString(const StringLiteral *S);
- SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
- SVal getLValueField(const FieldDecl *D, SVal Base);
- SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
-
/// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
/// conversions between arrays and pointers.
SVal ArrayToPointer(Loc Array) { return Array; }
/// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
/// It updatees the GRState object in place with the values removed.
- void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper,
+ Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
void iterBindings(Store store, BindingsHandler& f);
- const GRState *BindDecl(const GRState *state, const VarRegion *VR,
- SVal InitVal) {
- return state->makeWithStore(BindDeclInternal(state->getStore(), VR,
- &InitVal));
+ Store BindDecl(Store store, const VarRegion *VR, SVal InitVal) {
+ return BindDeclInternal(store, VR, &InitVal);
}
- const GRState *BindDeclWithNoInit(const GRState *state, const VarRegion *VR) {
- return state->makeWithStore(BindDeclInternal(state->getStore(), VR, 0));
+ Store BindDeclWithNoInit(Store store, const VarRegion *VR) {
+ return BindDeclInternal(store, VR, 0);
}
Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal);
@@ -121,114 +105,6 @@ StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
return new BasicStoreManager(StMgr);
}
-SVal BasicStoreManager::getLValueVar(const VarDecl* VD,
- const LocationContext *LC) {
- return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
-}
-
-SVal BasicStoreManager::getLValueString(const StringLiteral* S) {
- return ValMgr.makeLoc(MRMgr.getStringRegion(S));
-}
-
-SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
-
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
-
- if (isa<loc::MemRegionVal>(BaseL)) {
- const MemRegion *BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
- return ValMgr.makeLoc(MRMgr.getObjCIvarRegion(D, BaseR));
- }
-
- return UnknownVal();
-}
-
-SVal BasicStoreManager::getLValueField(const FieldDecl* D, SVal Base) {
-
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
- const MemRegion* BaseR = 0;
-
- switch(BaseL.getSubKind()) {
- case loc::GotoLabelKind:
- return UndefinedVal();
-
- case loc::MemRegionKind:
- BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
- break;
-
- case loc::ConcreteIntKind:
- // While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
- // like this work properly: &(((struct foo *) 0xa)->f)
- return Base;
-
- default:
- assert ("Unhandled Base.");
- return Base;
- }
-
- return ValMgr.makeLoc(MRMgr.getFieldRegion(D, BaseR));
-}
-
-SVal BasicStoreManager::getLValueElement(QualType elementType,
- SVal Offset, SVal Base) {
-
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
- const MemRegion* BaseR = 0;
-
- switch(BaseL.getSubKind()) {
- case loc::GotoLabelKind:
- // Technically we can get here if people do funny things with casts.
- return UndefinedVal();
-
- case loc::MemRegionKind: {
- const MemRegion *R = cast<loc::MemRegionVal>(BaseL).getRegion();
-
- if (isa<ElementRegion>(R)) {
- // int x;
- // char* y = (char*) &x;
- // 'y' => ElementRegion(0, VarRegion('x'))
- // y[0] = 'a';
- return Base;
- }
-
- if (isa<TypedRegion>(R) || isa<SymbolicRegion>(R)) {
- BaseR = R;
- break;
- }
-
- break;
- }
-
- case loc::ConcreteIntKind:
- // While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
- // like this work properly: &(((struct foo *) 0xa)->f)
- return Base;
-
- default:
- assert ("Unhandled Base.");
- return Base;
- }
-
- if (BaseR) {
- return ValMgr.makeLoc(MRMgr.getElementRegion(elementType, UnknownVal(),
- BaseR, getContext()));
- }
- else
- return UnknownVal();
-}
-
static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
bool foundPointer = false;
while (1) {
@@ -250,11 +126,9 @@ static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
}
}
-SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
- Loc loc, QualType T) {
-
+SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
if (isa<UnknownVal>(loc))
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
assert(!isa<UndefinedVal>(loc));
@@ -264,33 +138,32 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
- BindingsTy B = GetBindings(state->getStore());
+ BindingsTy B = GetBindings(store);
BindingsTy::data_type *Val = B.lookup(R);
if (!Val)
break;
- return SValuator::CastResult(state,
- CastRetrievedVal(*Val, cast<TypedRegion>(R), T));
+ return CastRetrievedVal(*Val, cast<TypedRegion>(R), T);
}
case loc::ConcreteIntKind:
// Some clients may call GetSVal with such an option simply because
// they are doing a quick scan through their Locs (potentially to
// invalidate their bindings). Just return Undefined.
- return SValuator::CastResult(state, UndefinedVal());
+ return UndefinedVal();
default:
assert (false && "Invalid Loc.");
break;
}
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
}
-Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
+Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) {
if (isa<loc::ConcreteInt>(loc))
return store;
@@ -352,12 +225,10 @@ Store BasicStoreManager::Remove(Store store, Loc loc) {
}
}
-void
-BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
- SymbolReaper& SymReaper,
+Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
- Store store = state.getStore();
BindingsTy B = GetBindings(store);
typedef SVal::symbol_iterator symbol_iterator;
@@ -398,7 +269,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
break;
Marked.insert(MR);
- SVal X = Retrieve(&state, loc::MemRegionVal(MR)).getSVal();
+ SVal X = Retrieve(store, loc::MemRegionVal(MR));
// FIXME: We need to handle symbols nested in region definitions.
for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
@@ -431,8 +302,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
}
}
- // Write the store back.
- state.setStore(store);
+ return store;
}
Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
@@ -452,7 +322,7 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
SelfRegion);
SVal X = ValMgr.getRegionValueSymbolVal(IVR);
- St = BindInternal(St, ValMgr.makeLoc(IVR), X);
+ St = Bind(St, ValMgr.makeLoc(IVR), X);
}
}
}
@@ -485,8 +355,7 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
const MemRegion *SelfRegion =
ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
assert(SelfRegion);
- St = BindInternal(St, ValMgr.makeLoc(VR),
- loc::MemRegionVal(SelfRegion));
+ St = Bind(St, ValMgr.makeLoc(VR), loc::MemRegionVal(SelfRegion));
// Scan the method for ivar references. While this requires an
// entire AST scan, the cost should not be high in practice.
St = scanForIvars(MD->getBody(), PD, SelfRegion, St);
@@ -505,7 +374,7 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
if (R->hasGlobalsOrParametersStorage())
X = ValMgr.getRegionValueSymbolVal(R);
- St = BindInternal(St, ValMgr.makeLoc(R), X);
+ St = Bind(St, ValMgr.makeLoc(R), X);
}
}
return St;
@@ -543,16 +412,16 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
if (!InitVal) {
QualType T = VD->getType();
if (Loc::IsLocType(T))
- store = BindInternal(store, loc::MemRegionVal(VR),
+ store = Bind(store, loc::MemRegionVal(VR),
loc::ConcreteInt(BasicVals.getValue(0, T)));
else if (T->isIntegerType())
- store = BindInternal(store, loc::MemRegionVal(VR),
+ store = Bind(store, loc::MemRegionVal(VR),
nonloc::ConcreteInt(BasicVals.getValue(0, T)));
else {
// assert(0 && "ignore other types of variables");
}
} else {
- store = BindInternal(store, loc::MemRegionVal(VR), *InitVal);
+ store = Bind(store, loc::MemRegionVal(VR), *InitVal);
}
}
} else {
@@ -560,7 +429,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
QualType T = VD->getType();
if (ValMgr.getSymbolManager().canSymbolicate(T)) {
SVal V = InitVal ? *InitVal : UndefinedVal();
- store = BindInternal(store, loc::MemRegionVal(VR), V);
+ store = Bind(store, loc::MemRegionVal(VR), V);
}
}
@@ -600,18 +469,18 @@ StoreManager::BindingsHandler::~BindingsHandler() {}
// Binding invalidation.
//===----------------------------------------------------------------------===//
-const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
- const MemRegion *R,
- const Expr *E,
- unsigned Count,
- InvalidatedSymbols *IS) {
+Store BasicStoreManager::InvalidateRegion(Store store,
+ const MemRegion *R,
+ const Expr *E,
+ unsigned Count,
+ InvalidatedSymbols *IS) {
R = R->StripCasts();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
- return state;
+ return store;
if (IS) {
- BindingsTy B = GetBindings(state->getStore());
+ BindingsTy B = GetBindings(store);
if (BindingsTy::data_type *Val = B.lookup(R)) {
if (SymbolRef Sym = Val->getAsSymbol())
IS->insert(Sym);
@@ -620,6 +489,6 @@ const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
QualType T = cast<TypedRegion>(R)->getValueType(R->getContext());
SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count);
- return Bind(state, loc::MemRegionVal(R), V);
+ return Bind(store, loc::MemRegionVal(R), V);
}
diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Checker/BasicValueFactory.cpp
index b33c277f86f9..246beead1208 100644
--- a/lib/Analysis/BasicValueFactory.cpp
+++ b/lib/Checker/BasicValueFactory.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
+#include "clang/Checker/PathSensitive/BasicValueFactory.h"
using namespace clang;
@@ -24,9 +24,8 @@ void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
}
void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID,
- const GRState *state,
- const TypedRegion *region) {
- ID.AddPointer(state);
+ const void *store,const TypedRegion *region) {
+ ID.AddPointer(store);
ID.AddPointer(region);
}
@@ -124,10 +123,10 @@ BasicValueFactory::getCompoundValData(QualType T,
}
const LazyCompoundValData*
-BasicValueFactory::getLazyCompoundValData(const GRState *state,
+BasicValueFactory::getLazyCompoundValData(const void *store,
const TypedRegion *region) {
llvm::FoldingSetNodeID ID;
- LazyCompoundValData::Profile(ID, state, region);
+ LazyCompoundValData::Profile(ID, store, region);
void* InsertPos;
LazyCompoundValData *D =
@@ -135,7 +134,7 @@ BasicValueFactory::getLazyCompoundValData(const GRState *state,
if (!D) {
D = (LazyCompoundValData*) BPAlloc.Allocate<LazyCompoundValData>();
- new (D) LazyCompoundValData(state, region);
+ new (D) LazyCompoundValData(store, region);
LazyCompoundValDataSet.InsertNode(D, InsertPos);
}
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 2a9531df60f1..0cf593b26009 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/Expr.h"
@@ -21,7 +21,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/ProgramPoint.h"
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 87de30ae7aec..6cf41b14dc5a 100644
--- a/lib/Analysis/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -14,9 +14,9 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
@@ -323,7 +323,7 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
|| V.isUndef()) {
- registerFindLastStore(BRC, R, V);
+ ::registerFindLastStore(BRC, R, V);
}
}
}
@@ -347,3 +347,21 @@ void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
}
}
}
+
+void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC,
+ const void *data,
+ const ExplodedNode* N) {
+
+ const MemRegion *R = static_cast<const MemRegion*>(data);
+
+ if (!R)
+ return;
+
+ const GRState *state = N->getState();
+ SVal V = state->getSVal(R);
+
+ if (V.isUnknown())
+ return;
+
+ BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
+}
diff --git a/lib/Analysis/BuiltinFunctionChecker.cpp b/lib/Checker/BuiltinFunctionChecker.cpp
index a89ad2164b30..8711492049c5 100644
--- a/lib/Analysis/BuiltinFunctionChecker.cpp
+++ b/lib/Checker/BuiltinFunctionChecker.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/StringSwitch.h"
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 5a15fbfb1f05..324916a6f6eb 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -14,15 +14,16 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/DomainSpecific/CocoaConventions.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/DenseMap.h"
@@ -34,129 +35,8 @@
#include <stdarg.h>
using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-// The "fundamental rule" for naming conventions of methods:
-// (url broken into two lines)
-// http://developer.apple.com/documentation/Cocoa/Conceptual/
-// MemoryMgmt/Tasks/MemoryManagementRules.html
-//
-// "You take ownership of an object if you create it using a method whose name
-// begins with "alloc" or "new" or contains "copy" (for example, alloc,
-// newObject, or mutableCopy), or if you send it a retain message. You are
-// responsible for relinquishing ownership of objects you own using release
-// or autorelease. Any other time you receive an object, you must
-// not release it."
-//
-
-using llvm::StrInStrNoCase;
using llvm::StringRef;
-
-enum NamingConvention { NoConvention, CreateRule, InitRule };
-
-static inline 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 inline 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;
-}
-
-static NamingConvention deriveNamingConvention(Selector S) {
- IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
-
- if (!II)
- return NoConvention;
-
- const char *s = II->getNameStart();
-
- // A method/function name may contain a prefix. We don't know it is there,
- // however, until we encounter the first '_'.
- bool InPossiblePrefix = true;
- bool AtBeginning = true;
- NamingConvention C = NoConvention;
-
- while (*s != '\0') {
- // Skip '_'.
- if (*s == '_') {
- if (InPossiblePrefix) {
- // If we already have a convention, return it. Otherwise, skip
- // the prefix as if it wasn't there.
- if (C != NoConvention)
- break;
-
- InPossiblePrefix = false;
- AtBeginning = true;
- assert(C == NoConvention);
- }
- ++s;
- continue;
- }
-
- // Skip numbers, ':', etc.
- if (!isalpha(*s)) {
- ++s;
- continue;
- }
-
- const char *wordEnd = parseWord(s);
- assert(wordEnd > s);
- unsigned len = wordEnd - s;
-
- switch (len) {
- default:
- break;
- case 3:
- // Methods starting with 'new' follow the create rule.
- if (AtBeginning && StringRef(s, len).equals_lower("new"))
- C = CreateRule;
- break;
- case 4:
- // Methods starting with 'alloc' or contain 'copy' follow the
- // create rule
- if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
- C = CreateRule;
- else // Methods starting with 'init' follow the init rule.
- if (AtBeginning && StringRef(s, len).equals_lower("init"))
- C = InitRule;
- break;
- case 5:
- if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
- C = CreateRule;
- break;
- }
-
- // If we aren't in the prefix and have a derived convention then just
- // return it now.
- if (!InPossiblePrefix && C != NoConvention)
- return C;
-
- AtBeginning = false;
- s = wordEnd;
- }
-
- // We will get here if there wasn't more than one word
- // after the prefix.
- return C;
-}
-
-static bool followsFundamentalRule(Selector S) {
- return deriveNamingConvention(S) == CreateRule;
-}
+using llvm::StrInStrNoCase;
static const ObjCMethodDecl*
ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
@@ -194,34 +74,6 @@ public:
} // end anonymous namespace
//===----------------------------------------------------------------------===//
-// Type querying functions.
-//===----------------------------------------------------------------------===//
-
-static bool isRefType(QualType RetTy, const char* prefix,
- ASTContext* Ctx = 0, const char* name = 0) {
-
- // Recursively walk the typedef stack, allowing typedefs of reference types.
- while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
- llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
- if (TDName.startswith(prefix) && TDName.endswith("Ref"))
- return true;
-
- RetTy = TD->getDecl()->getUnderlyingType();
- }
-
- if (!Ctx || !name)
- return false;
-
- // Is the type void*?
- const PointerType* PT = RetTy->getAs<PointerType>();
- if (!(PT->getPointeeType().getUnqualifiedType() == Ctx->VoidTy))
- return false;
-
- // Does the name start with the prefix?
- return llvm::StringRef(name).startswith(prefix);
-}
-
-//===----------------------------------------------------------------------===//
// Primitives used for constructing summaries for function/method calls.
//===----------------------------------------------------------------------===//
@@ -853,7 +705,7 @@ public:
RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD);
RetainSummary* getCFSummaryGetRule(FunctionDecl* FD);
- RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, const char* FName);
+ RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, StringRef FName);
RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff,
ArgEffect ReceiverEff = DoNothing,
@@ -880,10 +732,6 @@ public:
void InitializeClassMethodSummaries();
void InitializeMethodSummaries();
-
- bool isTrackedObjCObjectType(QualType T);
- bool isTrackedCFObjectType(QualType T);
-
private:
void addClsMethSummary(IdentifierInfo* ClsII, Selector S,
@@ -1072,62 +920,15 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
}
//===----------------------------------------------------------------------===//
-// Predicates.
-//===----------------------------------------------------------------------===//
-
-bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) {
- if (!Ty->isObjCObjectPointerType())
- return false;
-
- const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
-
- // Can be true for objects with the 'NSObject' attribute.
- if (!PT)
- return true;
-
- // We assume that id<..>, id, and "Class" all represent tracked objects.
- if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
- PT->isObjCClassType())
- return true;
-
- // Does the interface subclass NSObject?
- // FIXME: We can memoize here if this gets too expensive.
- const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
-
- // Assume that anything declared with a forward declaration and no
- // @interface subclasses NSObject.
- if (ID->isForwardDecl())
- return true;
-
- IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
-
- for ( ; ID ; ID = ID->getSuperClass())
- if (ID->getIdentifier() == NSObjectII)
- return true;
-
- return false;
-}
-
-bool RetainSummaryManager::isTrackedCFObjectType(QualType T) {
- return isRefType(T, "CF") || // Core Foundation.
- isRefType(T, "CG") || // Core Graphics.
- isRefType(T, "DADisk") || // Disk Arbitration API.
- isRefType(T, "DADissenter") ||
- isRefType(T, "DASessionRef");
-}
-
-//===----------------------------------------------------------------------===//
// Summary creation for functions (largely uses of Core Foundation).
//===----------------------------------------------------------------------===//
-static bool isRetain(FunctionDecl* FD, const char* FName) {
- const char* loc = strstr(FName, "Retain");
- return loc && loc[sizeof("Retain")-1] == '\0';
+static bool isRetain(FunctionDecl* FD, StringRef FName) {
+ return FName.endswith("Retain");
}
-static bool isRelease(FunctionDecl* FD, const char* FName) {
- const char* loc = strstr(FName, "Release");
- return loc && loc[sizeof("Release")-1] == '\0';
+static bool isRelease(FunctionDecl* FD, StringRef FName) {
+ return FName.endswith("Release");
}
RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
@@ -1152,12 +953,12 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
const IdentifierInfo *II = FD->getIdentifier();
if (!II)
break;
-
- const char* FName = II->getNameStart();
+
+ StringRef FName = II->getName();
// Strip away preceding '_'. Doing this here will effect all the checks
// down below.
- while (*FName == '_') ++FName;
+ FName = FName.substr(FName.find_first_not_of('_'));
// Inspect the result type.
QualType RetTy = FT->getResultType();
@@ -1165,133 +966,63 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// FIXME: This should all be refactored into a chain of "summary lookup"
// filters.
assert(ScratchArgs.isEmpty());
-
- switch (strlen(FName)) {
- default: break;
- case 14:
- if (!memcmp(FName, "pthread_create", 14)) {
- // Part of: <rdar://problem/7299394>. This will be addressed
- // better with IPA.
- S = getPersistentStopSummary();
- }
- break;
-
- case 17:
- // Handle: id NSMakeCollectable(CFTypeRef)
- if (!memcmp(FName, "NSMakeCollectable", 17)) {
- S = (RetTy->isObjCIdType())
- ? getUnarySummary(FT, cfmakecollectable)
- : getPersistentStopSummary();
- }
- else if (!memcmp(FName, "IOBSDNameMatching", 17) ||
- !memcmp(FName, "IOServiceMatching", 17)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 21:
- if (!memcmp(FName, "IOServiceNameMatching", 21)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 24:
- if (!memcmp(FName, "IOServiceAddNotification", 24)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,DoNothing);
- }
- break;
-
- case 25:
- if (!memcmp(FName, "IORegistryEntryIDMatching", 25)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 26:
- if (!memcmp(FName, "IOOpenFirmwarePathMatching", 26)) {
- // Part of <rdar://problem/6961230>. (IOKit)
- // This should be addressed using a API table.
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing, DoNothing);
- }
- break;
-
- case 27:
- if (!memcmp(FName, "IOServiceGetMatchingService", 27)) {
- // Part of <rdar://problem/6961230>.
- // This should be addressed using a API table.
- ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
- }
- break;
- case 28:
- if (!memcmp(FName, "IOServiceGetMatchingServices", 28)) {
- // FIXES: <rdar://problem/6326900>
- // This should be addressed using a API table. This strcmp is also
- // a little gross, but there is no need to super optimize here.
- ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
- DoNothing);
- }
- else if (!memcmp(FName, "CVPixelBufferCreateWithBytes", 28)) {
- // FIXES: <rdar://problem/7283567>
- // Eventually this can be improved by recognizing that the pixel
- // buffer passed to CVPixelBufferCreateWithBytes is released via
- // a callback and doing full IPA to make sure this is done correctly.
- // FIXME: This function has an out parameter that returns an
- // allocated object.
- ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
- DoNothing);
- }
- break;
-
- case 29:
- if (!memcmp(FName, "CGBitmapContextCreateWithData", 29)) {
- // FIXES: <rdar://problem/7358899>
- // Eventually this can be improved by recognizing that 'releaseInfo'
- // passed to CGBitmapContextCreateWithData is released via
- // a callback and doing full IPA to make sure this is done correctly.
- ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking);
- S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
- DoNothing,DoNothing);
- }
- break;
-
- case 32:
- if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) {
- // Part of <rdar://problem/6961230>.
- // This should be addressed using a API table.
- ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
- }
- break;
-
- case 34:
- if (!memcmp(FName, "CVPixelBufferCreateWithPlanarBytes", 34)) {
- // FIXES: <rdar://problem/7283567>
- // Eventually this can be improved by recognizing that the pixel
- // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
- // via a callback and doing full IPA to make sure this is done
- // correctly.
- ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking);
- S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing,
- DoNothing);
- }
- break;
+ if (FName == "pthread_create") {
+ // Part of: <rdar://problem/7299394>. This will be addressed
+ // better with IPA.
+ S = getPersistentStopSummary();
+ } else if (FName == "NSMakeCollectable") {
+ // Handle: id NSMakeCollectable(CFTypeRef)
+ S = (RetTy->isObjCIdType())
+ ? getUnarySummary(FT, cfmakecollectable)
+ : getPersistentStopSummary();
+ } else if (FName == "IOBSDNameMatching" ||
+ FName == "IOServiceMatching" ||
+ FName == "IOServiceNameMatching" ||
+ FName == "IORegistryEntryIDMatching" ||
+ FName == "IOOpenFirmwarePathMatching") {
+ // Part of <rdar://problem/6961230>. (IOKit)
+ // This should be addressed using a API table.
+ S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
+ DoNothing, DoNothing);
+ } else if (FName == "IOServiceGetMatchingService" ||
+ FName == "IOServiceGetMatchingServices") {
+ // FIXES: <rdar://problem/6326900>
+ // This should be addressed using a API table. This strcmp is also
+ // a little gross, but there is no need to super optimize here.
+ ScratchArgs = AF.Add(ScratchArgs, 1, DecRef);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName == "IOServiceAddNotification" ||
+ FName == "IOServiceAddMatchingNotification") {
+ // Part of <rdar://problem/6961230>. (IOKit)
+ // This should be addressed using a API table.
+ ScratchArgs = AF.Add(ScratchArgs, 2, DecRef);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName == "CVPixelBufferCreateWithBytes") {
+ // FIXES: <rdar://problem/7283567>
+ // Eventually this can be improved by recognizing that the pixel
+ // buffer passed to CVPixelBufferCreateWithBytes is released via
+ // a callback and doing full IPA to make sure this is done correctly.
+ // FIXME: This function has an out parameter that returns an
+ // allocated object.
+ ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName == "CGBitmapContextCreateWithData") {
+ // FIXES: <rdar://problem/7358899>
+ // Eventually this can be improved by recognizing that 'releaseInfo'
+ // passed to CGBitmapContextCreateWithData is released via
+ // a callback and doing full IPA to make sure this is done correctly.
+ ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
+ DoNothing, DoNothing);
+ } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
+ // FIXES: <rdar://problem/7283567>
+ // Eventually this can be improved by recognizing that the pixel
+ // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
+ // via a callback and doing full IPA to make sure this is done
+ // correctly.
+ ScratchArgs = AF.Add(ScratchArgs, 12, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
}
// Did we get a summary?
@@ -1312,10 +1043,10 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
if (RetTy->isPointerType()) {
// For CoreFoundation ('CF') types.
- if (isRefType(RetTy, "CF", &Ctx, FName)) {
+ if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
S = getUnarySummary(FT, cfretain);
- else if (strstr(FName, "MakeCollectable"))
+ else if (FName.find("MakeCollectable") != StringRef::npos)
S = getUnarySummary(FT, cfmakecollectable);
else
S = getCFCreateGetRuleSummary(FD, FName);
@@ -1324,7 +1055,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
}
// For CoreGraphics ('CG') types.
- if (isRefType(RetTy, "CG", &Ctx, FName)) {
+ if (cocoa::isRefType(RetTy, "CG", FName)) {
if (isRetain(FD, FName))
S = getUnarySummary(FT, cfretain);
else
@@ -1334,9 +1065,9 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
}
// For the Disk Arbitration API (DiskArbitration/DADisk.h)
- if (isRefType(RetTy, "DADisk") ||
- isRefType(RetTy, "DADissenter") ||
- isRefType(RetTy, "DASessionRef")) {
+ if (cocoa::isRefType(RetTy, "DADisk") ||
+ cocoa::isRefType(RetTy, "DADissenter") ||
+ cocoa::isRefType(RetTy, "DASessionRef")) {
S = getCFCreateGetRuleSummary(FD, FName);
break;
}
@@ -1348,10 +1079,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// about that don't return a pointer type.
if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) {
// Test for 'CGCF'.
- if (FName[1] == 'G' && FName[2] == 'C' && FName[3] == 'F')
- FName += 4;
- else
- FName += 2;
+ FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
if (isRelease(FD, FName))
S = getUnarySummary(FT, cfrelease);
@@ -1398,12 +1126,13 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
RetainSummary*
RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD,
- const char* FName) {
+ StringRef FName) {
- if (strstr(FName, "Create") || strstr(FName, "Copy"))
+ if (FName.find("Create") != StringRef::npos ||
+ FName.find("Copy") != StringRef::npos)
return getCFSummaryCreateRule(FD);
- if (strstr(FName, "Get"))
+ if (FName.find("Get") != StringRef::npos)
return getCFSummaryGetRule(FD);
return getDefaultSummary();
@@ -1471,7 +1200,7 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
assert(ScratchArgs.isEmpty());
// 'init' methods conceptually return a newly allocated object and claim
// the receiver.
- if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy))
+ if (cocoa::isCocoaObjectRef(RetTy) || cocoa::isCFObjectRef(RetTy))
return getPersistentSummary(ObjCInitRetE, DecRefMsg);
return getDefaultSummary();
@@ -1486,7 +1215,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
QualType RetTy = FD->getResultType();
// Determine if there is a special return effect for this method.
- if (isTrackedObjCObjectType(RetTy)) {
+ if (cocoa::isCocoaObjectRef(RetTy)) {
if (FD->getAttr<NSReturnsRetainedAttr>()) {
Summ.setRetEffect(ObjCAllocRetE);
}
@@ -1510,7 +1239,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
bool isTrackedLoc = false;
// Determine if there is a special return effect for this method.
- if (isTrackedObjCObjectType(MD->getResultType())) {
+ if (cocoa::isCocoaObjectRef(MD->getResultType())) {
if (MD->getAttr<NSReturnsRetainedAttr>()) {
Summ.setRetEffect(ObjCAllocRetE);
return;
@@ -1560,18 +1289,18 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
}
// Look for methods that return an owned object.
- if (isTrackedObjCObjectType(RetTy)) {
+ if (cocoa::isCocoaObjectRef(RetTy)) {
// EXPERIMENTAL: Assume the Cocoa conventions for all objects returned
// by instance methods.
- RetEffect E = followsFundamentalRule(S)
+ RetEffect E = cocoa::followsFundamentalRule(S)
? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC);
return getPersistentSummary(E, ReceiverEff, MayEscape);
}
// Look for methods that return an owned core foundation object.
- if (isTrackedCFObjectType(RetTy)) {
- RetEffect E = followsFundamentalRule(S)
+ if (cocoa::isCFObjectRef(RetTy)) {
+ RetEffect E = cocoa::followsFundamentalRule(S)
? RetEffect::MakeOwned(RetEffect::CF, true)
: RetEffect::MakeNotOwned(RetEffect::CF);
@@ -1653,7 +1382,7 @@ RetainSummaryManager::getInstanceMethodSummary(Selector S,
assert(ScratchArgs.isEmpty());
// "initXXX": pass-through for receiver.
- if (deriveNamingConvention(S) == InitRule)
+ if (cocoa::deriveNamingConvention(S) == cocoa::InitRule)
Summ = getInitMethodSummary(RetTy);
else
Summ = getCommonMethodSummary(MD, S, RetTy);
@@ -2880,10 +2609,12 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
StoreManager::InvalidatedSymbols IS;
- state = StoreMgr.InvalidateRegions(state, RegionsToInvalidate.data(),
+ Store store = state->getStore();
+ store = StoreMgr.InvalidateRegions(store, RegionsToInvalidate.data(),
RegionsToInvalidate.data() +
RegionsToInvalidate.size(),
Ex, Count, &IS);
+ state = state->makeWithStore(store);
for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
E = IS.end(); I!=E; ++I) {
// Remove any existing reference-count binding.
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
new file mode 100644
index 000000000000..7b21d08dcb71
--- /dev/null
+++ b/lib/Checker/CMakeLists.txt
@@ -0,0 +1,67 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangChecker
+ AdjustedReturnValueChecker.cpp
+ ArrayBoundChecker.cpp
+ AttrNonNullChecker.cpp
+ BasicConstraintManager.cpp
+ BasicObjCFoundationChecks.cpp
+ BasicStore.cpp
+ BasicValueFactory.cpp
+ BugReporter.cpp
+ BugReporterVisitors.cpp
+ BuiltinFunctionChecker.cpp
+ CFRefCount.cpp
+ CallAndMessageChecker.cpp
+ CallInliner.cpp
+ CastToStructChecker.cpp
+ CheckDeadStores.cpp
+ CheckObjCDealloc.cpp
+ CheckObjCInstMethSignature.cpp
+ CheckObjCUnusedIVars.cpp
+ CheckSecuritySyntaxOnly.cpp
+ CheckSizeofPointer.cpp
+ Checker.cpp
+ CocoaConventions.cpp
+ DereferenceChecker.cpp
+ DivZeroChecker.cpp
+ Environment.cpp
+ ExplodedGraph.cpp
+ FixedAddressChecker.cpp
+ FlatStore.cpp
+ GRBlockCounter.cpp
+ GRCoreEngine.cpp
+ GRExprEngine.cpp
+ GRExprEngineExperimentalChecks.cpp
+ GRState.cpp
+ LLVMConventionsChecker.cpp
+ MallocChecker.cpp
+ ManagerRegistry.cpp
+ MemRegion.cpp
+ NSAutoreleasePoolChecker.cpp
+ NSErrorChecker.cpp
+ NoReturnFunctionChecker.cpp
+ OSAtomicChecker.cpp
+ PathDiagnostic.cpp
+ PointerArithChecker.cpp
+ PointerSubChecker.cpp
+ PthreadLockChecker.cpp
+ RangeConstraintManager.cpp
+ RegionStore.cpp
+ ReturnPointerRangeChecker.cpp
+ ReturnStackAddressChecker.cpp
+ ReturnUndefChecker.cpp
+ SVals.cpp
+ SValuator.cpp
+ SimpleConstraintManager.cpp
+ SimpleSValuator.cpp
+ Store.cpp
+ SymbolManager.cpp
+ UndefBranchChecker.cpp
+ UndefCapturedBlockVarChecker.cpp
+ UndefResultChecker.cpp
+ UndefinedArraySubscriptChecker.cpp
+ UndefinedAssignmentChecker.cpp
+ VLASizeChecker.cpp
+ ValueManager.cpp
+ )
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index c287354650b8..9013c3818b0c 100644
--- a/lib/Analysis/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TargetInfo.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/ParentMap.h"
#include "GRExprEngineInternalChecks.h"
diff --git a/lib/Analysis/CallInliner.cpp b/lib/Checker/CallInliner.cpp
index d18bbcc0174a..d94994b19437 100644
--- a/lib/Analysis/CallInliner.cpp
+++ b/lib/Checker/CallInliner.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
using namespace clang;
diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp
index 219c09f6ab7a..bef5bc285ee2 100644
--- a/lib/Analysis/CastToStructChecker.cpp
+++ b/lib/Checker/CastToStructChecker.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp
index 6e4d8998620d..4a7ca705488a 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Checker/CheckDeadStores.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp
index 87c1f270a65c..d9606f1306d4 100644
--- a/lib/Analysis/CheckObjCDealloc.cpp
+++ b/lib/Checker/CheckObjCDealloc.cpp
@@ -13,9 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp
index 10ba896557df..8c43a45d92c0 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Checker/CheckObjCInstMethSignature.cpp
@@ -13,9 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
#include "clang/AST/ASTContext.h"
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Checker/CheckObjCUnusedIVars.cpp
index d4067c900f3f..f2cf58191632 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Checker/CheckObjCUnusedIVars.cpp
@@ -13,9 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp
index f4874a5dfe4c..923baf50f3f6 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TargetInfo.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Checker/CheckSizeofPointer.cpp
index 4f5da9f5a716..bbe494c99da5 100644
--- a/lib/Analysis/CheckSizeofPointer.cpp
+++ b/lib/Checker/CheckSizeofPointer.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
using namespace clang;
diff --git a/lib/Analysis/Checker.cpp b/lib/Checker/Checker.cpp
index fb9d04d947b7..36323b9efb61 100644
--- a/lib/Analysis/Checker.cpp
+++ b/lib/Checker/Checker.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
using namespace clang;
Checker::~Checker() {}
diff --git a/lib/Checker/CocoaConventions.cpp b/lib/Checker/CocoaConventions.cpp
new file mode 100644
index 000000000000..3ba887ccc7e3
--- /dev/null
+++ b/lib/Checker/CocoaConventions.cpp
@@ -0,0 +1,195 @@
+//===- CocoaConventions.h - Special handling of Cocoa conventions -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/DomainSpecific/CocoaConventions.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace clang;
+
+using llvm::StringRef;
+
+// The "fundamental rule" for naming conventions of methods:
+// (url broken into two lines)
+// http://developer.apple.com/documentation/Cocoa/Conceptual/
+// MemoryMgmt/Tasks/MemoryManagementRules.html
+//
+// "You take ownership of an object if you create it using a method whose name
+// begins with "alloc" or "new" or contains "copy" (for example, alloc,
+// newObject, or mutableCopy), or if you send it a retain message. You are
+// responsible for relinquishing ownership of objects you own using release
+// or autorelease. Any other time you receive an object, you must
+// 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) {
+ IdentifierInfo *II = S.getIdentifierInfoForSlot(0);
+
+ if (!II)
+ return NoConvention;
+
+ const char *s = II->getNameStart();
+
+ // A method/function name may contain a prefix. We don't know it is there,
+ // however, until we encounter the first '_'.
+ bool InPossiblePrefix = true;
+ bool AtBeginning = true;
+ NamingConvention C = NoConvention;
+
+ while (*s != '\0') {
+ // Skip '_'.
+ if (*s == '_') {
+ if (InPossiblePrefix) {
+ // If we already have a convention, return it. Otherwise, skip
+ // the prefix as if it wasn't there.
+ if (C != NoConvention)
+ break;
+
+ InPossiblePrefix = false;
+ AtBeginning = true;
+ assert(C == NoConvention);
+ }
+ ++s;
+ continue;
+ }
+
+ // Skip numbers, ':', etc.
+ if (!isalpha(*s)) {
+ ++s;
+ continue;
+ }
+
+ const char *wordEnd = parseWord(s);
+ assert(wordEnd > s);
+ unsigned len = wordEnd - s;
+
+ switch (len) {
+ default:
+ break;
+ case 3:
+ // Methods starting with 'new' follow the create rule.
+ if (AtBeginning && StringRef(s, len).equals_lower("new"))
+ C = CreateRule;
+ break;
+ case 4:
+ // Methods starting with 'alloc' or contain 'copy' follow the
+ // create rule
+ if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
+ C = CreateRule;
+ else // Methods starting with 'init' follow the init rule.
+ if (AtBeginning && StringRef(s, len).equals_lower("init"))
+ C = InitRule;
+ break;
+ case 5:
+ if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
+ C = CreateRule;
+ break;
+ }
+
+ // If we aren't in the prefix and have a derived convention then just
+ // return it now.
+ if (!InPossiblePrefix && C != NoConvention)
+ return C;
+
+ AtBeginning = false;
+ s = wordEnd;
+ }
+
+ // We will get here if there wasn't more than one word
+ // after the prefix.
+ return C;
+}
+
+bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix,
+ llvm::StringRef Name) {
+ // Recursively walk the typedef stack, allowing typedefs of reference types.
+ while (TypedefType* TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) {
+ llvm::StringRef TDName = TD->getDecl()->getIdentifier()->getName();
+ if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
+ return true;
+
+ RetTy = TD->getDecl()->getUnderlyingType();
+ }
+
+ if (Name.empty())
+ return false;
+
+ // Is the type void*?
+ const PointerType* PT = RetTy->getAs<PointerType>();
+ if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
+ return false;
+
+ // Does the name start with the prefix?
+ return Name.startswith(Prefix);
+}
+
+bool cocoa::isCFObjectRef(QualType T) {
+ return isRefType(T, "CF") || // Core Foundation.
+ isRefType(T, "CG") || // Core Graphics.
+ isRefType(T, "DADisk") || // Disk Arbitration API.
+ isRefType(T, "DADissenter") ||
+ isRefType(T, "DASessionRef");
+}
+
+
+bool cocoa::isCocoaObjectRef(QualType Ty) {
+ if (!Ty->isObjCObjectPointerType())
+ return false;
+
+ const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
+
+ // Can be true for objects with the 'NSObject' attribute.
+ if (!PT)
+ return true;
+
+ // We assume that id<..>, id, and "Class" all represent tracked objects.
+ if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
+ PT->isObjCClassType())
+ return true;
+
+ // Does the interface subclass NSObject?
+ // FIXME: We can memoize here if this gets too expensive.
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
+
+ // Assume that anything declared with a forward declaration and no
+ // @interface subclasses NSObject.
+ if (ID->isForwardDecl())
+ return true;
+
+ for ( ; ID ; ID = ID->getSuperClass())
+ if (ID->getIdentifier()->getName() == "NSObject")
+ return true;
+
+ return false;
+}
diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp
index 98243874d7d9..0cbc4086701a 100644
--- a/lib/Analysis/DereferenceChecker.cpp
+++ b/lib/Checker/DereferenceChecker.cpp
@@ -12,10 +12,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/Checkers/DereferenceChecker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp
index 266c23609422..e1346e11b6fd 100644
--- a/lib/Analysis/DivZeroChecker.cpp
+++ b/lib/Checker/DivZeroChecker.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/Environment.cpp b/lib/Checker/Environment.cpp
index f04cf7b05fed..c2c9190fc9ff 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Checker/Environment.cpp
@@ -10,7 +10,7 @@
// This file defined the Environment and EnvironmentManager classes.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "llvm/ADT/ImmutableMap.h"
diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Checker/ExplodedGraph.cpp
index 3b339ffc0dfe..20429b951992 100644
--- a/lib/Analysis/ExplodedGraph.cpp
+++ b/lib/Checker/ExplodedGraph.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/AST/Stmt.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp
index 031ca44b602e..04c17d6d7abb 100644
--- a/lib/Analysis/FixedAddressChecker.cpp
+++ b/lib/Checker/FixedAddressChecker.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp
new file mode 100644
index 000000000000..dac66def5dc9
--- /dev/null
+++ b/lib/Checker/FlatStore.cpp
@@ -0,0 +1,166 @@
+//=== FlatStore.cpp - Flat region-based store model -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "llvm/ADT/ImmutableIntervalMap.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace clang;
+using llvm::Interval;
+
+// The actual store type.
+typedef llvm::ImmutableIntervalMap<SVal> BindingVal;
+typedef llvm::ImmutableMap<const MemRegion *, BindingVal> RegionBindings;
+
+namespace {
+class FlatStoreManager : public StoreManager {
+ RegionBindings::Factory RBFactory;
+ BindingVal::Factory BVFactory;
+
+public:
+ FlatStoreManager(GRStateManager &mgr)
+ : StoreManager(mgr),
+ RBFactory(mgr.getAllocator()),
+ BVFactory(mgr.getAllocator()) {}
+
+ SVal Retrieve(Store store, Loc L, QualType T);
+ Store Bind(Store store, Loc L, SVal val);
+ Store Remove(Store St, Loc L);
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl,
+ const LocationContext *LC, SVal v);
+
+ Store getInitialStore(const LocationContext *InitLoc) {
+ return RBFactory.GetEmptyMap().getRoot();
+ }
+
+ SubRegionMap *getSubRegionMap(Store store) {
+ return 0;
+ }
+
+ SVal ArrayToPointer(Loc Array);
+ Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
+ return store;
+ }
+
+ Store BindDecl(Store store, const VarRegion *VR, SVal initVal);
+
+ Store BindDeclWithNoInit(Store store, const VarRegion *VR);
+
+ typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+
+ Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS);
+
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
+ void iterBindings(Store store, BindingsHandler& f);
+
+private:
+ static RegionBindings getRegionBindings(Store store) {
+ return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
+ }
+
+ Interval RegionToInterval(const MemRegion *R);
+
+ SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T);
+};
+} // end anonymous namespace
+
+StoreManager *clang::CreateFlatStoreManager(GRStateManager &StMgr) {
+ return new FlatStoreManager(StMgr);
+}
+
+SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) {
+ const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+ Interval I = RegionToInterval(R);
+ RegionBindings B = getRegionBindings(store);
+ const BindingVal *BV = B.lookup(R);
+ if (BV) {
+ const SVal *V = BVFactory.Lookup(*BV, I);
+ if (V)
+ return *V;
+ else
+ return RetrieveRegionWithNoBinding(R, T);
+ }
+ return RetrieveRegionWithNoBinding(R, T);
+}
+
+SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R,
+ QualType T) {
+ if (R->hasStackNonParametersStorage())
+ return UndefinedVal();
+ else
+ return ValMgr.getRegionValueSymbolVal(R, T);
+}
+
+Store FlatStoreManager::Bind(Store store, Loc L, SVal val) {
+ const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+ RegionBindings B = getRegionBindings(store);
+ const BindingVal *V = B.lookup(R);
+
+ BindingVal BV = BVFactory.GetEmptyMap();
+ if (V)
+ BV = *V;
+
+ Interval I = RegionToInterval(R);
+ BV = BVFactory.Add(BV, I, val);
+ B = RBFactory.Add(B, R, BV);
+ return B.getRoot();
+}
+
+Store FlatStoreManager::Remove(Store store, Loc L) {
+ return store;
+}
+
+Store FlatStoreManager::BindCompoundLiteral(Store store,
+ const CompoundLiteralExpr* cl,
+ const LocationContext *LC,
+ SVal v) {
+ return store;
+}
+
+SVal FlatStoreManager::ArrayToPointer(Loc Array) {
+ return Array;
+}
+
+Store FlatStoreManager::BindDecl(Store store, const VarRegion *VR,
+ SVal initVal) {
+ return store;
+}
+
+Store FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR) {
+ return store;
+}
+
+Store FlatStoreManager::InvalidateRegion(Store store, const MemRegion *R,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS) {
+ return store;
+}
+
+void FlatStoreManager::print(Store store, llvm::raw_ostream& Out,
+ const char* nl, const char *sep) {
+}
+
+void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) {
+}
+
+Interval FlatStoreManager::RegionToInterval(const MemRegion *R) {
+ switch (R->getKind()) {
+ case MemRegion::VarRegionKind: {
+ QualType T = cast<VarRegion>(R)->getValueType(Ctx);
+ uint64_t Size = Ctx.getTypeSize(T);
+ return Interval(0, Size-1);
+ }
+ default:
+ llvm_unreachable("Region kind unhandled.");
+ return Interval(0, 0);
+ }
+}
diff --git a/lib/Analysis/GRBlockCounter.cpp b/lib/Checker/GRBlockCounter.cpp
index 4f4103ac45b4..3fa3e1ebb9c6 100644
--- a/lib/Analysis/GRBlockCounter.cpp
+++ b/lib/Checker/GRBlockCounter.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
+#include "clang/Checker/PathSensitive/GRBlockCounter.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index 209452a3927a..d54b0777eda7 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/AST/Expr.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 8f8d859e0ca0..7f863193743b 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -12,11 +12,10 @@
// functions and build the ExplodedGraph at the expression level.
//
//===----------------------------------------------------------------------===//
-
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
@@ -48,7 +47,7 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
}
-static QualType GetCalleeReturnType(const CallExpr *CE) {
+static QualType GetCalleeReturnType(const CallExpr *CE) {
const Expr *Callee = CE->getCallee();
QualType T = Callee->getType();
if (const PointerType *PT = T->getAs<PointerType>()) {
@@ -62,7 +61,7 @@ static QualType GetCalleeReturnType(const CallExpr *CE) {
return T;
}
-static bool CalleeReturnsReference(const CallExpr *CE) {
+static bool CalleeReturnsReference(const CallExpr *CE) {
return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
}
@@ -177,10 +176,10 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &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_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
@@ -191,7 +190,7 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
// automatically.
}
-void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
ExplodedNodeSet &Dst,
const GRState *state,
ExplodedNode *Pred) {
@@ -220,8 +219,8 @@ void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
// 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 GRExprEngine::CheckerEvalCall(const CallExpr *CE,
- ExplodedNodeSet &Dst,
+bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
ExplodedNode *Pred) {
bool Evaluated = false;
ExplodedNodeSet DstTmp;
@@ -246,21 +245,21 @@ bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
return Evaluated;
}
-// FIXME: This is largely copy-paste from CheckerVisit(). Need to
+// FIXME: This is largely copy-paste from CheckerVisit(). Need to
// unify.
void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, 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;
@@ -273,16 +272,16 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
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, AssignE, 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.
}
@@ -300,7 +299,8 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
// 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 GRExprEngine
- // object.
+ // object.
+ RegisterAdjustedReturnValueChecker(Eng);
RegisterAttrNonNullChecker(Eng);
RegisterCallAndMessageChecker(Eng);
RegisterDereferenceChecker(Eng);
@@ -311,6 +311,7 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterUndefinedArraySubscriptChecker(Eng);
RegisterUndefinedAssignmentChecker(Eng);
RegisterUndefBranchChecker(Eng);
+ RegisterUndefCapturedBlockVarChecker(Eng);
RegisterUndefResultChecker(Eng);
// This is not a checker yet.
@@ -336,7 +337,7 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
BR(mgr, *this), TF(tf) {
// Register internal checks.
RegisterInternalChecks(*this);
-
+
// FIXME: Eventually remove the TF object entirely.
TF->RegisterChecks(*this);
TF->RegisterPrinters(getStateManager().Printers);
@@ -375,7 +376,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
// FIXME: It would be nice if we had a more general mechanism to add
// such preconditions. Some day.
do {
- const Decl *D = InitLoc->getDecl();
+ const Decl *D = InitLoc->getDecl();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Precondition: the first argument of 'main' is an integer guaranteed
// to be > 0.
@@ -387,11 +388,11 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
QualType T = PD->getType();
if (!T->isIntegerType())
break;
-
+
const MemRegion *R = state->getRegion(PD, InitLoc);
if (!R)
break;
-
+
SVal V = state->getSVal(loc::MemRegionVal(R));
SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V,
ValMgr.makeZeroVal(T),
@@ -399,23 +400,23 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
DefinedOrUnknownSVal *Constraint =
dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
-
+
if (!Constraint)
break;
-
+
if (const GRState *newState = state->Assume(*Constraint, true))
state = newState;
-
+
break;
}
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
// Precondition: 'self' is always non-null upon entry to an Objective-C
// method.
const ImplicitParamDecl *SelfD = MD->getSelfDecl();
const MemRegion *R = state->getRegion(SelfD, InitLoc);
SVal V = state->getSVal(loc::MemRegionVal(R));
-
+
if (const Loc *LV = dyn_cast<Loc>(&V)) {
// Assume that the pointer value in 'self' is non-null.
state = state->Assume(*LV, true);
@@ -423,7 +424,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
}
}
} while (0);
-
+
return state;
}
@@ -434,19 +435,19 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
- bool assumption) {
+ bool assumption) {
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
I != E; ++I) {
if (!state)
- return NULL;
-
+ return NULL;
+
state = I->second->EvalAssume(state, cond, assumption);
}
-
+
if (!state)
return NULL;
-
+
return TF->EvalAssume(state, cond, assumption);
}
@@ -615,7 +616,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::AsmStmtClass:
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
-
+
case Stmt::BlockDeclRefExprClass:
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false);
break;
@@ -637,7 +638,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
- if (AMgr.shouldEagerlyAssume() &&
+ if (AMgr.shouldEagerlyAssume() &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false);
@@ -695,7 +696,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
// 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;
+ break;
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass: {
@@ -703,7 +704,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitCast(C, C->getSubExpr(), Pred, Dst, false);
break;
}
-
+
case Stmt::IfStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
@@ -775,7 +776,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::StringLiteralClass:
VisitLValue(cast<StringLiteral>(S), Pred, Dst);
break;
-
+
case Stmt::SwitchStmtClass:
// This case isn't for branch processing, but for handling the
// initialization of a condition variable.
@@ -793,18 +794,18 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitUnaryOperator(U, Pred, Dst, false);
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;
+ break;
}
}
void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
-
+
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Ex->getLocStart(),
"Error evaluating statement");
@@ -836,27 +837,27 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::CompoundAssignOperatorClass:
VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::BlockDeclRefExprClass:
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr *C = cast<CallExpr>(Ex);
assert(CalleeReturnsReferenceOrRecord(C));
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
break;
}
-
+
case Stmt::CompoundLiteralExprClass:
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
- return;
+ return;
case Stmt::DeclRefExprClass:
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass: {
CastExpr *C = cast<CastExpr>(Ex);
@@ -864,7 +865,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
VisitCast(C, C->getSubExpr(), Pred, Dst, true);
break;
}
-
+
case Stmt::MemberExprClass:
VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
return;
@@ -872,11 +873,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::ObjCIvarRefExprClass:
VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
return;
-
+
case Stmt::ObjCMessageExprClass: {
ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
assert(ReceiverReturnsReferenceOrRecord(ME));
- VisitObjCMessageExpr(ME, Pred, Dst, true);
+ VisitObjCMessageExpr(ME, Pred, Dst, true);
return;
}
@@ -911,7 +912,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::IntegerLiteralClass:
CreateCXXTemporaryObject(Ex, Pred, Dst);
return;
-
+
default:
// Arbitrary subexpressions can return aggregate temporaries that
// can be used in a lvalue context. We need to enhance our support
@@ -1083,7 +1084,7 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
SVal recovered = RecoverCastedSymbol(getStateManager(),
builder.getState(), Condition,
getContext());
-
+
if (!recovered.isUnknown()) {
X = recovered;
}
@@ -1165,7 +1166,7 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) {
void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
- assert(Ex == CurrentStmt &&
+ assert(Ex == CurrentStmt &&
Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
const GRState* state = GetState(Pred);
@@ -1203,7 +1204,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
if (CondV_untested.isUndef()) {
//ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
- // FIXME: add checker
+ // FIXME: add checker
//UndefBranches.insert(N);
return;
@@ -1247,7 +1248,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
CondV, CaseVal);
-
+
// Now "assume" that the case matches.
if (const GRState* stateNew = state->Assume(Res, true)) {
builder.generateCaseStmtNode(I, stateNew);
@@ -1271,7 +1272,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
DefaultSt = NULL;
}
}
-
+
// Concretize the next value in the range.
if (V1.Val.getInt() == V2.Val.getInt())
break;
@@ -1314,7 +1315,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
MakeNode(Dst, B, Pred, state->BindExpr(B, X));
return;
}
-
+
DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
// We took the RHS. Because the value of the '&&' or '||' expression must
@@ -1347,16 +1348,16 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+
ExplodedNodeSet Tmp;
-
+
CanQualType T = getContext().getCanonicalType(BE->getType());
SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T,
Pred->getLocationContext());
MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
ProgramPoint::PostLValueKind);
-
+
// Post-visit the BlockExpr.
CheckerVisit(BE, Dst, Tmp, false);
}
@@ -1391,7 +1392,7 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D,
else
V = UnknownVal();
}
-
+
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
ProgramPoint::PostLValueKind);
}
@@ -1494,19 +1495,19 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE,
Stmt* StoreE, ExplodedNode* Pred,
const GRState* state, SVal location, SVal Val,
bool atDeclInit) {
-
-
+
+
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet, Src;
Src.Add(Pred);
CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true);
-
+
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
-
+
if (Pred != *I)
state = GetState(*I);
-
+
const GRState* newState = 0;
if (atDeclInit) {
@@ -1565,7 +1566,7 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE,
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
ProgramPoint::PostStoreKind);
SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
-
+
// Proceed with the store.
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
@@ -1578,12 +1579,12 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
// Are we loading from a region? This actually results in two loads; one
// to fetch the address of the referenced value and one to fetch the
// referenced value.
- if (const TypedRegion *TR =
+ if (const TypedRegion *TR =
dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
-
+
QualType ValTy = TR->getValueType(getContext());
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
- static int loadReferenceTag = 0;
+ static int loadReferenceTag = 0;
ExplodedNodeSet Tmp;
EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
getContext().getPointerType(RT->getPointeeType()));
@@ -1593,11 +1594,11 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
state = GetState(*I);
location = state->getSVal(Ex);
EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
- }
+ }
return;
}
}
-
+
EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
}
@@ -1605,16 +1606,16 @@ void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex,
ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag, QualType LoadTy) {
-
+
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
if (Tmp.empty())
return;
-
+
assert(!location.isUndef());
-
+
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
SaveAndRestore<const void*> OldTag(Builder->Tag);
@@ -1627,7 +1628,7 @@ void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex,
ProgramPoint::PostLoadKind, tag);
}
else {
- SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
+ SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
Ex->getType() : LoadTy);
MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
tag);
@@ -1644,11 +1645,11 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
Dst.Add(Pred);
return;
}
-
+
ExplodedNodeSet Src, Tmp;
Src.Add(Pred);
ExplodedNodeSet *PrevSet = &Src;
-
+
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
@@ -1658,10 +1659,10 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
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
@@ -1670,7 +1671,7 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
*NI == Pred ? state : GetState(*NI),
location, tag, isLoad);
}
-
+
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
@@ -1688,7 +1689,7 @@ public:
CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
: I(i), N(n) {}
-};
+};
} // end anonymous namespace
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
@@ -1706,31 +1707,31 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
llvm::SmallVector<CallExprWLItem, 20> WorkList;
WorkList.reserve(AE - AI);
WorkList.push_back(CallExprWLItem(AI, Pred));
-
+
ExplodedNodeSet ArgsEvaluated;
while (!WorkList.empty()) {
CallExprWLItem Item = WorkList.back();
WorkList.pop_back();
-
+
if (Item.I == AE) {
ArgsEvaluated.insert(Item.N);
continue;
}
-
+
// Evaluate the argument.
ExplodedNodeSet Tmp;
const unsigned ParamIdx = Item.I - AI;
-
+
bool VisitAsLvalue = false;
if (Proto && ParamIdx < Proto->getNumArgs())
VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
+
if (VisitAsLvalue)
VisitLValue(*Item.I, Item.N, Tmp);
else
Visit(*Item.I, Item.N, Tmp);
-
+
// Enqueue evaluating the next argument on the worklist.
++(Item.I);
@@ -1741,32 +1742,32 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
// Now process the call itself.
ExplodedNodeSet DstTmp;
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);
+ Visit(Callee, *NI, DstTmp2);
// Perform the previsit of the CallExpr, storing the results in DstTmp.
CheckerVisit(CE, DstTmp, DstTmp2, true);
}
-
+
// 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) {
-
+
const GRState* state = GetState(*DI);
SVal L = state->getSVal(Callee);
-
+
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
ExplodedNodeSet DstChecker;
-
+
// If the callee is processed by a checker, skip the rest logic.
if (CheckerEvalCall(CE, DstChecker, *DI))
DstTmp3.insert(DstChecker);
@@ -1774,17 +1775,17 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
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 && "GRStmtNodeBuilder must be defined.");
+ assert(Builder && "GRStmtNodeBuilder 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 &&
@@ -1793,24 +1794,24 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
}
}
}
-
+
// Finally, perform the post-condition check of the CallExpr and store
// the created nodes in 'Dst'.
-
+
if (!(!asLValue && CalleeReturnsReference(CE))) {
CheckerVisit(CE, Dst, DstTmp3, false);
return;
}
-
+
// Handle the case where the called function returns a reference but
// we expect an rvalue. For such cases, convert the reference to
- // an rvalue.
+ // an rvalue.
// FIXME: This conversion doesn't actually happen unless the result
// of CallExpr is consumed by another expression.
ExplodedNodeSet DstTmp4;
CheckerVisit(CE, DstTmp4, DstTmp3, false);
QualType LoadTy = CE->getType();
-
+
static int *ConvertToRvalueTag = 0;
for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end();
NI!=NE; ++NI) {
@@ -1950,10 +1951,10 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
Stmt* elem = S->getElement();
ExplodedNodeSet Tmp;
EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
-
+
if (Tmp.empty())
return;
-
+
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
Pred = *NI;
const GRState *state = GetState(Pred);
@@ -1993,90 +1994,96 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
// Transfer function: Objective-C message expressions.
//===----------------------------------------------------------------------===//
+namespace {
+class ObjCMsgWLItem {
+public:
+ ObjCMessageExpr::arg_iterator I;
+ ExplodedNode *N;
+
+ ObjCMsgWLItem(const ObjCMessageExpr::arg_iterator &i, ExplodedNode *n)
+ : I(i), N(n) {}
+};
+} // end anonymous namespace
+
void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue){
- VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
- Pred, Dst, asLValue);
-}
+ // Create a worklist to process both the arguments.
+ llvm::SmallVector<ObjCMsgWLItem, 20> WL;
-void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
- ObjCMessageExpr::arg_iterator AI,
- ObjCMessageExpr::arg_iterator AE,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue) {
- if (AI == AE) {
+ // But first evaluate the receiver (if any).
+ ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
+ if (Expr *Receiver = ME->getReceiver()) {
+ ExplodedNodeSet Tmp;
+ Visit(Receiver, Pred, Tmp);
- // Process the receiver.
+ if (Tmp.empty())
+ return;
- if (Expr* Receiver = ME->getReceiver()) {
- ExplodedNodeSet Tmp;
- Visit(Receiver, Pred, Tmp);
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
+ WL.push_back(ObjCMsgWLItem(AI, *I));
+ }
+ else
+ WL.push_back(ObjCMsgWLItem(AI, Pred));
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE;
- ++NI)
- VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue);
+ // Evaluate the arguments.
+ ExplodedNodeSet ArgsEvaluated;
+ while (!WL.empty()) {
+ ObjCMsgWLItem Item = WL.back();
+ WL.pop_back();
- return;
+ if (Item.I == AE) {
+ ArgsEvaluated.insert(Item.N);
+ continue;
}
- VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(*AI, Pred, Tmp);
+ // Evaluate the subexpression.
+ ExplodedNodeSet Tmp;
- ++AI;
+ // FIXME: [Objective-C++] handle arguments that are references
+ Visit(*Item.I, Item.N, Tmp);
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
- VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue);
-}
+ // Enqueue evaluating the next argument on the worklist.
+ ++(Item.I);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ WL.push_back(ObjCMsgWLItem(Item.I, *NI));
+ }
-void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst,
- bool asLValue) {
+ // Now that the arguments are processed, handle the previsits checks.
+ ExplodedNodeSet DstPrevisit;
+ CheckerVisit(ME, DstPrevisit, ArgsEvaluated, true);
- // Handle previsits checks.
- ExplodedNodeSet Src, DstTmp;
- Src.Add(Pred);
-
- CheckerVisit(ME, DstTmp, Src, true);
-
- ExplodedNodeSet PostVisitSrc;
+ // Proceed with evaluate the message expression.
+ ExplodedNodeSet DstEval;
- for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
- DI!=DE; ++DI) {
+ for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(),
+ DE = DstPrevisit.end(); DI != DE; ++DI) {
Pred = *DI;
bool RaisesException = false;
-
- unsigned OldSize = PostVisitSrc.size();
+ unsigned OldSize = DstEval.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
if (const Expr *Receiver = ME->getReceiver()) {
const GRState *state = Pred->getState();
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal =
+ 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
+ // 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(ME, PostVisitSrc, nilState, Pred);
+ CheckerEvalNilReceiver(ME, DstEval, nilState, Pred);
continue;
}
- assert(notNilState);
-
// Check if the "raise" message was sent.
+ assert(notNilState);
if (ME->getSelector() == RaiseSel)
RaisesException = true;
@@ -2086,7 +2093,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState);
+ EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
else {
IdentifierInfo* ClsName = ME->getClassName();
@@ -2104,7 +2111,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Lazily create a cache of the selectors.
if (!NSExceptionInstanceRaiseSelectors) {
ASTContext& Ctx = getContext();
- NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
+ NSExceptionInstanceRaiseSelectors =
+ new Selector[NUM_RAISE_SELECTORS];
llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
unsigned idx = 0;
@@ -2133,36 +2141,35 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
Builder->BuildSinks = true;
// Dispatch to plug-in transfer function.
- EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred));
+ EvalObjCMessageExpr(DstEval, ME, Pred, Builder->GetState(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 && PostVisitSrc.size() == OldSize &&
+ if (!Builder->BuildSinks && DstEval.size() == OldSize &&
!Builder->HasGeneratedNode)
- MakeNode(PostVisitSrc, ME, Pred, GetState(Pred));
+ MakeNode(DstEval, ME, Pred, GetState(Pred));
}
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
if (!(!asLValue && ReceiverReturnsReference(ME))) {
- CheckerVisit(ME, Dst, PostVisitSrc, false);
+ CheckerVisit(ME, Dst, DstEval, false);
return;
}
-
+
// Handle the case where the message expression returns a reference but
// we expect an rvalue. For such cases, convert the reference to
- // an rvalue.
+ // an rvalue.
// FIXME: This conversion doesn't actually happen unless the result
// of ObjCMessageExpr is consumed by another expression.
ExplodedNodeSet DstRValueConvert;
- CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false);
+ CheckerVisit(ME, DstRValueConvert, DstEval, false);
QualType LoadTy = ME->getType();
-
+
static int *ConvertToRvalueTag = 0;
for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(),
- NE = DstRValueConvert.end();
- NI!=NE; ++NI) {
+ NE = DstRValueConvert.end(); NI != NE; ++NI) {
const GRState *state = GetState(*NI);
EvalLoad(Dst, ME, *NI, state, state->getSVal(ME),
&ConvertToRvalueTag, LoadTy);
@@ -2173,7 +2180,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
+void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst, bool asLValue) {
ExplodedNodeSet S1;
QualType T = CastE->getType();
@@ -2235,8 +2242,8 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
ExplodedNode* N = *I;
const GRState* state = GetState(N);
SVal V = state->getSVal(Ex);
- const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy);
- state = Res.getState()->BindExpr(CastE, Res.getSVal());
+ V = SVator.EvalCast(V, T, ExTy);
+ state = state->BindExpr(CastE, V);
MakeNode(Dst, CastE, N, state);
}
return;
@@ -2296,7 +2303,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet Tmp2;
CheckerVisit(DS, Tmp2, Tmp, true);
-
+
for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
ExplodedNode *N = *I;
const GRState *state = GetState(N);
@@ -2311,12 +2318,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
// UnknownVal.
if (InitVal.isUnknown() ||
!getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
-
+
EvalBind(Dst, DS, DS, *I, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
+ loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
}
else {
state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
@@ -2327,26 +2334,26 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S,
ExplodedNode *Pred, ExplodedNodeSet& Dst) {
-
- Expr* InitEx = VD->getInit();
+
+ 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 = ValMgr.getConjuredSymbolVal(NULL, InitEx,
+ InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
Builder->getCurrentBlockCount());
}
-
+
EvalBind(Dst, S, S, N, state,
loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
}
@@ -2461,12 +2468,14 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
}
else if (!T.getTypePtr()->isConstantSizeType()) {
// FIXME: Add support for VLAs.
+ Dst.Add(Pred);
return;
}
else if (T->isObjCInterfaceType()) {
// Some code tries to take the sizeof an ObjCInterfaceType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
+ Dst.Add(Pred);
return;
}
else {
@@ -2475,10 +2484,10 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
}
}
else // Get alignment of the type.
- amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8);
+ amt = getContext().getTypeAlignInChars(T);
MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex,
+ GetState(Pred)->BindExpr(Ex,
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
@@ -2567,7 +2576,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
assert(U->getType()->isIntegerType());
assert(IV.isSigned() == U->getType()->isSignedIntegerType());
- SVal X = ValMgr.makeIntVal(IV);
+ SVal X = ValMgr.makeIntVal(IV);
MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
return;
}
@@ -2715,7 +2724,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
if (V2_untested.isUnknownOrUndef()) {
MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
continue;
- }
+ }
DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
// Handle all other values.
@@ -2770,19 +2779,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
}
-void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst) {
// Get the this object region from StoreManager.
const MemRegion *R =
ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
Pred->getLocationContext());
-
+
const GRState *state = GetState(Pred);
SVal V = state->getSVal(loc::MemRegionVal(R));
MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
}
-void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
+void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
}
@@ -2808,7 +2817,7 @@ void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A,
void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
- ExplodedNode* Pred,
+ ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
if (I == E) {
@@ -2846,7 +2855,7 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+
ExplodedNodeSet Src;
if (Expr *RetE = RS->getRetValue()) {
Visit(RetE, Pred, Src);
@@ -2854,25 +2863,25 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
else {
Src.Add(Pred);
}
-
+
ExplodedNodeSet CheckedSet;
CheckerVisit(RS, CheckedSet, Src, true);
-
+
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I != E; ++I) {
assert(Builder && "GRStmtNodeBuilder must be defined.");
-
+
Pred = *I;
unsigned size = Dst.size();
-
+
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
-
+
getTF().EvalReturn(Dst, *this, *Builder, RS, Pred);
-
- // Handle the case where no nodes where generated.
- if (!Builder->BuildSinks && Dst.size() == size &&
+
+ // Handle the case where no nodes where generated.
+ if (!Builder->BuildSinks && Dst.size() == size &&
!Builder->HasGeneratedNode)
MakeNode(Dst, RS, Pred, GetState(Pred));
}
@@ -2926,7 +2935,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
QualType T = RHS->getType();
-
+
if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV))
&& (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) {
unsigned Count = Builder->getCurrentBlockCount();
@@ -2940,12 +2949,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
continue;
}
-
+
if (!B->isAssignmentOp()) {
// Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr).
SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
-
+
if (Result.isUnknown()) {
if (OldSt != state) {
// Generate a new node if we have already created a new state.
@@ -2953,12 +2962,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
}
else
Tmp3.Add(*I2);
-
+
continue;
}
-
+
state = state->BindExpr(B, Result);
-
+
MakeNode(Tmp3, B, *I2, state);
continue;
}
@@ -3004,13 +3013,11 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
QualType RTy = getContext().getCanonicalType(RHS->getType());
// Promote LHS.
- llvm::tie(state, V) = SVator.EvalCast(V, state, CLHSTy, LTy);
+ V = SVator.EvalCast(V, CLHSTy, LTy);
// Compute the result of the operation.
- SVal Result;
- llvm::tie(state, Result) = SVator.EvalCast(EvalBinOp(state, Op, V,
- RightV, CTy),
- state, B->getType(), CTy);
+ SVal Result = SVator.EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
+ B->getType(), CTy);
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
@@ -3030,12 +3037,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
LHSVal = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count);
// However, we need to convert the symbol to the computation type.
- llvm::tie(state, Result) = SVator.EvalCast(LHSVal, state, CTy, LTy);
+ Result = SVator.EvalCast(LHSVal, CTy, LTy);
}
else {
// The left-hand side may bind to a different value then the
// computation type.
- llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy);
+ LHSVal = SVator.EvalCast(Result, LTy, CTy);
}
EvalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result),
@@ -3047,24 +3054,24 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
CheckerVisit(B, Dst, Tmp3, false);
}
-void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ExplodedNodeSet Tmp;
Visit(Ex, Pred, Tmp);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
const GRState *state = GetState(*I);
-
+
// Bind the temporary object to the value of the expression. Then bind
// the expression to the location of the object.
SVal V = state->getSVal(Ex);
- const MemRegion *R =
+ const MemRegion *R =
ValMgr.getRegionManager().getCXXObjectRegion(Ex,
Pred->getLocationContext());
state = state->bindLoc(loc::MemRegionVal(R), V);
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
- }
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Checker/GRExprEngineExperimentalChecks.cpp
index 33479b0cb7e5..89b4e4b6392f 100644
--- a/lib/Analysis/GRExprEngineExperimentalChecks.cpp
+++ b/lib/Checker/GRExprEngineExperimentalChecks.cpp
@@ -14,7 +14,7 @@
#include "GRExprEngineInternalChecks.h"
#include "GRExprEngineExperimentalChecks.h"
-#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
using namespace clang;
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.h b/lib/Checker/GRExprEngineExperimentalChecks.h
index 9a9da32e556e..9a9da32e556e 100644
--- a/lib/Analysis/GRExprEngineExperimentalChecks.h
+++ b/lib/Checker/GRExprEngineExperimentalChecks.h
diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h
index e2354ed09888..64a930d504cf 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.h
+++ b/lib/Checker/GRExprEngineInternalChecks.h
@@ -19,6 +19,7 @@ namespace clang {
class GRExprEngine;
+void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng);
void RegisterAttrNonNullChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
@@ -35,8 +36,8 @@ void RegisterArrayBoundChecker(GRExprEngine &Eng);
void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
void RegisterUndefBranchChecker(GRExprEngine &Eng);
+void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng);
void RegisterUndefResultChecker(GRExprEngine &Eng);
-
void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
void RegisterOSAtomicChecker(GRExprEngine &Eng);
diff --git a/lib/Analysis/GRState.cpp b/lib/Checker/GRState.cpp
index 051d465f41b7..592f930316e1 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Checker/GRState.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/raw_ostream.h"
@@ -50,7 +50,8 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc,
state, RegionRoots);
// Clean up the store.
- StoreMgr->RemoveDeadBindings(NewState, Loc, SymReaper, RegionRoots);
+ NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, SymReaper,
+ RegionRoots);
return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState),
SymReaper);
@@ -301,7 +302,8 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
// Now look at the subregions.
if (!SRM.get())
- SRM.reset(state->getStateManager().getStoreManager().getSubRegionMap(state));
+ SRM.reset(state->getStateManager().getStoreManager().
+ getSubRegionMap(state->getStore()));
return SRM->iterSubRegions(R, *this);
}
diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp
new file mode 100644
index 000000000000..14f0fc1280df
--- /dev/null
+++ b/lib/Checker/LLVMConventionsChecker.cpp
@@ -0,0 +1,335 @@
+//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines LLVMConventionsChecker, a bunch of small little checks
+// for checking specific coding conventions in the LLVM/Clang codebase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include <string>
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Generic type checking routines.
+//===----------------------------------------------------------------------===//
+
+static bool IsLLVMStringRef(QualType T) {
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ return llvm::StringRef(QualType(RT, 0).getAsString()) ==
+ "class llvm::StringRef";
+}
+
+static bool InStdNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
+ if (!ND)
+ return false;
+ const IdentifierInfo *II = ND->getIdentifier();
+ if (!II || II->getName() != "std")
+ return false;
+ DC = ND->getDeclContext();
+ return isa<TranslationUnitDecl>(DC);
+}
+
+static bool IsStdString(QualType T) {
+ if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
+ T = QT->getNamedType();
+
+ const TypedefType *TT = T->getAs<TypedefType>();
+ if (!TT)
+ return false;
+
+ const TypedefDecl *TD = TT->getDecl();
+
+ if (!InStdNamespace(TD))
+ return false;
+
+ return TD->getName() == "string";
+}
+
+static bool InClangNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
+ if (!ND)
+ return false;
+ const IdentifierInfo *II = ND->getIdentifier();
+ if (!II || II->getName() != "clang")
+ return false;
+ DC = ND->getDeclContext();
+ return isa<TranslationUnitDecl>(DC);
+}
+
+static bool InLLVMNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
+ if (!ND)
+ return false;
+ const IdentifierInfo *II = ND->getIdentifier();
+ if (!II || II->getName() != "llvm")
+ return false;
+ DC = ND->getDeclContext();
+ return isa<TranslationUnitDecl>(DC);
+}
+
+static bool IsClangType(const RecordDecl *RD) {
+ return RD->getName() == "Type" && InClangNamespace(RD);
+}
+
+static bool IsClangDecl(const RecordDecl *RD) {
+ return RD->getName() == "Decl" && InClangNamespace(RD);
+}
+
+static bool IsClangStmt(const RecordDecl *RD) {
+ return RD->getName() == "Stmt" && InClangNamespace(RD);
+}
+
+static bool isClangAttr(const RecordDecl *RD) {
+ return RD->getName() == "Attr" && InClangNamespace(RD);
+}
+
+static bool IsStdVector(QualType T) {
+ const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
+ if (!TS)
+ return false;
+
+ TemplateName TM = TS->getTemplateName();
+ TemplateDecl *TD = TM.getAsTemplateDecl();
+
+ if (!TD || !InStdNamespace(TD))
+ return false;
+
+ return TD->getName() == "vector";
+}
+
+static bool IsSmallVector(QualType T) {
+ const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
+ if (!TS)
+ return false;
+
+ TemplateName TM = TS->getTemplateName();
+ TemplateDecl *TD = TM.getAsTemplateDecl();
+
+ if (!TD || !InLLVMNamespace(TD))
+ return false;
+
+ return TD->getName() == "SmallVector";
+}
+
+//===----------------------------------------------------------------------===//
+// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
+// lifetime is shorter than the StringRef's.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
+ BugReporter &BR;
+public:
+ StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
+ void VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
+ I != E; ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+ }
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+ void VisitDeclStmt(DeclStmt *DS);
+private:
+ void VisitVarDecl(VarDecl *VD);
+ void CheckStringRefBoundtoTemporaryString(VarDecl *VD);
+};
+} // end anonymous namespace
+
+static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
+ StringRefCheckerVisitor walker(BR);
+ walker.Visit(D->getBody());
+}
+
+void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
+ VisitChildren(S);
+
+ for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
+ if (VarDecl *VD = dyn_cast<VarDecl>(*I))
+ VisitVarDecl(VD);
+}
+
+void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
+ Expr *Init = VD->getInit();
+ if (!Init)
+ return;
+
+ // Pattern match for:
+ // llvm::StringRef x = call() (where call returns std::string)
+ if (!IsLLVMStringRef(VD->getType()))
+ return;
+ CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init);
+ if (!Ex1)
+ return;
+ CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
+ if (!Ex2 || Ex2->getNumArgs() != 1)
+ return;
+ ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
+ if (!Ex3)
+ return;
+ CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
+ if (!Ex4 || Ex4->getNumArgs() != 1)
+ return;
+ ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
+ if (!Ex5)
+ return;
+ CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
+ if (!Ex6 || !IsStdString(Ex6->getType()))
+ return;
+
+ // Okay, badness! Report an error.
+ const char *desc = "StringRef should not be bound to temporary "
+ "std::string that it outlives";
+
+ BR.EmitBasicReport(desc, "LLVM Conventions", desc,
+ VD->getLocStart(), Init->getSourceRange());
+}
+
+//===----------------------------------------------------------------------===//
+// CHECK: Clang AST nodes should not have fields that can allocate
+// memory.
+//===----------------------------------------------------------------------===//
+
+static bool AllocatesMemory(QualType T) {
+ return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
+}
+
+// This type checking could be sped up via dynamic programming.
+static bool IsPartOfAST(const CXXRecordDecl *R) {
+ if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || isClangAttr(R))
+ return true;
+
+ for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
+ E = R->bases_end(); I!=E; ++I) {
+ CXXBaseSpecifier BS = *I;
+ QualType T = BS.getType();
+ if (const RecordType *baseT = T->getAs<RecordType>()) {
+ CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
+ if (IsPartOfAST(baseD))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace {
+class ASTFieldVisitor {
+ llvm::SmallVector<FieldDecl*, 10> FieldChain;
+ CXXRecordDecl *Root;
+ BugReporter &BR;
+public:
+ ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
+ : Root(root), BR(br) {}
+
+ void Visit(FieldDecl *D);
+ void ReportError(QualType T);
+};
+} // end anonymous namespace
+
+static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
+ if (!IsPartOfAST(R))
+ return;
+
+ for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
+ I != E; ++I) {
+ ASTFieldVisitor walker(R, BR);
+ walker.Visit(*I);
+ }
+}
+
+void ASTFieldVisitor::Visit(FieldDecl *D) {
+ FieldChain.push_back(D);
+
+ QualType T = D->getType();
+
+ if (AllocatesMemory(T))
+ ReportError(T);
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I)
+ Visit(*I);
+ }
+
+ FieldChain.pop_back();
+}
+
+void ASTFieldVisitor::ReportError(QualType T) {
+ llvm::SmallString<1024> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "AST class '" << Root->getName() << "' has a field '"
+ << FieldChain.front()->getName() << "' that allocates heap memory";
+ if (FieldChain.size() > 1) {
+ os << " via the following chain: ";
+ bool isFirst = true;
+ for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
+ E=FieldChain.end(); I!=E; ++I) {
+ if (!isFirst)
+ os << '.';
+ else
+ isFirst = false;
+ os << (*I)->getName();
+ }
+ }
+ os << " (type " << FieldChain.back()->getType().getAsString() << ")";
+ os.flush();
+
+ // Note that this will fire for every translation unit that uses this
+ // class. This is suboptimal, but at least scan-build will merge
+ // duplicate HTML reports. In the future we need a unified way of merging
+ // duplicate reports across translation units. For C++ classes we cannot
+ // just report warnings when we see an out-of-line method definition for a
+ // class, as that heuristic doesn't always work (the complete definition of
+ // the class may be in the header file, for example).
+ BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
+ os.str(), FieldChain.front()->getLocStart());
+}
+
+//===----------------------------------------------------------------------===//
+// Entry point for all checks.
+//===----------------------------------------------------------------------===//
+
+static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
+ for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
+ I!=E ; ++I) {
+
+ Decl *D = *I;
+
+ if (D->getBody())
+ CheckStringRefAssignedTemporary(D, BR);
+
+ if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
+ if (R->isDefinition())
+ CheckASTMemory(R, BR);
+
+ if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
+ ScanCodeDecls(DC_child, BR);
+ }
+}
+
+void clang::CheckLLVMConventions(TranslationUnitDecl &TU,
+ BugReporter &BR) {
+ ScanCodeDecls(&TU, BR);
+}
+
diff --git a/lib/Checker/Makefile b/lib/Checker/Makefile
new file mode 100644
index 000000000000..673d152270ca
--- /dev/null
+++ b/lib/Checker/Makefile
@@ -0,0 +1,21 @@
+##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements analyses built on top of source-level CFGs.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangChecker
+BUILD_ARCHIVE = 1
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp
index 28f4db788068..4ff98642e1c2 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Checker/MallocChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineExperimentalChecks.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -172,6 +172,11 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
const GRState *state) {
SVal ArgVal = state->getSVal(CE->getArg(0));
+
+ // If ptr is NULL, no operation is preformed.
+ if (ArgVal.isZeroConstant())
+ return state;
+
SymbolRef Sym = ArgVal.getAsLocSymbol();
assert(Sym);
diff --git a/lib/Analysis/ManagerRegistry.cpp b/lib/Checker/ManagerRegistry.cpp
index 8943db2a2343..d11a997cc0f6 100644
--- a/lib/Analysis/ManagerRegistry.cpp
+++ b/lib/Checker/ManagerRegistry.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/ManagerRegistry.h"
+#include "clang/Checker/ManagerRegistry.h"
using namespace clang;
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 87d60d340934..194015a11b11 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -13,12 +13,11 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/raw_ostream.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathSensitive/ValueManager.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -682,7 +681,7 @@ const MemRegion *MemRegion::StripCasts() const {
static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition(Ctx))
+ if (!D->getDefinition())
return false;
}
@@ -760,7 +759,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
const VarDecl *VD = *I;
const VarRegion *VR = 0;
- if (!VD->getAttr<BlocksAttr>())
+ if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage())
VR = MemMgr.getVarRegion(VD, this);
else {
if (LC)
diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp
index 2ff04878f7ab..29bac9c384c2 100644
--- a/lib/Analysis/NSAutoreleasePoolChecker.cpp
+++ b/lib/Checker/NSAutoreleasePoolChecker.cpp
@@ -15,9 +15,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "BasicObjCFoundationChecks.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp
index e3cf57fd0c1b..e428e2e83f2a 100644
--- a/lib/Analysis/NSErrorChecker.cpp
+++ b/lib/Checker/NSErrorChecker.cpp
@@ -15,10 +15,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/LocalCheckers.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/Checkers/DereferenceChecker.h"
#include "BasicObjCFoundationChecks.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Checker/NoReturnFunctionChecker.cpp
index 5cfd9acd5f56..1455d87665db 100644
--- a/lib/Analysis/NoReturnFunctionChecker.cpp
+++ b/lib/Checker/NoReturnFunctionChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Checker/OSAtomicChecker.cpp
index 9d34e9ec5c8b..7f4aeca33178 100644
--- a/lib/Analysis/OSAtomicChecker.cpp
+++ b/lib/Checker/OSAtomicChecker.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/StringSwitch.h"
@@ -153,8 +153,7 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
// Handle implicit value casts.
if (const TypedRegion *R =
dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
- llvm::tie(state, val) = SVator.EvalCast(val, state,R->getValueType(Ctx),
- newValueExpr->getType());
+ val = SVator.EvalCast(val,R->getValueType(Ctx),newValueExpr->getType());
}
Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N,
diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp
index 734570a21e64..97500d95785c 100644
--- a/lib/Analysis/PathDiagnostic.cpp
+++ b/lib/Checker/PathDiagnostic.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp
index 370233ce38bd..3d62d0c7b9d7 100644
--- a/lib/Analysis/PointerArithChecker.cpp
+++ b/lib/Checker/PointerArithChecker.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp
index c597a2580751..acc848ac8edb 100644
--- a/lib/Analysis/PointerSubChecker.cpp
+++ b/lib/Checker/PointerSubChecker.cpp
@@ -13,7 +13,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Checker/PthreadLockChecker.cpp
index e95095c7975e..74e266c3edfc 100644
--- a/lib/Analysis/PthreadLockChecker.cpp
+++ b/lib/Checker/PthreadLockChecker.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "GRExprEngineExperimentalChecks.h"
#include "llvm/ADT/ImmutableSet.h"
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Checker/RangeConstraintManager.cpp
index 2cf3dfb6d0db..c904c33e08d2 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Checker/RangeConstraintManager.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Analysis/ManagerRegistry.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/ManagerRegistry.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index a735ed94578e..f70105af1379 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -14,10 +14,10 @@
// parameters are created lazily.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/MemRegion.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Support/Optional.h"
#include "clang/Basic/TargetInfo.h"
@@ -32,81 +32,55 @@ using namespace clang;
#define USE_EXPLICIT_COMPOUND 0
//===----------------------------------------------------------------------===//
-// Representation of value bindings.
+// Representation of binding keys.
//===----------------------------------------------------------------------===//
namespace {
-class BindingVal {
+class BindingKey {
public:
- enum BindingKind { Direct, Default };
+ enum Kind { Direct = 0x0, Default = 0x1 };
private:
- SVal Value;
- BindingKind Kind;
-
+ llvm ::PointerIntPair<const MemRegion*, 1> P;
+ uint64_t Offset;
+
+ explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
+ : P(r, (unsigned) k), Offset(offset) { assert(r); }
public:
- BindingVal(SVal V, BindingKind K) : Value(V), Kind(K) {}
-
- bool isDefault() const { return Kind == Default; }
-
- const SVal *getValue() const { return &Value; }
-
- const SVal *getDirectValue() const { return isDefault() ? 0 : &Value; }
-
- const SVal *getDefaultValue() const { return isDefault() ? &Value : 0; }
-
+
+ bool isDefault() const { return P.getInt() == Default; }
+ bool isDirect() const { return P.getInt() == Direct; }
+
+ const MemRegion *getRegion() const { return P.getPointer(); }
+ uint64_t getOffset() const { return Offset; }
+
void Profile(llvm::FoldingSetNodeID& ID) const {
- Value.Profile(ID);
- ID.AddInteger(Kind);
+ ID.AddPointer(P.getOpaqueValue());
+ ID.AddInteger(Offset);
}
-
- inline bool operator==(const BindingVal& R) const {
- return Value == R.Value && Kind == R.Kind;
- }
-
- inline bool operator!=(const BindingVal& R) const {
- return !(*this == R);
- }
-};
-}
-
-namespace llvm {
-static inline
-llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
- if (V.isDefault())
- os << "(default) ";
- else
- os << "(direct) ";
- os << *V.getValue();
- return os;
-}
-} // end llvm namespace
-
-//===----------------------------------------------------------------------===//
-// Representation of binding keys.
-//===----------------------------------------------------------------------===//
-
-namespace {
- class BindingKey : public std::pair<const MemRegion*, uint64_t> {
-public:
- explicit BindingKey(const MemRegion *r, uint64_t offset)
- : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); }
- const MemRegion *getRegion() const { return first; }
- uint64_t getOffset() const { return second; }
+ static BindingKey Make(const MemRegion *R, Kind k);
- void Profile(llvm::FoldingSetNodeID& ID) const {
- ID.AddPointer(getRegion());
- ID.AddInteger(getOffset());
+ bool operator<(const BindingKey &X) const {
+ if (P.getOpaqueValue() < X.P.getOpaqueValue())
+ return true;
+ if (P.getOpaqueValue() > X.P.getOpaqueValue())
+ return false;
+ return Offset < X.Offset;
+ }
+
+ bool operator==(const BindingKey &X) const {
+ return P.getOpaqueValue() == X.P.getOpaqueValue() &&
+ Offset == X.Offset;
}
-
- static BindingKey Make(const MemRegion *R);
};
} // end anonymous namespace
namespace llvm {
static inline
llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
- os << '(' << K.getRegion() << ',' << K.getOffset() << ')';
+ os << '(' << K.getRegion() << ',' << K.getOffset()
+ << ',' << (K.isDirect() ? "direct" : "default")
+ << ')';
return os;
}
} // end llvm namespace
@@ -115,7 +89,7 @@ namespace llvm {
// Actual Store type.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings;
+typedef llvm::ImmutableMap<BindingKey, SVal> RegionBindings;
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -178,9 +152,11 @@ static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) {
namespace {
class RegionStoreSubRegionMap : public SubRegionMap {
- typedef llvm::ImmutableSet<const MemRegion*> SetTy;
- typedef llvm::DenseMap<const MemRegion*, SetTy> Map;
- SetTy::Factory F;
+public:
+ typedef llvm::ImmutableSet<const MemRegion*> Set;
+ typedef llvm::DenseMap<const MemRegion*, Set> Map;
+private:
+ Set::Factory F;
Map M;
public:
bool add(const MemRegion* Parent, const MemRegion* SubRegion) {
@@ -198,6 +174,11 @@ public:
void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
~RegionStoreSubRegionMap() {}
+
+ const Set *getSubRegions(const MemRegion *Parent) const {
+ Map::const_iterator I = M.find(Parent);
+ return I == M.end() ? NULL : &I->second;
+ }
bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
Map::const_iterator I = M.find(Parent);
@@ -205,30 +186,22 @@ public:
if (I == M.end())
return true;
- llvm::ImmutableSet<const MemRegion*> S = I->second;
- for (llvm::ImmutableSet<const MemRegion*>::iterator SI=S.begin(),SE=S.end();
- SI != SE; ++SI) {
+ Set S = I->second;
+ for (Set::iterator SI=S.begin(),SE=S.end(); SI != SE; ++SI) {
if (!V.Visit(Parent, *SI))
return false;
}
return true;
}
-
- typedef SetTy::iterator iterator;
-
- std::pair<iterator, iterator> begin_end(const MemRegion *R) {
- Map::iterator I = M.find(R);
- SetTy S = I == M.end() ? F.GetEmptySet() : I->second;
- return std::make_pair(S.begin(), S.end());
- }
};
+
class RegionStoreManager : public StoreManager {
const RegionStoreFeatures Features;
RegionBindings::Factory RBFactory;
- typedef llvm::DenseMap<const GRState *, RegionStoreSubRegionMap*> SMCache;
+ typedef llvm::DenseMap<Store, RegionStoreSubRegionMap*> SMCache;
SMCache SC;
public:
@@ -242,7 +215,9 @@ public:
delete (*I).second;
}
- SubRegionMap *getSubRegionMap(const GRState *state);
+ SubRegionMap *getSubRegionMap(Store store) {
+ return getRegionStoreSubRegionMap(store);
+ }
RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store);
@@ -255,35 +230,7 @@ public:
/// setImplicitDefaultValue - Set the default binding for the provided
/// MemRegion to the value implicitly defined for compound literals when
/// the value is not specified.
- const GRState *setImplicitDefaultValue(const GRState *state,
- const MemRegion *R,
- QualType T);
-
- /// getLValueString - Returns an SVal representing the lvalue of a
- /// StringLiteral. Within RegionStore a StringLiteral has an
- /// associated StringRegion, and the lvalue of a StringLiteral is
- /// the lvalue of that region.
- SVal getLValueString(const StringLiteral* S);
-
- /// getLValueCompoundLiteral - Returns an SVal representing the
- /// lvalue of a compound literal. Within RegionStore a compound
- /// literal has an associated region, and the lvalue of the
- /// compound literal is the lvalue of that region.
- SVal getLValueCompoundLiteral(const CompoundLiteralExpr*);
-
- /// getLValueVar - Returns an SVal that represents the lvalue of a
- /// variable. Within RegionStore a variable has an associated
- /// VarRegion, and the lvalue of the variable is the lvalue of that region.
- SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
-
- SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
-
- SVal getLValueField(const FieldDecl* D, SVal Base);
-
- SVal getLValueFieldOrIvar(const Decl* D, SVal Base);
-
- SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
-
+ Store setImplicitDefaultValue(Store store, const MemRegion *R, QualType T);
/// ArrayToPointer - Emulates the "decay" of an array to a pointer
/// type. 'Array' represents the lvalue of the array being decayed
@@ -293,8 +240,7 @@ public:
/// casts from arrays to pointers.
SVal ArrayToPointer(Loc Array);
- SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,
- NonLoc R, QualType resultTy);
+ SVal EvalBinOp(BinaryOperator::Opcode Op,Loc L, NonLoc R, QualType resultTy);
Store getInitialStore(const LocationContext *InitLoc) {
return RBFactory.GetEmptyMap().getRoot();
@@ -304,52 +250,57 @@ public:
// Binding values to regions.
//===-------------------------------------------------------------------===//
- const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS) {
- return RegionStoreManager::InvalidateRegions(state, &R, &R+1, E, Count, IS);
+ Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS) {
+ return RegionStoreManager::InvalidateRegions(store, &R, &R+1, E, Count, IS);
}
- const GRState *InvalidateRegions(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- const Expr *E, unsigned Count,
- InvalidatedSymbols *IS);
+ Store InvalidateRegions(Store store,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
-private:
+public: // Made public for helper classes.
+
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
RegionStoreSubRegionMap &M);
- RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V);
- RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V);
+ RegionBindings Add(RegionBindings B, BindingKey K, SVal V);
+
+ RegionBindings Add(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k, SVal V);
- const BindingVal *Lookup(RegionBindings B, BindingKey K);
- const BindingVal *Lookup(RegionBindings B, const MemRegion *R);
+ const SVal *Lookup(RegionBindings B, BindingKey K);
+ const SVal *Lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k);
RegionBindings Remove(RegionBindings B, BindingKey K);
- RegionBindings Remove(RegionBindings B, const MemRegion *R);
+ RegionBindings Remove(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k);
+
+ RegionBindings Remove(RegionBindings B, const MemRegion *R) {
+ return Remove(Remove(B, R, BindingKey::Direct), R, BindingKey::Default);
+ }
+
Store Remove(Store store, BindingKey K);
-public:
- const GRState *Bind(const GRState *state, Loc LV, SVal V);
+public: // Part of public interface to class.
- const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL,
- const LocationContext *LC,
- SVal V);
+ Store Bind(Store store, Loc LV, SVal V);
- const GRState *BindDecl(const GRState *ST, const VarRegion *VR,
- SVal InitVal);
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
+ const LocationContext *LC, SVal V);
- const GRState *BindDeclWithNoInit(const GRState *state,
- const VarRegion *) {
- return state;
+ Store BindDecl(Store store, const VarRegion *VR, SVal InitVal);
+
+ Store BindDeclWithNoInit(Store store, const VarRegion *) {
+ return store;
}
/// BindStruct - Bind a compound value to a structure.
- const GRState *BindStruct(const GRState *, const TypedRegion* R, SVal V);
+ Store BindStruct(Store store, const TypedRegion* R, SVal V);
- const GRState *BindArray(const GRState *state, const TypedRegion* R, SVal V);
+ Store BindArray(Store store, const TypedRegion* R, SVal V);
/// KillStruct - Set the entire struct to unknown.
Store KillStruct(Store store, const TypedRegion* R);
@@ -372,20 +323,19 @@ public:
/// return undefined
/// else
/// return symbolic
- SValuator::CastResult Retrieve(const GRState *state, Loc L,
- QualType T = QualType());
+ SVal Retrieve(Store store, Loc L, QualType T = QualType());
- SVal RetrieveElement(const GRState *state, const ElementRegion *R);
+ SVal RetrieveElement(Store store, const ElementRegion *R);
- SVal RetrieveField(const GRState *state, const FieldRegion *R);
+ SVal RetrieveField(Store store, const FieldRegion *R);
- SVal RetrieveObjCIvar(const GRState *state, const ObjCIvarRegion *R);
+ SVal RetrieveObjCIvar(Store store, const ObjCIvarRegion *R);
- SVal RetrieveVar(const GRState *state, const VarRegion *R);
+ SVal RetrieveVar(Store store, const VarRegion *R);
- SVal RetrieveLazySymbol(const GRState *state, const TypedRegion *R);
+ SVal RetrieveLazySymbol(const TypedRegion *R);
- SVal RetrieveFieldOrElementCommon(const GRState *state, const TypedRegion *R,
+ SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R,
QualType Ty, const MemRegion *superR);
/// Retrieve the values in a struct and return a CompoundVal, used when doing
@@ -393,20 +343,18 @@ public:
/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
- SVal RetrieveStruct(const GRState *St, const TypedRegion* R);
+ SVal RetrieveStruct(Store store, const TypedRegion* R);
- SVal RetrieveArray(const GRState *St, const TypedRegion* R);
+ SVal RetrieveArray(Store store, const TypedRegion* R);
/// Get the state and region whose binding this region R corresponds to.
- std::pair<const GRState*, const MemRegion*>
+ std::pair<Store, const MemRegion*>
GetLazyBinding(RegionBindings B, const MemRegion *R);
- const GRState* CopyLazyBindings(nonloc::LazyCompoundVal V,
- const GRState *state,
- const TypedRegion *R);
+ Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
+ const TypedRegion *R);
- const ElementRegion *GetElementZeroRegion(const SymbolicRegion *SR,
- QualType T);
+ const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
//===------------------------------------------------------------------===//
// State pruning.
@@ -414,7 +362,7 @@ public:
/// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
- void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper,
+ Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
const GRState *EnterStackFrame(const GRState *state,
@@ -500,10 +448,6 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
return M;
}
-SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) {
- return getRegionStoreSubRegionMap(state->getStore());
-}
-
//===----------------------------------------------------------------------===//
// Binding invalidation.
//===----------------------------------------------------------------------===//
@@ -511,258 +455,227 @@ SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) {
void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
const MemRegion *R,
RegionStoreSubRegionMap &M) {
- RegionStoreSubRegionMap::iterator I, E;
-
- for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
- RemoveSubRegionBindings(B, *I, M);
+
+ if (const RegionStoreSubRegionMap::Set *S = M.getSubRegions(R))
+ for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end();
+ I != E; ++I)
+ RemoveSubRegionBindings(B, *I, M);
B = Remove(B, R);
}
-const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
- const MemRegion * const *I,
- const MemRegion * const *E,
- const Expr *Ex,
- unsigned Count,
- InvalidatedSymbols *IS) {
- ASTContext& Ctx = StateMgr.getContext();
-
- // Get the mapping of regions -> subregions.
- llvm::OwningPtr<RegionStoreSubRegionMap>
- SubRegions(getRegionStoreSubRegionMap(state->getStore()));
+namespace {
+class InvalidateRegionsWorker {
+ typedef BumpVector<BindingKey> RegionCluster;
+ typedef llvm::DenseMap<const MemRegion *, RegionCluster *> ClusterMap;
+ typedef llvm::SmallVector<std::pair<const MemRegion *,RegionCluster*>, 10>
+ WorkList;
+
+ BumpVectorContext BVC;
+ ClusterMap ClusterM;
+ WorkList WL;
- RegionBindings B = GetRegionBindings(state->getStore());
-
- llvm::DenseMap<const MemRegion *, unsigned> Visited;
- llvm::SmallVector<const MemRegion *, 10> WorkList;
+ RegionStoreManager &RM;
+ StoreManager::InvalidatedSymbols *IS;
+ ASTContext &Ctx;
+ ValueManager &ValMgr;
- for ( ; I != E; ++I) {
- // Strip away casts.
- WorkList.push_back((*I)->StripCasts());
+public:
+ InvalidateRegionsWorker(RegionStoreManager &rm,
+ StoreManager::InvalidatedSymbols *is,
+ ASTContext &ctx, ValueManager &valMgr)
+ : RM(rm), IS(is), Ctx(ctx), ValMgr(valMgr) {}
+
+ Store InvalidateRegions(Store store, const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count);
+
+private:
+ void AddToWorkList(BindingKey K);
+ void AddToWorkList(const MemRegion *R);
+ void AddToCluster(BindingKey K);
+ RegionCluster **getCluster(const MemRegion *R);
+ void VisitBinding(SVal V);
+};
+}
+
+void InvalidateRegionsWorker::AddToCluster(BindingKey K) {
+ const MemRegion *R = K.getRegion();
+ const MemRegion *baseR = R->getBaseRegion();
+ RegionCluster **CPtr = getCluster(baseR);
+ assert(*CPtr);
+ (*CPtr)->push_back(K, BVC);
+}
+
+void InvalidateRegionsWorker::AddToWorkList(BindingKey K) {
+ AddToWorkList(K.getRegion());
+}
+
+void InvalidateRegionsWorker::AddToWorkList(const MemRegion *R) {
+ const MemRegion *baseR = R->getBaseRegion();
+ RegionCluster **CPtr = getCluster(baseR);
+ if (RegionCluster *C = *CPtr) {
+ WL.push_back(std::make_pair(baseR, C));
+ *CPtr = NULL;
+ }
+}
+
+InvalidateRegionsWorker::RegionCluster **
+InvalidateRegionsWorker::getCluster(const MemRegion *R) {
+ RegionCluster *&CRef = ClusterM[R];
+ if (!CRef) {
+ void *Mem = BVC.getAllocator().Allocate<RegionCluster>();
+ CRef = new (Mem) RegionCluster(BVC, 10);
}
+ return &CRef;
+}
+
+void InvalidateRegionsWorker::VisitBinding(SVal V) {
+ // A symbol? Mark it touched by the invalidation.
+ if (IS)
+ if (SymbolRef Sym = V.getAsSymbol())
+ IS->insert(Sym);
- while (!WorkList.empty()) {
- const MemRegion *R = WorkList.back();
- WorkList.pop_back();
-
- // Have we visited this region before?
- unsigned &visited = Visited[R];
- if (visited)
- continue;
- visited = 1;
+ if (const MemRegion *R = V.getAsRegion()) {
+ AddToWorkList(R);
+ return;
+ }
+
+ // Is it a LazyCompoundVal? All references get invalidated as well.
+ if (const nonloc::LazyCompoundVal *LCS =
+ dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ const MemRegion *LazyR = LCS->getRegion();
+ RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+
+ for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+ const MemRegion *baseR = RI.getKey().getRegion();
+ if (cast<SubRegion>(baseR)->isSubRegionOf(LazyR))
+ VisitBinding(RI.getData());
+ }
- // Add subregions to work list.
- RegionStoreSubRegionMap::iterator I, E;
- for (llvm::tie(I, E) = SubRegions->begin_end(R); I!=E; ++I)
- WorkList.push_back(*I);
+ return;
+ }
+}
- // Get the old binding. Is it a region? If so, add it to the worklist.
- if (Optional<SVal> V = getDirectBinding(B, R)) {
- if (const MemRegion *RV = V->getAsRegion())
- WorkList.push_back(RV);
+Store InvalidateRegionsWorker::InvalidateRegions(Store store,
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count)
+{
+ RegionBindings B = RegionStoreManager::GetRegionBindings(store);
+
+ // Scan the entire store and make the region clusters.
+ for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) {
+ AddToCluster(RI.getKey());
+ if (const MemRegion *R = RI.getData().getAsRegion()) {
+ // Generate a cluster, but don't add the region to the cluster
+ // if there aren't any bindings.
+ getCluster(R->getBaseRegion());
+ }
+ }
+
+ // Add the cluster for I .. E to a worklist.
+ for ( ; I != E; ++I)
+ AddToWorkList(*I);
+
+ while (!WL.empty()) {
+ const MemRegion *baseR;
+ RegionCluster *C;
+ llvm::tie(baseR, C) = WL.back();
+ WL.pop_back();
+
+ for (RegionCluster::iterator I = C->begin(), E = C->end(); I != E; ++I) {
+ BindingKey K = *I;
- // A symbol? Mark it touched by the invalidation.
- if (IS) {
- if (SymbolRef Sym = V->getAsSymbol())
- IS->insert(Sym);
- }
+ // Get the old binding. Is it a region? If so, add it to the worklist.
+ if (const SVal *V = RM.Lookup(B, K))
+ VisitBinding(*V);
+
+ B = RM.Remove(B, K);
}
+
+ // Now inspect the base region.
- // Symbolic region? Mark that symbol touched by the invalidation.
if (IS) {
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ // Symbolic region? Mark that symbol touched by the invalidation.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
IS->insert(SR->getSymbol());
}
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
- if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
for (BlockDataRegion::referenced_vars_iterator
- I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ;
- I != E; ++I) {
- const VarRegion *VR = *I;
- if (VR->getDecl()->getAttr<BlocksAttr>())
- WorkList.push_back(VR);
+ BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ;
+ BI != BE; ++BI) {
+ const VarRegion *VR = *BI;
+ const VarDecl *VD = VR->getDecl();
+ if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+ AddToWorkList(VR);
}
continue;
}
-
- // Handle the region itself.
- if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) {
+
+ if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
- DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy,
Count);
- B = Add(B, R, BindingVal(V, BindingVal::Default));
+ B = RM.Add(B, baseR, BindingKey::Default, V);
continue;
}
-
- if (!R->isBoundable())
- continue;
-
- const TypedRegion *TR = cast<TypedRegion>(R);
+
+ if (!baseR->isBoundable())
+ continue;
+
+ const TypedRegion *TR = cast<TypedRegion>(baseR);
QualType T = TR->getValueType(Ctx);
-
- if (const RecordType *RT = T->getAsStructureType()) {
- const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);
+ // Invalidate the binding.
+ if (const RecordType *RT = T->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
// No record definition. There is nothing we can do.
- if (!RD)
+ if (!RD) {
+ B = RM.Remove(B, baseR);
continue;
+ }
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
- DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy,
Count);
- B = Add(B, R, BindingVal(V, BindingVal::Default));
+ B = RM.Add(B, baseR, BindingKey::Default, V);
continue;
- }
-
+ }
+
if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
- ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
- B = Add(B, R, BindingVal(V, BindingVal::Default));
+ ValMgr.getConjuredSymbolVal(baseR, Ex, AT->getElementType(), Count);
+ B = RM.Add(B, baseR, BindingKey::Default, V);
continue;
}
-
- if ((isa<FieldRegion>(R)||isa<ElementRegion>(R)||isa<ObjCIvarRegion>(R))
- && Visited[cast<SubRegion>(R)->getSuperRegion()]) {
- // For fields and elements whose super region has also been invalidated,
- // only remove the old binding. The super region will get set with a
- // default value from which we can lazily derive a new symbolic value.
- B = Remove(B, R);
- continue;
- }
-
- // Invalidate the binding.
- DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
+
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, T, Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
- B = Add(B, R, BindingVal(V, BindingVal::Direct));
+ B = RM.Add(B, baseR, BindingKey::Direct, V);
}
// Create a new state with the updated bindings.
- return state->makeWithStore(B.getRoot());
-}
-
-//===----------------------------------------------------------------------===//
-// getLValueXXX methods.
-//===----------------------------------------------------------------------===//
-
-/// getLValueString - Returns an SVal representing the lvalue of a
-/// StringLiteral. Within RegionStore a StringLiteral has an
-/// associated StringRegion, and the lvalue of a StringLiteral is the
-/// lvalue of that region.
-SVal RegionStoreManager::getLValueString(const StringLiteral* S) {
- return loc::MemRegionVal(MRMgr.getStringRegion(S));
-}
-
-/// getLValueVar - Returns an SVal that represents the lvalue of a
-/// variable. Within RegionStore a variable has an associated
-/// VarRegion, and the lvalue of the variable is the lvalue of that region.
-SVal RegionStoreManager::getLValueVar(const VarDecl *VD,
- const LocationContext *LC) {
- return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC));
-}
-
-SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
- return getLValueFieldOrIvar(D, Base);
-}
-
-SVal RegionStoreManager::getLValueField(const FieldDecl* D, SVal Base) {
- return getLValueFieldOrIvar(D, Base);
-}
-
-SVal RegionStoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
- if (Base.isUnknownOrUndef())
- return Base;
-
- Loc BaseL = cast<Loc>(Base);
- const MemRegion* BaseR = 0;
-
- switch (BaseL.getSubKind()) {
- case loc::MemRegionKind:
- BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
- break;
-
- case loc::GotoLabelKind:
- // These are anormal cases. Flag an undefined value.
- return UndefinedVal();
-
- case loc::ConcreteIntKind:
- // While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
- // like this work properly: &(((struct foo *) 0xa)->f)
- return Base;
-
- default:
- assert(0 && "Unhandled Base.");
- return Base;
- }
-
- // NOTE: We must have this check first because ObjCIvarDecl is a subclass
- // of FieldDecl.
- if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D))
- return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR));
-
- return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
+ return B.getRoot();
}
-SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset,
- SVal Base) {
-
- // If the base is an unknown or undefined value, just return it back.
- // FIXME: For absolute pointer addresses, we just return that value back as
- // well, although in reality we should return the offset added to that
- // value.
- if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
- return Base;
-
- // Only handle integer offsets... for now.
- if (!isa<nonloc::ConcreteInt>(Offset))
- return UnknownVal();
-
- const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
-
- // Pointer of any type can be cast and used as array base.
- const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
-
- // Convert the offset to the appropriate size and signedness.
- Offset = ValMgr.convertToArrayIndex(Offset);
-
- if (!ElemR) {
- //
- // If the base region is not an ElementRegion, create one.
- // This can happen in the following example:
- //
- // char *p = __builtin_alloc(10);
- // p[1] = 8;
- //
- // Observe that 'p' binds to an AllocaRegion.
- //
- return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
- BaseRegion, getContext()));
- }
-
- SVal BaseIdx = ElemR->getIndex();
-
- if (!isa<nonloc::ConcreteInt>(BaseIdx))
- return UnknownVal();
-
- const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
- const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
- assert(BaseIdxI.isSigned());
-
- // Compute the new index.
- SVal NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
-
- // Construct the new ElementRegion.
- const MemRegion *ArrayR = ElemR->getSuperRegion();
- return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
- getContext()));
+Store RegionStoreManager::InvalidateRegions(Store store,
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count,
+ InvalidatedSymbols *IS) {
+ InvalidateRegionsWorker W(*this, IS, getContext(),
+ StateMgr.getValueManager());
+ return W.InvalidateRegions(store, I, E, Ex, Count);
}
-
+
//===----------------------------------------------------------------------===//
// Extents for regions.
//===----------------------------------------------------------------------===//
@@ -885,8 +798,7 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
// Pointer arithmetic.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::EvalBinOp(const GRState *state,
- BinaryOperator::Opcode Op, Loc L, NonLoc R,
+SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R,
QualType resultTy) {
// Assume the base location is MemRegionVal.
if (!isa<loc::MemRegionVal>(L))
@@ -989,33 +901,33 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
//===----------------------------------------------------------------------===//
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
- const MemRegion *R) {
- if (const BindingVal *BV = Lookup(B, R))
- return Optional<SVal>::create(BV->getDirectValue());
-
+ const MemRegion *R) {
+ if (const SVal *V = Lookup(B, R, BindingKey::Direct))
+ return *V;
+
return Optional<SVal>();
}
Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
const MemRegion *R) {
-
if (R->isBoundable())
if (const TypedRegion *TR = dyn_cast<TypedRegion>(R))
if (TR->getValueType(getContext())->isUnionType())
return UnknownVal();
- if (const BindingVal *V = Lookup(B, R))
- return Optional<SVal>::create(V->getDefaultValue());
+ if (const SVal *V = Lookup(B, R, BindingKey::Default))
+ return *V;
return Optional<SVal>();
}
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = Lookup(B, R))
- return Optional<SVal>::create(BV->getValue());
-
- return Optional<SVal>();
+
+ if (Optional<SVal> V = getDirectBinding(B, R))
+ return V;
+
+ return getDefaultBinding(B, R);
}
static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
@@ -1042,42 +954,29 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
}
const ElementRegion *
-RegionStoreManager::GetElementZeroRegion(const SymbolicRegion *SR, QualType T) {
+RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) {
ASTContext &Ctx = getContext();
SVal idx = ValMgr.makeZeroArrayIndex();
assert(!T.isNull());
- return MRMgr.getElementRegion(T, idx, SR, Ctx);
+ return MRMgr.getElementRegion(T, idx, R, Ctx);
}
-
-
-
-SValuator::CastResult
-RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
+SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
// FIXME: Is this even possible? Shouldn't this be treated as a null
// dereference at a higher level?
if (isa<loc::ConcreteInt>(L))
- return SValuator::CastResult(state, UndefinedVal());
+ return UndefinedVal();
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
- // FIXME: return symbolic value for these cases.
- // Example:
- // void f(int* p) { int x = *p; }
- // char* p = alloca();
- // read(p);
- // c = *p;
- if (isa<AllocaRegion>(MR))
- return SValuator::CastResult(state, UnknownVal());
-
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
- MR = GetElementZeroRegion(SR, T);
+ if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR))
+ MR = GetElementZeroRegion(MR, T);
if (isa<CodeTextRegion>(MR))
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
// instead of 'Loc', and have the other Loc cases handled at a higher level.
@@ -1105,23 +1004,21 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
#endif
if (RTy->isStructureType())
- return SValuator::CastResult(state, RetrieveStruct(state, R));
+ return RetrieveStruct(store, R);
// FIXME: Handle unions.
if (RTy->isUnionType())
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
if (RTy->isArrayType())
- return SValuator::CastResult(state, RetrieveArray(state, R));
+ return RetrieveArray(store, R);
// FIXME: handle Vector types.
if (RTy->isVectorType())
- return SValuator::CastResult(state, UnknownVal());
+ return UnknownVal();
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveField(state, FR), FR,
- T, false));
+ return CastRetrievedVal(RetrieveField(store, FR), FR, T, false);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
// FIXME: Here we actually perform an implicit conversion from the loaded
@@ -1129,9 +1026,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// more intelligently. For example, an 'element' can encompass multiple
// bound regions (e.g., several bound bytes), or could be a subset of
// a larger value.
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveElement(state, ER),
- ER, T, false));
+ return CastRetrievedVal(RetrieveElement(store, ER), ER, T, false);
}
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
@@ -1141,9 +1036,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// reinterpretted, it is possible we stored a different value that could
// fit within the ivar. Either we need to cast these when storing them
// or reinterpret them lazily (as we do here).
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveObjCIvar(state, IVR),
- IVR, T, false));
+ return CastRetrievedVal(RetrieveObjCIvar(store, IVR), IVR, T, false);
}
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
@@ -1153,18 +1046,15 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// variable is reinterpretted, it is possible we stored a different value
// that could fit within the variable. Either we need to cast these when
// storing them or reinterpret them lazily (as we do here).
- return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveVar(state, VR), VR, T,
- false));
+ return CastRetrievedVal(RetrieveVar(store, VR), VR, T, false);
}
- RegionBindings B = GetRegionBindings(state->getStore());
- const BindingVal *V = Lookup(B, R);
+ RegionBindings B = GetRegionBindings(store);
+ const SVal *V = Lookup(B, R, BindingKey::Direct);
// Check if the region has a binding.
if (V)
- if (SVal const *SV = V->getValue())
- return SValuator::CastResult(state, *SV);
+ return *V;
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
@@ -1174,44 +1064,45 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
// to specific values.
- return SValuator::CastResult(state, UndefinedVal());
+ return UndefinedVal();
}
// All other values are symbolic.
- return SValuator::CastResult(state, ValMgr.getRegionValueSymbolVal(R, RTy));
+ return ValMgr.getRegionValueSymbolVal(R, RTy);
}
-std::pair<const GRState*, const MemRegion*>
+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->getState(), V->getRegion());
+ return std::make_pair(V->getStore(), V->getRegion());
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- const std::pair<const GRState *, const MemRegion *> &X =
+ const std::pair<Store, const MemRegion *> &X =
GetLazyBinding(B, ER->getSuperRegion());
- if (X.first)
+ if (X.second)
return std::make_pair(X.first,
MRMgr.getElementRegionWithSuper(ER, X.second));
}
else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
- const std::pair<const GRState *, const MemRegion *> &X =
+ const std::pair<Store, const MemRegion *> &X =
GetLazyBinding(B, FR->getSuperRegion());
- if (X.first)
+ if (X.second)
return std::make_pair(X.first,
MRMgr.getFieldRegionWithSuper(FR, X.second));
}
-
- return std::make_pair((const GRState*) 0, (const MemRegion *) 0);
+ // 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);
}
-SVal RegionStoreManager::RetrieveElement(const GRState* state,
+SVal RegionStoreManager::RetrieveElement(Store store,
const ElementRegion* R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
@@ -1256,29 +1147,29 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
dyn_cast<nonloc::LazyCompoundVal>(V)) {
R = MRMgr.getElementRegionWithSuper(R, LCV->getRegion());
- return RetrieveElement(LCV->getState(), R);
+ return RetrieveElement(LCV->getStore(), R);
}
// Other cases: give up.
return UnknownVal();
}
- return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
+ return RetrieveFieldOrElementCommon(store, R, R->getElementType(), superR);
}
-SVal RegionStoreManager::RetrieveField(const GRState* state,
+SVal RegionStoreManager::RetrieveField(Store store,
const FieldRegion* R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
QualType Ty = R->getValueType(getContext());
- return RetrieveFieldOrElementCommon(state, R, Ty, R->getSuperRegion());
+ return RetrieveFieldOrElementCommon(store, R, Ty, R->getSuperRegion());
}
-SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
+SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
const TypedRegion *R,
QualType Ty,
const MemRegion *superR) {
@@ -1286,7 +1177,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
// At this point we have already checked in either RetrieveElement or
// RetrieveField if 'R' has a direct binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
while (superR) {
if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
@@ -1313,18 +1204,14 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
}
// Lazy binding?
- const GRState *lazyBindingState = NULL;
+ Store lazyBindingStore = NULL;
const MemRegion *lazyBindingRegion = NULL;
- llvm::tie(lazyBindingState, lazyBindingRegion) = GetLazyBinding(B, R);
-
- if (lazyBindingState) {
- assert(lazyBindingRegion && "Lazy-binding region not set");
-
- if (isa<ElementRegion>(R))
- return RetrieveElement(lazyBindingState,
- cast<ElementRegion>(lazyBindingRegion));
+ llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R);
- return RetrieveField(lazyBindingState,
+ if (lazyBindingRegion) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
+ return RetrieveElement(lazyBindingStore, ER);
+ return RetrieveField(lazyBindingStore,
cast<FieldRegion>(lazyBindingRegion));
}
@@ -1345,11 +1232,10 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
return ValMgr.getRegionValueSymbolVal(R, Ty);
}
-SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
- const ObjCIvarRegion* R) {
+SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
@@ -1365,30 +1251,42 @@ SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
return UnknownVal();
}
- return RetrieveLazySymbol(state, R);
+ return RetrieveLazySymbol(R);
}
-SVal RegionStoreManager::RetrieveVar(const GRState *state,
- const VarRegion *R) {
+SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
// Lazily derive a value for the VarRegion.
const VarDecl *VD = R->getDecl();
+ QualType T = VD->getType();
+ const MemSpaceRegion *MS = R->getMemorySpace();
+
+ if (isa<UnknownSpaceRegion>(MS) ||
+ isa<StackArgumentsSpaceRegion>(MS))
+ return ValMgr.getRegionValueSymbolVal(R, T);
- if (R->hasGlobalsOrParametersStorage() ||
- isa<UnknownSpaceRegion>(R->getMemorySpace()))
- return ValMgr.getRegionValueSymbolVal(R, VD->getType());
+ if (isa<GlobalsSpaceRegion>(MS)) {
+ if (VD->isFileVarDecl())
+ return ValMgr.getRegionValueSymbolVal(R, T);
+ if (T->isIntegerType())
+ return ValMgr.makeIntVal(0, T);
+ if (T->isPointerType())
+ return ValMgr.makeNull();
+
+ return UnknownVal();
+ }
+
return UndefinedVal();
}
-SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state,
- const TypedRegion *R) {
+SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
QualType valTy = R->getValueType(getContext());
@@ -1396,8 +1294,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state,
return ValMgr.getRegionValueSymbolVal(R, valTy);
}
-SVal RegionStoreManager::RetrieveStruct(const GRState *state,
- const TypedRegion* R) {
+SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
@@ -1417,18 +1314,17 @@ SVal RegionStoreManager::RetrieveStruct(const GRState *state,
Field != FieldEnd; ++Field) {
FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
QualType FTy = (*Field)->getType();
- SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy).getSVal();
+ SVal FieldValue = Retrieve(store, loc::MemRegionVal(FR), FTy).getSVal();
StructVal = getBasicVals().consVals(FieldValue, StructVal);
}
return ValMgr.makeCompoundVal(T, StructVal);
#else
- return ValMgr.makeLazyCompoundVal(state, R);
+ return ValMgr.makeLazyCompoundVal(store, R);
#endif
}
-SVal RegionStoreManager::RetrieveArray(const GRState *state,
- const TypedRegion * R) {
+SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) {
#if USE_EXPLICIT_COMPOUND
QualType T = R->getValueType(getContext());
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
@@ -1440,14 +1336,14 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R,
getContext());
QualType ETy = ER->getElementType();
- SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy).getSVal();
+ SVal ElementVal = Retrieve(store, loc::MemRegionVal(ER), ETy).getSVal();
ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
}
return ValMgr.makeCompoundVal(T, ArrayVal);
#else
assert(isa<ConstantArrayType>(R->getValueType(getContext())));
- return ValMgr.makeLazyCompoundVal(state, R);
+ return ValMgr.makeLazyCompoundVal(store, R);
#endif
}
@@ -1458,14 +1354,14 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
Store RegionStoreManager::Remove(Store store, Loc L) {
if (isa<loc::MemRegionVal>(L))
if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
- return Remove(store, BindingKey::Make(R));
+ return Remove(GetRegionBindings(store), R).getRoot();
return store;
}
-const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
+Store RegionStoreManager::Bind(Store store, Loc L, SVal V) {
if (isa<loc::ConcreteInt>(L))
- return state;
+ return store;
// If we get here, the location should be a region.
const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
@@ -1473,7 +1369,7 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
// Check if the region is a struct region.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
if (TR->getValueType(getContext())->isStructureType())
- return BindStruct(state, TR, V);
+ return BindStruct(store, TR, V);
// Special case: the current region represents a cast and it and the super
// region both have pointer types or intptr_t types. If so, perform the
@@ -1490,14 +1386,13 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
if (IsAnyPointerOrIntptr(superTy, Ctx) &&
IsAnyPointerOrIntptr(erTy, Ctx)) {
- SValuator::CastResult cr =
- ValMgr.getSValuator().EvalCast(V, state, superTy, erTy);
- return Bind(cr.getState(), loc::MemRegionVal(superR), cr.getSVal());
+ V = ValMgr.getSValuator().EvalCast(V, superTy, erTy);
+ return Bind(store, loc::MemRegionVal(superR), V);
}
// For now, just invalidate the fields of the struct/union/class.
// FIXME: Precisely handle the fields of the record.
if (superTy->isRecordType())
- return InvalidateRegion(state, superR, NULL, 0, NULL);
+ return InvalidateRegion(store, superR, NULL, 0, NULL);
}
}
}
@@ -1516,39 +1411,35 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
}
// Perform the binding.
- RegionBindings B = GetRegionBindings(state->getStore());
- return state->makeWithStore(Add(B, R,
- BindingVal(V, BindingVal::Direct)).getRoot());
+ RegionBindings B = GetRegionBindings(store);
+ return Add(B, R, BindingKey::Direct, V).getRoot();
}
-const GRState *RegionStoreManager::BindDecl(const GRState *ST,
- const VarRegion *VR,
- SVal InitVal) {
+Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
+ SVal InitVal) {
QualType T = VR->getDecl()->getType();
if (T->isArrayType())
- return BindArray(ST, VR, InitVal);
+ return BindArray(store, VR, InitVal);
if (T->isStructureType())
- return BindStruct(ST, VR, InitVal);
+ return BindStruct(store, VR, InitVal);
- return Bind(ST, ValMgr.makeLoc(VR), InitVal);
+ return Bind(store, ValMgr.makeLoc(VR), InitVal);
}
// FIXME: this method should be merged into Bind().
-const GRState *
-RegionStoreManager::BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr *CL,
- const LocationContext *LC,
- SVal V) {
- return Bind(state, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
+Store RegionStoreManager::BindCompoundLiteral(Store store,
+ const CompoundLiteralExpr *CL,
+ const LocationContext *LC,
+ SVal V) {
+ return Bind(store, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
V);
}
-const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
- const MemRegion *R,
- QualType T) {
- Store store = state->getStore();
+Store RegionStoreManager::setImplicitDefaultValue(Store store,
+ const MemRegion *R,
+ QualType T) {
RegionBindings B = GetRegionBindings(store);
SVal V;
@@ -1562,23 +1453,24 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy);
}
else {
- return state;
+ return store;
}
- return state->makeWithStore(Add(B, R,
- BindingVal(V, BindingVal::Default)).getRoot());
+ return Add(B, R, BindingKey::Default, V).getRoot();
}
-const GRState *RegionStoreManager::BindArray(const GRState *state,
- const TypedRegion* R,
- SVal Init) {
-
- QualType T = R->getValueType(getContext());
- ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
- QualType ElementTy = CAT->getElementType();
-
- uint64_t size = CAT->getSize().getZExtValue();
-
+Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
+ SVal Init) {
+
+ ASTContext &Ctx = getContext();
+ const ArrayType *AT =
+ cast<ArrayType>(Ctx.getCanonicalType(R->getValueType(Ctx)));
+ QualType ElementTy = AT->getElementType();
+ Optional<uint64_t> Size;
+
+ if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT))
+ Size = CAT->getSize().getZExtValue();
+
// Check if the init expr is a StringLiteral.
if (isa<loc::MemRegionVal>(Init)) {
const MemRegion* InitR = cast<loc::MemRegionVal>(Init).getRegion();
@@ -1590,6 +1482,11 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
// Copy bytes from the string literal into the target array. Trailing bytes
// in the array that are not covered by the string literal are initialized
// to zero.
+
+ // We assume that string constants are bound to
+ // constant arrays.
+ uint64_t size = Size.getValue();
+
for (uint64_t i = 0; i < size; ++i, ++j) {
if (j >= len)
break;
@@ -1599,26 +1496,26 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
getContext());
SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true);
- state = Bind(state, loc::MemRegionVal(ER), V);
+ store = Bind(store, loc::MemRegionVal(ER), V);
}
- return state;
+ return store;
}
// Handle lazy compound values.
if (nonloc::LazyCompoundVal *LCV = dyn_cast<nonloc::LazyCompoundVal>(&Init))
- return CopyLazyBindings(*LCV, state, R);
+ return CopyLazyBindings(*LCV, store, R);
// Remaining case: explicit compound values.
if (Init.isUnknown())
- return setImplicitDefaultValue(state, R, ElementTy);
+ return setImplicitDefaultValue(store, R, ElementTy);
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
- for (; i < size; ++i, ++VI) {
+ for (; Size.hasValue() ? i < Size.getValue() : true ; ++i, ++VI) {
// The init list might be shorter than the array length.
if (VI == VE)
break;
@@ -1626,27 +1523,25 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
SVal Idx = ValMgr.makeArrayIndex(i);
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
- if (CAT->getElementType()->isStructureType())
- state = BindStruct(state, ER, *VI);
+ if (ElementTy->isStructureType())
+ store = BindStruct(store, ER, *VI);
else
- // FIXME: Do we need special handling of nested arrays?
- state = Bind(state, ValMgr.makeLoc(ER), *VI);
+ store = Bind(store, ValMgr.makeLoc(ER), *VI);
}
// If the init list is shorter than the array length, set the
// array default value.
- if (i < size)
- state = setImplicitDefaultValue(state, R, ElementTy);
+ if (Size.hasValue() && i < Size.getValue())
+ store = setImplicitDefaultValue(store, R, ElementTy);
- return state;
+ return store;
}
-const GRState *
-RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
- SVal V) {
+Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
+ SVal V) {
if (!Features.supportsFields())
- return state;
+ return store;
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
@@ -1655,16 +1550,16 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
RecordDecl* RD = RT->getDecl();
if (!RD->isDefinition())
- return state;
+ return store;
// Handle lazy compound values.
if (const nonloc::LazyCompoundVal *LCV=dyn_cast<nonloc::LazyCompoundVal>(&V))
- return CopyLazyBindings(*LCV, state, R);
+ return CopyLazyBindings(*LCV, store, R);
// We may get non-CompoundVal accidentally due to imprecise cast logic.
// Ignore them and kill the field values.
if (V.isUnknown() || !isa<nonloc::CompoundVal>(V))
- return state->makeWithStore(KillStruct(state->getStore(), R));
+ return KillStruct(store, R);
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
@@ -1680,22 +1575,21 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
if (FTy->isArrayType())
- state = BindArray(state, FR, *VI);
+ store = BindArray(store, FR, *VI);
else if (FTy->isStructureType())
- state = BindStruct(state, FR, *VI);
+ store = BindStruct(store, FR, *VI);
else
- state = Bind(state, ValMgr.makeLoc(FR), *VI);
+ store = Bind(store, ValMgr.makeLoc(FR), *VI);
}
// There may be fewer values in the initialize list than the fields of struct.
if (FI != FE) {
- Store store = state->getStore();
RegionBindings B = GetRegionBindings(store);
- B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
- state = state->makeWithStore(B.getRoot());
+ B = Add(B, R, BindingKey::Default, ValMgr.makeIntVal(0, false));
+ store = B.getRoot();
}
- return state;
+ return store;
}
Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
@@ -1705,74 +1599,70 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
RemoveSubRegionBindings(B, R, *SubRegions);
// Set the default value of the struct region to "unknown".
- B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
-
- return B.getRoot();
+ return Add(B, R, BindingKey::Default, UnknownVal()).getRoot();
}
-const GRState*
-RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
- const GRState *state,
- const TypedRegion *R) {
+Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
+ Store store, const TypedRegion *R) {
// Nuke the old bindings stemming from R.
- RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings B = GetRegionBindings(store);
llvm::OwningPtr<RegionStoreSubRegionMap>
- SubRegions(getRegionStoreSubRegionMap(state->getStore()));
+ SubRegions(getRegionStoreSubRegionMap(store));
// B and DVM are updated after the call to RemoveSubRegionBindings.
RemoveSubRegionBindings(B, R, *SubRegions.get());
// Now copy the bindings. This amounts to just binding 'V' to 'R'. This
// results in a zero-copy algorithm.
- return state->makeWithStore(Add(B, R,
- BindingVal(V, BindingVal::Direct)).getRoot());
+ return Add(B, R, BindingKey::Direct, V).getRoot();
}
//===----------------------------------------------------------------------===//
// "Raw" retrievals and bindings.
//===----------------------------------------------------------------------===//
-BindingKey BindingKey::Make(const MemRegion *R) {
+BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
const RegionRawOffset &O = ER->getAsRawOffset();
if (O.getRegion())
- return BindingKey(O.getRegion(), O.getByteOffset());
+ return BindingKey(O.getRegion(), O.getByteOffset(), k);
// FIXME: There are some ElementRegions for which we cannot compute
// raw offsets yet, including regions with symbolic offsets.
}
- return BindingKey(R, 0);
+ return BindingKey(R, 0, k);
}
-RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K,
- BindingVal V) {
+RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K, SVal V) {
return RBFactory.Add(B, K, V);
}
RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R,
- BindingVal V) {
- return Add(B, BindingKey::Make(R), V);
+ BindingKey::Kind k, SVal V) {
+ return Add(B, BindingKey::Make(R, k), V);
}
-const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
+const SVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
return B.lookup(K);
}
-const BindingVal *RegionStoreManager::Lookup(RegionBindings B,
- const MemRegion *R) {
- return Lookup(B, BindingKey::Make(R));
+const SVal *RegionStoreManager::Lookup(RegionBindings B,
+ const MemRegion *R,
+ BindingKey::Kind k) {
+ return Lookup(B, BindingKey::Make(R, k));
}
RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) {
return RBFactory.Remove(B, K);
}
-RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){
- return Remove(B, BindingKey::Make(R));
+RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k){
+ return Remove(B, BindingKey::Make(R, k));
}
Store RegionStoreManager::Remove(Store store, BindingKey K) {
@@ -1784,13 +1674,12 @@ Store RegionStoreManager::Remove(Store store, BindingKey K) {
// State pruning.
//===----------------------------------------------------------------------===//
-void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
- SymbolReaper& SymReaper,
+Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
+ SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
{
- typedef std::pair<const GRState*, const MemRegion *> RBDNode;
+ typedef std::pair<Store, const MemRegion *> RBDNode;
- Store store = state.getStore();
RegionBindings B = GetRegionBindings(store);
// The backmap from regions to subregions.
@@ -1825,7 +1714,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
if (SymReaper.isLive(Loc, VR))
- WorkList.push_back(std::make_pair(&state, VR));
+ WorkList.push_back(std::make_pair(store, VR));
continue;
}
@@ -1833,7 +1722,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
llvm::SmallVectorImpl<RBDNode> &Q =
SymReaper.isLive(SR->getSymbol()) ? WorkList : Postponed;
- Q.push_back(std::make_pair(&state, SR));
+ Q.push_back(std::make_pair(store, SR));
continue;
}
@@ -1847,7 +1736,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Enqueue the RegionRoots onto WorkList.
for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(),
E=RegionRoots.end(); I!=E; ++I) {
- WorkList.push_back(std::make_pair(&state, *I));
+ WorkList.push_back(std::make_pair(store, *I));
}
RegionRoots.clear();
@@ -1864,23 +1753,24 @@ tryAgain:
Visited.insert(N);
const MemRegion *R = N.second;
- const GRState *state_N = N.first;
+ Store store_N = N.first;
// Enqueue subregions.
RegionStoreSubRegionMap *M;
- if (&state == state_N)
+ if (store == store_N)
M = SubRegions.get();
else {
- RegionStoreSubRegionMap *& SM = SC[state_N];
+ RegionStoreSubRegionMap *& SM = SC[store_N];
if (!SM)
- SM = getRegionStoreSubRegionMap(state_N->getStore());
+ SM = getRegionStoreSubRegionMap(store_N);
M = SM;
}
-
- RegionStoreSubRegionMap::iterator I, E;
- for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I)
- WorkList.push_back(std::make_pair(state_N, *I));
+
+ if (const RegionStoreSubRegionMap::Set *S = M->getSubRegions(R))
+ for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end();
+ I != E; ++I)
+ WorkList.push_back(std::make_pair(store_N, *I));
// Enqueue the super region.
if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
@@ -1891,7 +1781,7 @@ tryAgain:
// pointer arithmetic can get us to the other fields or elements.
assert(isa<FieldRegion>(R) || isa<ElementRegion>(R)
|| isa<ObjCIvarRegion>(R));
- WorkList.push_back(std::make_pair(state_N, superR));
+ WorkList.push_back(std::make_pair(store_N, superR));
}
}
@@ -1908,14 +1798,13 @@ tryAgain:
RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
RI != RE; ++RI) {
if ((*RI)->getDecl()->getAttr<BlocksAttr>())
- WorkList.push_back(std::make_pair(state_N, *RI));
+ WorkList.push_back(std::make_pair(store_N, *RI));
}
// No possible data bindings on a BlockDataRegion. Continue to the
// next region in the worklist.
continue;
}
- Store store_N = state_N->getStore();
RegionBindings B_N = GetRegionBindings(store_N);
// Get the data binding for R (if any).
@@ -1927,7 +1816,7 @@ tryAgain:
dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) {
const LazyCompoundValData *D = LCV->getCVData();
- WorkList.push_back(std::make_pair(D->getState(), D->getRegion()));
+ WorkList.push_back(std::make_pair(D->getStore(), D->getRegion()));
}
else {
// Update the set of live symbols.
@@ -1937,7 +1826,7 @@ tryAgain:
// If V is a region, then add it to the worklist.
if (const MemRegion *RX = V->getAsRegion())
- WorkList.push_back(std::make_pair(state_N, RX));
+ WorkList.push_back(std::make_pair(store_N, RX));
}
}
}
@@ -1960,27 +1849,27 @@ tryAgain:
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
+ Store new_store = store;
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey().getRegion();
// If this region live? Is so, none of its symbols are dead.
- if (Visited.count(std::make_pair(&state, R)))
+ if (Visited.count(std::make_pair(store, R)))
continue;
// Remove this dead region from the store.
- store = Remove(store, I.getKey());
+ new_store = Remove(new_store, I.getKey());
// Mark all non-live symbols that this region references as dead.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.maybeDead(SymR->getSymbol());
- SVal X = *I.getData().getValue();
+ SVal X = I.getData();
SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
for (; SI != SE; ++SI)
SymReaper.maybeDead(*SI);
}
- // Write the store back.
- state.setStore(store);
+ return new_store;
}
GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
@@ -1993,12 +1882,13 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
// Copy the arg expression value to the arg variables.
+ Store store = state->getStore();
for (; AI != AE; ++AI, ++PI) {
SVal ArgVal = state->getSVal(*AI);
- state = Bind(state, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
+ store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
}
- return state;
+ return state->makeWithStore(store);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp
index b0350cb576ff..949ded507c5b 100644
--- a/lib/Analysis/ReturnPointerRangeChecker.cpp
+++ b/lib/Checker/ReturnPointerRangeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/ReturnStackAddressChecker.cpp b/lib/Checker/ReturnStackAddressChecker.cpp
new file mode 100644
index 000000000000..9cbabba4a5f5
--- /dev/null
+++ b/lib/Checker/ReturnStackAddressChecker.cpp
@@ -0,0 +1,125 @@
+//== ReturnStackAddressChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ReturnStackAddressChecker, which is a path-sensitive
+// check which looks for the addresses of stack variables being returned to
+// callers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class ReturnStackAddressChecker :
+ public CheckerVisitor<ReturnStackAddressChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnStackAddressChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+private:
+ void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
+};
+}
+
+void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnStackAddressChecker());
+}
+
+void *ReturnStackAddressChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnStackAddressChecker::EmitStackError(CheckerContext &C,
+ const MemRegion *R,
+ const Expr *RetE) {
+ ExplodedNode *N = C.GenerateSink();
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Return of address to stack-allocated memory");
+
+ // Generate a report for this bug.
+ llvm::SmallString<512> buf;
+ llvm::raw_svector_ostream os(buf);
+ SourceRange range;
+
+ // Get the base region, stripping away fields and elements.
+ R = R->getBaseRegion();
+
+ // Check if the region is a compound literal.
+ if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
+ const CompoundLiteralExpr* CL = CR->getLiteralExpr();
+ os << "Address of stack memory associated with a compound literal "
+ "declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart())
+ << " returned to caller";
+ range = CL->getSourceRange();
+ }
+ else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
+ const Expr* ARE = AR->getExpr();
+ SourceLocation L = ARE->getLocStart();
+ range = ARE->getSourceRange();
+ os << "Address of stack memory allocated by call to alloca() on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
+ else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ const BlockDecl *BD = BR->getCodeRegion()->getDecl();
+ SourceLocation L = BD->getLocStart();
+ range = BD->getSourceRange();
+ os << "Address of stack-allocated block declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
+ else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ os << "Address of stack memory associated with local variable '"
+ << VR->getString() << "' returned";
+ range = VR->getDecl()->getSourceRange();
+ }
+ else {
+ assert(false && "Invalid region in ReturnStackAddressChecker.");
+ return;
+ }
+
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ report->addRange(RetE->getSourceRange());
+ if (range.isValid())
+ report->addRange(range);
+
+ C.EmitReport(report);
+}
+
+void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
+ const ReturnStmt *RS) {
+
+ const Expr *RetE = RS->getRetValue();
+ if (!RetE)
+ return;
+
+ SVal V = C.getState()->getSVal(RetE);
+ const MemRegion *R = V.getAsRegion();
+
+ if (!R || !R->hasStackStorage())
+ return;
+
+ if (R->hasStackStorage()) {
+ EmitStackError(C, R, RetE);
+ return;
+ }
+}
diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp
index 7cd71265805b..ee259883e48c 100644
--- a/lib/Analysis/ReturnUndefChecker.cpp
+++ b/lib/Checker/ReturnUndefChecker.cpp
@@ -14,9 +14,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
diff --git a/lib/Analysis/SVals.cpp b/lib/Checker/SVals.cpp
index fbdb73b0ef2e..28b3fce050bb 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Checker/SVals.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Basic/IdentifierTable.h"
using namespace clang;
@@ -153,8 +153,8 @@ void SVal::symbol_iterator::expand() {
assert(false && "unhandled expansion case");
}
-const GRState *nonloc::LazyCompoundVal::getState() const {
- return static_cast<const LazyCompoundValData*>(Data)->getState();
+const void *nonloc::LazyCompoundVal::getStore() const {
+ return static_cast<const LazyCompoundValData*>(Data)->getStore();
}
const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
@@ -299,7 +299,7 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
}
case nonloc::LazyCompoundValKind: {
const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
- os << "lazyCompoundVal{" << (void*) C.getState() << ',' << C.getRegion()
+ os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion()
<< '}';
break;
}
diff --git a/lib/Analysis/SValuator.cpp b/lib/Checker/SValuator.cpp
index 8392fcf65a2c..542fc1b1078d 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Checker/SValuator.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/SValuator.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/SValuator.h"
+#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
@@ -53,25 +53,29 @@ DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST,
ValMgr.getContext().IntTy));
}
-SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
- QualType castTy, QualType originalTy){
-
+SVal SValuator::EvalCast(SVal val, QualType castTy, QualType originalTy) {
if (val.isUnknownOrUndef() || castTy == originalTy)
- return CastResult(state, val);
+ return val;
ASTContext &C = ValMgr.getContext();
// For const casts, just propagate the value.
if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
if (C.hasSameUnqualifiedType(castTy, originalTy))
- return CastResult(state, val);
+ return val;
+ // Check for casts to real or complex numbers. We don't handle these at all
+ // right now.
+ if (castTy->isFloatingType() || castTy->isAnyComplexType())
+ return UnknownVal();
+
+ // Check for casts from integers to integers.
if (castTy->isIntegerType() && originalTy->isIntegerType())
- return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy));
+ return EvalCastNL(cast<NonLoc>(val), castTy);
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
- return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+ return EvalCastL(cast<Loc>(val), castTy);
// Check for casts from integers to pointers.
if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
@@ -79,10 +83,9 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
if (const MemRegion *R = LV->getLoc().getAsRegion()) {
StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager();
R = storeMgr.CastRegion(R, castTy);
- return R ? CastResult(state, loc::MemRegionVal(R))
- : CastResult(state, UnknownVal());
+ return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
}
- return CastResult(state, LV->getLoc());
+ return LV->getLoc();
}
goto DispatchCast;
}
@@ -90,7 +93,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// Just pass through function and block pointers.
if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) {
assert(Loc::IsLocType(castTy));
- return CastResult(state, val);
+ return val;
}
// Check for casts from array type to another type.
@@ -101,7 +104,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// Are we casting from an array to a pointer? If so just pass on
// the decayed value.
if (castTy->isPointerType())
- return CastResult(state, val);
+ return val;
// Are we casting from an array to an integer? If so, cast the decayed
// pointer value to an integer.
@@ -111,7 +114,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// need the original decayed type.
// QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
// QualType pointerTy = C.getPointerType(elemTy);
- return CastResult(state, EvalCastL(cast<Loc>(val), castTy));
+ return EvalCastL(cast<Loc>(val), castTy);
}
// Check for casts from a region to a specific type.
@@ -144,21 +147,11 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
// different type. If the MemRegion* returned is NULL, this expression
// evaluates to UnknownVal.
R = storeMgr.CastRegion(R, castTy);
- return R ? CastResult(state, loc::MemRegionVal(R))
- : CastResult(state, UnknownVal());
+ return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
}
DispatchCast:
// All other cases.
- return CastResult(state,
- isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
- : EvalCastNL(cast<NonLoc>(val), castTy));
-}
-
-SValuator::DefinedOrUnknownCastResult
-SValuator::EvalCast(DefinedOrUnknownSVal V, const GRState *ST,
- QualType castTy, QualType originalType) {
- SValuator::CastResult X = EvalCast((SVal) V, ST, castTy, originalType);
- return DefinedOrUnknownCastResult(X.getState(),
- cast<DefinedOrUnknownSVal>(X.getSVal()));
+ return isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy)
+ : EvalCastNL(cast<NonLoc>(val), castTy);
}
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Checker/SimpleConstraintManager.cpp
index eca20d574db3..8c423a99777d 100644
--- a/lib/Analysis/SimpleConstraintManager.cpp
+++ b/lib/Checker/SimpleConstraintManager.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "SimpleConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/Checker.h"
namespace clang {
diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Checker/SimpleConstraintManager.h
index 818239831948..5f20e0072b20 100644
--- a/lib/Analysis/SimpleConstraintManager.h
+++ b/lib/Checker/SimpleConstraintManager.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H
#define LLVM_CLANG_ANALYSIS_SIMPLE_CONSTRAINT_MANAGER_H
-#include "clang/Analysis/PathSensitive/ConstraintManager.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/ConstraintManager.h"
+#include "clang/Checker/PathSensitive/GRState.h"
namespace clang {
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp
index 8f2f5a1b134c..fb1d74a99046 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Checker/SimpleSValuator.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/SValuator.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/SValuator.h"
+#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
@@ -423,6 +423,6 @@ SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
}
// Delegate pointer arithmetic to the StoreManager.
- return state->getStateManager().getStoreManager().EvalBinOp(state, op, lhs,
+ return state->getStateManager().getStoreManager().EvalBinOp(op, lhs,
rhs, resultTy);
}
diff --git a/lib/Analysis/Store.cpp b/lib/Checker/Store.cpp
index 1724a9250c25..e524cb3d7cc3 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Checker/Store.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Store.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/Store.h"
+#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/AST/CharUnits.h"
using namespace clang;
StoreManager::StoreManager(GRStateManager &stateMgr)
: ValMgr(stateMgr.getValueManager()), StateMgr(stateMgr),
- MRMgr(ValMgr.getRegionManager()) {}
+ MRMgr(ValMgr.getRegionManager()), Ctx(stateMgr.getContext()) {}
const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
QualType EleTy, uint64_t index) {
@@ -31,7 +31,7 @@ const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition(Ctx))
+ if (!D->getDefinition())
return false;
}
@@ -224,27 +224,104 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
return V;
}
-const GRState *StoreManager::InvalidateRegions(const GRState *state,
- const MemRegion * const *I,
- const MemRegion * const *End,
- const Expr *E,
- unsigned Count,
- InvalidatedSymbols *IS) {
+Store StoreManager::InvalidateRegions(Store store,
+ const MemRegion * const *I,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS) {
for ( ; I != End ; ++I)
- state = InvalidateRegion(state, *I, E, Count, IS);
+ store = InvalidateRegion(store, *I, E, Count, IS);
- return state;
+ return store;
}
-//===----------------------------------------------------------------------===//
-// Common getLValueXXX methods.
-//===----------------------------------------------------------------------===//
+SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
+ if (Base.isUnknownOrUndef())
+ return Base;
+
+ Loc BaseL = cast<Loc>(Base);
+ const MemRegion* BaseR = 0;
+
+ switch (BaseL.getSubKind()) {
+ case loc::MemRegionKind:
+ BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+ break;
+
+ case loc::GotoLabelKind:
+ // These are anormal cases. Flag an undefined value.
+ return UndefinedVal();
+
+ case loc::ConcreteIntKind:
+ // While these seem funny, this can happen through casts.
+ // FIXME: What we should return is the field offset. For example,
+ // add the field offset to the integer value. That way funny things
+ // like this work properly: &(((struct foo *) 0xa)->f)
+ return Base;
+
+ default:
+ assert(0 && "Unhandled Base.");
+ return Base;
+ }
+
+ // NOTE: We must have this check first because ObjCIvarDecl is a subclass
+ // of FieldDecl.
+ if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D))
+ return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR));
+
+ return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
+}
+
+SVal StoreManager::getLValueElement(QualType elementType, SVal Offset,
+ SVal Base) {
+
+ // If the base is an unknown or undefined value, just return it back.
+ // FIXME: For absolute pointer addresses, we just return that value back as
+ // well, although in reality we should return the offset added to that
+ // value.
+ if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
+ return Base;
+
+ // Only handle integer offsets... for now.
+ if (!isa<nonloc::ConcreteInt>(Offset))
+ return UnknownVal();
+
+ const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
+
+ // Pointer of any type can be cast and used as array base.
+ const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
+
+ // Convert the offset to the appropriate size and signedness.
+ Offset = ValMgr.convertToArrayIndex(Offset);
+
+ if (!ElemR) {
+ //
+ // If the base region is not an ElementRegion, create one.
+ // This can happen in the following example:
+ //
+ // char *p = __builtin_alloc(10);
+ // p[1] = 8;
+ //
+ // Observe that 'p' binds to an AllocaRegion.
+ //
+ return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
+ BaseRegion, Ctx));
+ }
+
+ SVal BaseIdx = ElemR->getIndex();
+
+ if (!isa<nonloc::ConcreteInt>(BaseIdx))
+ return UnknownVal();
+
+ const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
+ const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
+ assert(BaseIdxI.isSigned());
+
+ // Compute the new index.
+ SVal NewIdx = nonloc::ConcreteInt(
+ ValMgr.getBasicValueFactory().getValue(BaseIdxI + OffI));
-/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
-/// of a compound literal. Within RegionStore a compound literal
-/// has an associated region, and the lvalue of the compound literal
-/// is the lvalue of that region.
-SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
- const LocationContext *LC) {
- return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+ // Construct the new ElementRegion.
+ const MemRegion *ArrayR = ElemR->getSuperRegion();
+ return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
+ Ctx));
}
diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp
index 3fe36b064e3d..40bdcf65bca4 100644
--- a/lib/Analysis/SymbolManager.cpp
+++ b/lib/Checker/SymbolManager.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/SymbolManager.h"
-#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Analysis/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp
index c739d1ac4b22..e047b187b108 100644
--- a/lib/Analysis/UndefBranchChecker.cpp
+++ b/lib/Checker/UndefBranchChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/Checker.h"
using namespace clang;
diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp
new file mode 100644
index 000000000000..a8d7284b40ac
--- /dev/null
+++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp
@@ -0,0 +1,101 @@
+// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker detects blocks that capture uninitialized values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+class UndefCapturedBlockVarChecker
+ : public CheckerVisitor<UndefCapturedBlockVarChecker> {
+ BugType *BT;
+
+public:
+ UndefCapturedBlockVarChecker() : BT(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefCapturedBlockVarChecker());
+}
+
+static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
+ const VarDecl *VD){
+ if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S))
+ if (BR->getDecl() == VD)
+ return BR;
+
+ for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+ I!=E; ++I)
+ if (const Stmt *child = *I) {
+ const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD);
+ if (BR)
+ return BR;
+ }
+
+ return NULL;
+}
+
+void
+UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
+ const BlockExpr *BE) {
+ if (!BE->hasBlockDeclRefExprs())
+ return;
+
+ const GRState *state = C.getState();
+ const BlockDataRegion *R =
+ cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+
+ BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+ E = R->referenced_vars_end();
+
+ for (; I != E; ++I) {
+ // This VarRegion is the region associated with the block; we need
+ // the one associated with the encompassing context.
+ const VarRegion *VR = *I;
+ const VarDecl *VD = VR->getDecl();
+
+ if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+ continue;
+
+ // Get the VarRegion associated with VD in the local stack frame.
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ VR = C.getValueManager().getRegionManager().getVarRegion(VD, LC);
+
+ if (state->getSVal(VR).isUndef())
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT)
+ BT = new BuiltinBug("Captured block variable is uninitialized");
+
+ // Generate a bug report.
+ llvm::SmallString<128> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "Variable '" << VD->getName() << "' is captured by block with "
+ "a garbage value";
+
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+ if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
+ R->addRange(Ex->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerFindLastStore, VR);
+ // need location of block
+ C.EmitReport(R);
+ }
+ }
+}
diff --git a/lib/Analysis/UndefResultChecker.cpp b/lib/Checker/UndefResultChecker.cpp
index acc86dda5a97..fb2283a62044 100644
--- a/lib/Analysis/UndefResultChecker.cpp
+++ b/lib/Checker/UndefResultChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Checker/UndefinedArraySubscriptChecker.cpp
index d6aacaf1f85e..a2792ad17ba1 100644
--- a/lib/Analysis/UndefinedArraySubscriptChecker.cpp
+++ b/lib/Checker/UndefinedArraySubscriptChecker.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp
index 4630b823a91e..7c33c1d39235 100644
--- a/lib/Analysis/UndefinedAssignmentChecker.cpp
+++ b/lib/Checker/UndefinedAssignmentChecker.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp
index 2690d6f0cffc..51ad1e2daf5e 100644
--- a/lib/Analysis/VLASizeChecker.cpp
+++ b/lib/Checker/VLASizeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Checker/ValueManager.cpp
index d09137330cb2..5359489a2299 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Checker/ValueManager.cpp
@@ -13,8 +13,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/ValueManager.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Checker/PathSensitive/ValueManager.h"
+#include "clang/Analysis/AnalysisContext.h"
using namespace clang;
using namespace llvm;
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index ca5b6fa97c26..46b62441d6e4 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -13,6 +13,7 @@
#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
+#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
@@ -176,7 +177,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// block literal.
// __invoke
CharUnits subBlockSize;
- uint64_t subBlockAlign;
+ CharUnits subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::Function *Fn
@@ -249,7 +250,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
llvm::AllocaInst *A = CreateTempAlloca(Ty);
- A->setAlignment(subBlockAlign);
+ A->setAlignment(subBlockAlign.getQuantity());
V = A;
std::vector<HelperInfo> NoteForHelper(subBlockDeclRefDecls.size());
@@ -355,7 +356,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
}
QualType BPT = BE->getType();
- return Builder.CreateBitCast(V, ConvertType(BPT));
+ V = Builder.CreateBitCast(V, ConvertType(BPT));
+ // See if this is a __weak block variable and the must call objc_read_weak
+ // on it.
+ const FunctionType *ftype = BPT->getPointeeType()->getAs<FunctionType>();
+ QualType RES = ftype->getResultType();
+ if (RES.isObjCGCWeak()) {
+ // Must cast argument to id*
+ const llvm::Type *ObjectPtrTy =
+ ConvertType(CGM.getContext().getObjCIdType());
+ const llvm::Type *PtrObjectPtrTy =
+ llvm::PointerType::getUnqual(ObjectPtrTy);
+ V = Builder.CreateBitCast(V, PtrObjectPtrTy);
+ V = CGM.getObjCRuntime().EmitObjCWeakRead(*this, V);
+ }
+ return V;
}
@@ -496,10 +511,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
// Load the function.
llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
- QualType ResultType = FnType->getAs<FunctionType>()->getResultType();
+ const FunctionType *FuncTy = FnType->getAs<FunctionType>();
+ QualType ResultType = FuncTy->getResultType();
const CGFunctionInfo &FnInfo =
- CGM.getTypes().getFunctionInfo(ResultType, Args);
+ CGM.getTypes().getFunctionInfo(ResultType, Args, FuncTy->getCallConv(),
+ FuncTy->getNoReturnAttr());
// Cast the function pointer to the right type.
const llvm::Type *BlockFTy =
@@ -593,8 +610,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Block literal size. For global blocks we just use the size of the generic
// block literal struct.
- CharUnits BlockLiteralSize = CharUnits::fromQuantity(
- TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8);
+ CharUnits BlockLiteralSize =
+ CGM.GetTargetTypeStoreSize(getGenericBlockLiteralType());
DescriptorFields[1] =
llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity());
@@ -615,7 +632,7 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
CodeGenFunction::BlockInfo Info(0, n);
CharUnits subBlockSize;
- uint64_t subBlockAlign;
+ CharUnits subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
@@ -678,7 +695,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
CharUnits &Size,
- uint64_t &Align,
+ CharUnits &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose) {
@@ -698,13 +715,14 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
LocalDeclMap[VD] = i->second;
}
- BlockOffset = CharUnits::fromQuantity(
- CGM.getTargetData()
- .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8);
- BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ BlockOffset =
+ CGM.GetTargetTypeStoreSize(CGM.getGenericBlockLiteralType());
+ BlockAlign = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
QualType ResultType;
+ CallingConv CC = BlockFunctionType->getCallConv();
+ bool NoReturn = BlockFunctionType->getNoReturnAttr();
bool IsVariadic;
if (const FunctionProtoType *FTy =
dyn_cast<FunctionProtoType>(BlockFunctionType)) {
@@ -743,7 +761,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
Args.push_back(std::make_pair(*i, (*i)->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(ResultType, Args);
+ CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
@@ -777,10 +795,9 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
if (CGDebugInfo *DI = getDebugInfo()) {
// Emit debug information for all the BlockDeclRefDecls.
- for (unsigned i=0; i < BlockDeclRefDecls.size(); ++i) {
- const Expr *E = BlockDeclRefDecls[i];
- const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
- if (BDRE) {
+ for (unsigned i = 0, e = BlockDeclRefDecls.size(); i != e; ++i) {
+ if (const BlockDeclRefExpr *BDRE =
+ dyn_cast<BlockDeclRefExpr>(BlockDeclRefDecls[i])) {
const ValueDecl *D = BDRE->getDecl();
DI->setLocation(D->getLocation());
DI->EmitDeclareOfBlockDeclRefVariable(BDRE,
@@ -798,9 +815,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
FinishFunction(cast<CompoundStmt>(BExpr->getBody())->getRBracLoc());
// The runtime needs a minimum alignment of a void *.
- uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ CharUnits MinAlign = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
BlockOffset = CharUnits::fromQuantity(
- llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign));
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(),
+ MinAlign.getQuantity()));
Size = BlockOffset;
Align = BlockAlign;
@@ -813,20 +831,20 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
CharUnits Size = getContext().getTypeSizeInChars(D->getType());
- uint64_t Align = getContext().getDeclAlignInBytes(D);
+ CharUnits Align = getContext().getDeclAlign(D);
if (BDRE->isByRef()) {
Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy);
- Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
+ Align = getContext().getTypeAlignInChars(getContext().VoidPtrTy);
}
- assert ((Align > 0) && "alignment must be 1 byte or more");
+ assert ((Align.isPositive()) && "alignment must be 1 byte or more");
CharUnits OldOffset = BlockOffset;
// Ensure proper alignment, even if it means we have to have a gap
BlockOffset = CharUnits::fromQuantity(
- llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align));
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align.getQuantity()));
BlockAlign = std::max(Align, BlockAlign);
CharUnits Pad = BlockOffset - OldOffset;
@@ -868,7 +886,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -949,7 +967,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1033,7 +1051,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -1096,7 +1114,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args);
+ CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index f42244c52e0e..a9f5ae05c109 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -177,8 +177,9 @@ public:
/// BlockOffset - The offset in bytes for the next allocation of an
/// imported block variable.
CharUnits BlockOffset;
- /// BlockAlign - Maximal alignment needed for the Block expressed in bytes.
- uint64_t BlockAlign;
+ /// BlockAlign - Maximal alignment needed for the Block expressed in
+ /// characters.
+ CharUnits BlockAlign;
/// getBlockOffset - Allocate an offset for the ValueDecl from a
/// BlockDeclRefExpr in a block literal (BlockExpr).
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index f11d52e4334c..beaf7b89c003 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -304,6 +304,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Size = Builder.CreateIntCast(Size, llvm::Type::getInt32Ty(VMContext), false, "tmp");
return RValue::get(Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), Size, "tmp"));
}
+ case Builtin::BIbzero:
case Builtin::BI__builtin_bzero: {
Value *Address = EmitScalarExpr(E->getArg(0));
Builder.CreateCall4(CGM.getMemSetFn(), Address,
@@ -656,7 +657,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// Unknown builtin, for now just dump it out and return undef.
if (hasAggregateLLVMType(E->getType()))
- return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType())));
+ return RValue::getAggregate(CreateMemTemp(E->getType()));
return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 4323f84d9633..28c4c6b4b57b 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -165,7 +165,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
GlobalDecl GD, bool Extern,
const CovariantThunkAdjustment &Adjustment) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
FunctionArgList Args;
ImplicitParamDecl *ThisDecl =
@@ -190,7 +191,6 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
StartFunction(FD, ResultType, Fn, Args, SourceLocation());
// generate body
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
@@ -232,7 +232,9 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType));
}
- RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
+ FPT->getCallConv(),
+ FPT->getNoReturnAttr()),
Callee, ReturnValueSlot(), CallArgs, MD);
if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
bool CanBeZero = !(ResultType->isReferenceType()
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 2dda0b883f04..b064c125ad00 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -33,12 +33,19 @@ using namespace CodeGen;
// FIXME: Use iterator and sidestep silly type array creation.
+static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
+ switch (CC) {
+ default: return llvm::CallingConv::C;
+ case CC_X86StdCall: return llvm::CallingConv::X86_StdCall;
+ case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
+ }
+}
+
const
CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) {
- // FIXME: Set calling convention correctly, it needs to be associated with the
- // type somehow.
return getFunctionInfo(FTNP->getResultType(),
- llvm::SmallVector<QualType, 16>(), 0);
+ llvm::SmallVector<QualType, 16>(),
+ FTNP->getCallConv(), FTNP->getNoReturnAttr());
}
const
@@ -47,20 +54,19 @@ CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) {
// FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- // FIXME: Set calling convention correctly, it needs to be associated with the
- // type somehow.
- return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ FTP->getCallConv(), FTP->getNoReturnAttr());
}
-static unsigned getCallingConventionForDecl(const Decl *D) {
+static CallingConv getCallingConventionForDecl(const Decl *D) {
// Set the appropriate calling convention for the Function.
if (D->hasAttr<StdCallAttr>())
- return llvm::CallingConv::X86_StdCall;
+ return CC_X86StdCall;
if (D->hasAttr<FastCallAttr>())
- return llvm::CallingConv::X86_FastCall;
+ return CC_X86FastCall;
- return llvm::CallingConv::C;
+ return CC_C;
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
@@ -75,7 +81,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
// FIXME: Set calling convention correctly, it needs to be associated with the
// type somehow.
- return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ FTP->getCallConv(), FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
@@ -87,8 +94,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
const FunctionProtoType *FTP = MD->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- return getFunctionInfo(FTP->getResultType(), ArgTys,
- getCallingConventionForDecl(MD));
+ return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
+ FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
@@ -105,8 +112,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- return getFunctionInfo(FTP->getResultType(), ArgTys,
- getCallingConventionForDecl(D));
+ return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
+ FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
@@ -123,8 +130,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
- return getFunctionInfo(FTP->getResultType(), ArgTys,
- getCallingConventionForDecl(D));
+ return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
+ FTP->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
@@ -132,19 +139,19 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
if (MD->isInstance())
return getFunctionInfo(MD);
- unsigned CallingConvention = getCallingConventionForDecl(FD);
const FunctionType *FTy = FD->getType()->getAs<FunctionType>();
if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy))
return getFunctionInfo(FNTP->getResultType(),
llvm::SmallVector<QualType, 16>(),
- CallingConvention);
+ FNTP->getCallConv(), FNTP->getNoReturnAttr());
const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy);
llvm::SmallVector<QualType, 16> ArgTys;
// FIXME: Kill copy.
for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i)
ArgTys.push_back(FPT->getArgType(i));
- return getFunctionInfo(FPT->getResultType(), ArgTys, CallingConvention);
+ return getFunctionInfo(FPT->getResultType(), ArgTys,
+ FPT->getCallConv(), FPT->getNoReturnAttr());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
@@ -156,37 +163,56 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
e = MD->param_end(); i != e; ++i)
ArgTys.push_back((*i)->getType());
return getFunctionInfo(MD->getResultType(), ArgTys,
- getCallingConventionForDecl(MD));
+ getCallingConventionForDecl(MD),
+ /*NoReturn*/ false);
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
+ // FIXME: Do we need to handle ObjCMethodDecl?
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+ return getFunctionInfo(CD, GD.getCtorType());
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
+ return getFunctionInfo(DD, GD.getDtorType());
+
+ return getFunctionInfo(FD);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const CallArgList &Args,
- unsigned CallingConvention){
+ CallingConv CC,
+ bool NoReturn) {
// FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(i->second);
- return getFunctionInfo(ResTy, ArgTys, CallingConvention);
+ return getFunctionInfo(ResTy, ArgTys, CC, NoReturn);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
- unsigned CallingConvention){
+ CallingConv CC,
+ bool NoReturn) {
// FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(i->second);
- return getFunctionInfo(ResTy, ArgTys, CallingConvention);
+ return getFunctionInfo(ResTy, ArgTys, CC, NoReturn);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys,
- unsigned CallingConvention){
+ CallingConv CallConv,
+ bool NoReturn) {
+ unsigned CC = ClangCallConvToLLVMCallConv(CallConv);
+
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, CallingConvention, ResTy,
+ CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy,
ArgTys.begin(), ArgTys.end());
void *InsertPos = 0;
@@ -195,7 +221,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
return *FI;
// Construct the function info.
- FI = new CGFunctionInfo(CallingConvention, ResTy, ArgTys);
+ FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys);
FunctionInfos.InsertNode(FI, InsertPos);
// Compute ABI information.
@@ -205,10 +231,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
}
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
+ bool _NoReturn,
QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys)
: CallingConvention(_CallingConvention),
- EffectiveCallingConvention(_CallingConvention)
+ EffectiveCallingConvention(_CallingConvention),
+ NoReturn(_NoReturn)
{
NumArgs = ArgTys.size();
Args = new ArgInfo[1 + NumArgs];
@@ -258,7 +286,7 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
QualType FT = FD->getType();
// FIXME: What are the right qualifiers here?
- LValue LV = EmitLValueForField(Addr, FD, false, 0);
+ LValue LV = EmitLValueForField(Addr, FD, 0);
if (CodeGenFunction::hasAggregateLLVMType(FT)) {
AI = ExpandTypeFromArgs(FT, LV, AI);
} else {
@@ -285,7 +313,7 @@ CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
QualType FT = FD->getType();
// FIXME: What are the right qualifiers here?
- LValue LV = EmitLValueForField(Addr, FD, false, 0);
+ LValue LV = EmitLValueForField(Addr, FD, 0);
if (CodeGenFunction::hasAggregateLLVMType(FT)) {
ExpandTypeToArgs(FT, RValue::getAggregate(LV.getAddress()), Args);
} else {
@@ -490,6 +518,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
CallingConv = FI.getEffectiveCallingConvention();
+ if (FI.isNoReturn())
+ FuncAttrs |= llvm::Attribute::NoReturn;
+
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<NoThrowAttr>())
@@ -685,7 +716,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Create a temporary alloca to hold the argument; the rest of
// codegen expects to access aggregates & complex values by
// reference.
- V = CreateTempAlloca(ConvertTypeForMem(Ty));
+ V = CreateMemTemp(Ty);
Builder.CreateStore(AI, V);
} else {
if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
@@ -702,8 +733,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// If this structure was expanded into multiple arguments then
// we need to create a temporary and reconstruct it from the
// arguments.
- llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(Ty),
- Arg->getName() + ".addr");
+ llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr");
// FIXME: What are the right qualifiers here?
llvm::Function::arg_iterator End =
ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI);
@@ -719,7 +749,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
if (hasAggregateLLVMType(Ty)) {
- EmitParmDecl(*Arg, CreateTempAlloca(ConvertTypeForMem(Ty)));
+ EmitParmDecl(*Arg, CreateMemTemp(Ty));
} else {
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())));
}
@@ -732,7 +762,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// FIXME: This is very wasteful; EmitParmDecl is just going to drop the
// result in a new alloca anyway, so we could just store into that
// directly if we broke the abstraction down more.
- llvm::Value *V = CreateTempAlloca(ConvertTypeForMem(Ty), "coerce");
+ llvm::Value *V = CreateMemTemp(Ty, "coerce");
CreateCoercedStore(AI, V, /*DestIsVolatile=*/false, *this);
// Match to what EmitParmDecl is expecting for this type.
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
@@ -803,7 +833,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
if (ArgType->isReferenceType())
- return EmitReferenceBindingToExpr(E, ArgType);
+ return EmitReferenceBindingToExpr(E);
return EmitAnyExprToTemp(E);
}
@@ -827,7 +857,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (CGM.ReturnTypeUsesSret(CallInfo)) {
llvm::Value *Value = ReturnValue.getValue();
if (!Value)
- Value = CreateTempAlloca(ConvertTypeForMem(RetTy));
+ Value = CreateMemTemp(RetTy);
Args.push_back(Value);
}
@@ -843,7 +873,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Indirect:
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
- Args.push_back(CreateTempAlloca(ConvertTypeForMem(I->second)));
+ Args.push_back(CreateMemTemp(I->second));
if (RV.isScalar())
EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, I->second);
else
@@ -874,10 +904,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: Avoid the conversion through memory if possible.
llvm::Value *SrcPtr;
if (RV.isScalar()) {
- SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce");
+ SrcPtr = CreateMemTemp(I->second, "coerce");
EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, I->second);
} else if (RV.isComplex()) {
- SrcPtr = CreateTempAlloca(ConvertTypeForMem(I->second), "coerce");
+ SrcPtr = CreateMemTemp(I->second, "coerce");
StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
} else
SrcPtr = RV.getAggregateAddr();
@@ -982,7 +1012,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
bool DestIsVolatile = ReturnValue.isVolatile();
if (!DestPtr) {
- DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "agg.tmp");
+ DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
Builder.CreateStore(CI, DestPtr, DestIsVolatile);
@@ -1000,7 +1030,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
bool DestIsVolatile = ReturnValue.isVolatile();
if (!DestPtr) {
- DestPtr = CreateTempAlloca(ConvertTypeForMem(RetTy), "coerce");
+ DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
}
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 427ab5f4cbc8..9601e9ae9a27 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -69,6 +69,9 @@ namespace CodeGen {
/// depend on the ABI.
unsigned EffectiveCallingConvention;
+ /// Whether this function is noreturn.
+ bool NoReturn;
+
unsigned NumArgs;
ArgInfo *Args;
@@ -77,6 +80,7 @@ namespace CodeGen {
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention,
+ bool NoReturn,
QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys);
~CGFunctionInfo() { delete[] Args; }
@@ -88,6 +92,8 @@ namespace CodeGen {
unsigned arg_size() const { return NumArgs; }
+ bool isNoReturn() const { return NoReturn; }
+
/// getCallingConvention - Return the user specified calling
/// convention.
unsigned getCallingConvention() const { return CallingConvention; }
@@ -108,6 +114,7 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
+ ID.AddBoolean(NoReturn);
getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
it->type.Profile(ID);
@@ -115,10 +122,12 @@ namespace CodeGen {
template<class Iterator>
static void Profile(llvm::FoldingSetNodeID &ID,
unsigned CallingConvention,
+ bool NoReturn,
QualType ResTy,
Iterator begin,
Iterator end) {
ID.AddInteger(CallingConvention);
+ ID.AddBoolean(NoReturn);
ResTy.Profile(ID);
for (; begin != end; ++begin)
begin->Profile(ID);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index a822ca2b7417..fa5a47f31564 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -19,11 +19,11 @@ using namespace clang;
using namespace CodeGen;
static uint64_t
-ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
+ComputeNonVirtualBaseClassOffset(ASTContext &Context,
+ const CXXBasePath &Path,
unsigned Start) {
uint64_t Offset = 0;
- const CXXBasePath &Path = Paths.front();
for (unsigned i = Start, e = Path.size(); i != e; ++i) {
const CXXBasePathElement& Element = Path[i];
@@ -44,20 +44,21 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
}
llvm::Constant *
-CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- if (ClassDecl == BaseClassDecl)
+CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class,
+ const CXXRecordDecl *BaseClass) {
+ if (Class == BaseClass)
return 0;
CXXBasePaths Paths(/*FindAmbiguities=*/false,
/*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(ClassDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
+ if (!const_cast<CXXRecordDecl *>(Class)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) {
assert(false && "Class must be derived from the passed in base class!");
return 0;
}
- uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
+ uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(),
+ Paths.front(), 0);
if (!Offset)
return 0;
@@ -67,51 +68,6 @@ CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
-static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
- llvm::Value *BaseValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(ClassDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return 0;
- }
-
- unsigned Start = 0;
- llvm::Value *VirtualOffset = 0;
-
- const CXXBasePath &Path = Paths.front();
- const CXXRecordDecl *VBase = 0;
- for (unsigned i = 0, e = Path.size(); i != e; ++i) {
- const CXXBasePathElement& Element = Path[i];
- if (Element.Base->isVirtual()) {
- Start = i+1;
- QualType VBaseType = Element.Base->getType();
- VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
- }
- }
- if (VBase)
- VirtualOffset =
- CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
-
- uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
-
- if (!Offset)
- return VirtualOffset;
-
- const llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
- llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
-
- if (VirtualOffset)
- return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
-
- return NonVirtualOffset;
-}
-
// FIXME: This probably belongs in CGVtable, but it relies on
// the static function ComputeNonVirtualBaseClassOffset, so we should make that
// a CodeGenModule member function as well.
@@ -144,25 +100,91 @@ CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start);
+ ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
return ThunkAdjustment(Offset, VirtualOffset);
}
+/// Gets the address of a virtual base class within a complete object.
+/// This should only be used for (1) non-virtual bases or (2) virtual bases
+/// when the type is known to be complete (e.g. in complete destructors).
+///
+/// The object pointed to by 'This' is assumed to be non-null.
+llvm::Value *
+CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
+ bool isBaseVirtual,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base) {
+ // 'this' must be a pointer (in some address space) to Derived.
+ assert(This->getType()->isPointerTy() &&
+ cast<llvm::PointerType>(This->getType())->getElementType()
+ == ConvertType(Derived));
+
+ // Compute the offset of the virtual base.
+ uint64_t Offset;
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
+ if (isBaseVirtual)
+ Offset = Layout.getVBaseClassOffset(Base);
+ else
+ 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) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
+ V = Builder.CreateBitCast(V, Int8PtrTy);
+ V = Builder.CreateConstInBoundsGEP1_64(V, Offset / 8);
+ }
+ V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo());
+
+ return V;
+}
+
llvm::Value *
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
+ const CXXRecordDecl *Class,
+ const CXXRecordDecl *BaseClass,
bool NullCheckValue) {
QualType BTy =
getContext().getCanonicalType(
- getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
+ getContext().getTypeDeclType(BaseClass));
const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
- if (ClassDecl == BaseClassDecl) {
+ if (Class == BaseClass) {
// Just cast back.
return Builder.CreateBitCast(Value, BasePtrTy);
}
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+ if (!const_cast<CXXRecordDecl *>(Class)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return 0;
+ }
+
+ unsigned Start = 0;
+ llvm::Value *VirtualOffset = 0;
+
+ const CXXBasePath &Path = Paths.front();
+ const CXXRecordDecl *VBase = 0;
+ for (unsigned i = 0, e = Path.size(); i != e; ++i) {
+ const CXXBasePathElement& Element = Path[i];
+ if (Element.Base->isVirtual()) {
+ Start = i+1;
+ QualType VBaseType = Element.Base->getType();
+ VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+ }
+ }
+
+ uint64_t Offset =
+ ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
+ if (!Offset && !VBase) {
+ // Just cast back.
+ return Builder.CreateBitCast(Value, BasePtrTy);
+ }
+
llvm::BasicBlock *CastNull = 0;
llvm::BasicBlock *CastNotNull = 0;
llvm::BasicBlock *CastEnd = 0;
@@ -179,16 +201,27 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
EmitBlock(CastNotNull);
}
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ if (VBase)
+ VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase);
- llvm::Value *Offset =
- GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+ llvm::Value *NonVirtualOffset = 0;
+ if (Offset)
+ NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
- if (Offset) {
- // Apply the offset.
- Value = Builder.CreateBitCast(Value, Int8PtrTy);
- Value = Builder.CreateGEP(Value, Offset, "add.ptr");
- }
+ llvm::Value *BaseOffset;
+ if (VBase) {
+ if (NonVirtualOffset)
+ BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
+ else
+ BaseOffset = VirtualOffset;
+ } else
+ BaseOffset = NonVirtualOffset;
+
+ // Apply the base offset.
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
+ Value = Builder.CreateBitCast(Value, Int8PtrTy);
+ Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr");
// Cast back.
Value = Builder.CreateBitCast(Value, BasePtrTy);
@@ -212,19 +245,27 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
llvm::Value *
CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *DerivedClassDecl,
+ const CXXRecordDecl *Class,
+ const CXXRecordDecl *DerivedClass,
bool NullCheckValue) {
QualType DerivedTy =
getContext().getCanonicalType(
- getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
+ getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClass)));
const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
- if (ClassDecl == DerivedClassDecl) {
+ if (Class == DerivedClass) {
// Just cast back.
return Builder.CreateBitCast(Value, DerivedPtrTy);
}
+ llvm::Value *NonVirtualOffset =
+ CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class);
+
+ if (!NonVirtualOffset) {
+ // No offset, we can just cast back.
+ return Builder.CreateBitCast(Value, DerivedPtrTy);
+ }
+
llvm::BasicBlock *CastNull = 0;
llvm::BasicBlock *CastNotNull = 0;
llvm::BasicBlock *CastEnd = 0;
@@ -241,17 +282,13 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
EmitBlock(CastNotNull);
}
- llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
- ClassDecl);
- if (Offset) {
- // Apply the offset.
- Value = Builder.CreatePtrToInt(Value, Offset->getType());
- Value = Builder.CreateSub(Value, Offset);
- Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
- } else {
- // Just cast.
- Value = Builder.CreateBitCast(Value, DerivedPtrTy);
- }
+ // Apply the offset.
+ Value = Builder.CreatePtrToInt(Value, NonVirtualOffset->getType());
+ Value = Builder.CreateSub(Value, NonVirtualOffset);
+ Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
+
+ // Just cast.
+ Value = Builder.CreateBitCast(Value, DerivedPtrTy);
if (NullCheckValue) {
Builder.CreateBr(CastEnd);
@@ -327,9 +364,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ const FunctionProtoType *FPT
+ = BaseCopyCtor->getType()->getAs<FunctionProtoType>();
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
}
EmitBlock(ContinueBlock);
@@ -412,8 +449,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
RValue::getAggregate(Src);
CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, MD);
}
EmitBlock(ContinueBlock);
@@ -503,9 +539,9 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ const FunctionProtoType *FPT =
+ BaseCopyCtor->getType()->getAs<FunctionProtoType>();
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
}
}
@@ -550,9 +586,7 @@ void CodeGenFunction::EmitClassCopyAssignment(
RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
RValue::getAggregate(Src);
CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- QualType ResultType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, MD);
}
@@ -629,8 +663,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0);
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -647,26 +681,9 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
continue;
}
- if (Field->getType()->isReferenceType()) {
- unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field);
-
- llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
- "lhs.ref");
-
- llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
- "rhs.ref");
-
- // Load the value in RHS.
- RHS = Builder.CreateLoad(RHS);
-
- // And store it in the LHS
- Builder.CreateStore(RHS, LHS);
-
- continue;
- }
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+ LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0);
+ LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0);
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
@@ -745,8 +762,8 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0);
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -763,8 +780,8 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
continue;
}
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0);
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
@@ -810,29 +827,21 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
if (CtorType == Ctor_Base && isBaseVirtual)
return;
- // Compute the offset to the base; we do this directly instead of using
- // GetAddressOfBaseClass because the class doesn't have a vtable pointer
- // at this point.
- // FIXME: This could be refactored back into GetAddressOfBaseClass if it took
- // an extra parameter for whether the derived class is the complete object
- // class.
- const ASTRecordLayout &Layout =
- CGF.getContext().getASTRecordLayout(ClassDecl);
- uint64_t Offset;
- if (isBaseVirtual)
- Offset = Layout.getVBaseClassOffset(BaseClassDecl);
- else
- Offset = Layout.getBaseClassOffset(BaseClassDecl);
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *BaseClassType = CGF.ConvertType(QualType(BaseType, 0));
- llvm::Value *V = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
- V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8);
- V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
-
- CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
- Ctor_Base, V,
- BaseInit->const_arg_begin(),
- BaseInit->const_arg_end());
+ // We can pretend to be a complete class because it only matters for
+ // virtual bases, and we only do virtual bases for complete ctors.
+ llvm::Value *V = ThisPtr;
+ V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual,
+ ClassDecl, BaseClassDecl);
+
+ CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true);
+
+ if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) {
+ // FIXME: Is this OK for C++0x delegating constructors?
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+
+ CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext());
+ CGF.EmitCXXDestructorCall(DD, Dtor_Base, V);
+ }
}
static void EmitMemberInitializer(CodeGenFunction &CGF,
@@ -846,91 +855,62 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
QualType FieldType = CGF.getContext().getCanonicalType(Field->getType());
llvm::Value *ThisPtr = CGF.LoadCXXThis();
- LValue LHS;
- if (FieldType->isReferenceType()) {
- // FIXME: This is really ugly; should be refactored somehow
- unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field);
- llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp");
- assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
- LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType));
- } else {
- LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0);
- }
-
+ LValue LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0);
+
// If we are initializing an anonymous union field, drill down to the field.
if (MemberInit->getAnonUnionMember()) {
Field = MemberInit->getAnonUnionMember();
- LHS = CGF.EmitLValueForField(LHS.getAddress(), Field,
- /*IsUnion=*/true, 0);
+ LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, 0);
FieldType = Field->getType();
}
- // If the field is an array, branch based on the element type.
- const ConstantArrayType *Array =
- CGF.getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = CGF.getContext().getBaseElementType(FieldType);
-
- // We lose the constructor for anonymous union members, so handle them
- // explicitly.
- // FIXME: This is somwhat ugly.
- if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) {
- if (MemberInit->getNumArgs())
- CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(),
- LHS.isVolatileQualified());
- else
- CGF.EmitAggregateClear(LHS.getAddress(), Field->getType());
- return;
- }
-
- if (FieldType->getAs<RecordType>()) {
- assert(MemberInit->getConstructor() &&
- "EmitCtorPrologue - no constructor to initialize member");
- if (Array) {
- const llvm::Type *BasePtr = CGF.ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(),
- Array, BaseAddrPtr,
- MemberInit->const_arg_begin(),
- MemberInit->const_arg_end());
- }
- else
- CGF.EmitCXXConstructorCall(MemberInit->getConstructor(),
- Ctor_Complete, LHS.getAddress(),
- MemberInit->const_arg_begin(),
- MemberInit->const_arg_end());
- return;
- }
-
- assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only");
- Expr *RhsExpr = *MemberInit->arg_begin();
+ // FIXME: If there's no initializer and the CXXBaseOrMemberInitializer
+ // was implicitly generated, we shouldn't be zeroing memory.
RValue RHS;
if (FieldType->isReferenceType()) {
- RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType,
- /*IsInitializer=*/true);
+ RHS = CGF.EmitReferenceBindingToExpr(MemberInit->getInit(),
+ /*IsInitializer=*/true);
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
- } else if (Array) {
+ } else if (FieldType->isArrayType() && !MemberInit->getInit()) {
CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType());
- } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) {
- RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true));
+ } else if (!CGF.hasAggregateLLVMType(Field->getType())) {
+ RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit(), true));
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
- } else if (RhsExpr->getType()->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(),
+ } else if (MemberInit->getInit()->getType()->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
LHS.isVolatileQualified());
} else {
- // Handle member function pointers; other aggregates shouldn't get this far.
- CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified());
+ CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(),
+ LHS.isVolatileQualified(), false, true);
+
+ if (!CGF.Exceptions)
+ return;
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ if (!RT)
+ return;
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD->hasTrivialDestructor()) {
+ // FIXME: Is this OK for C++0x delegating constructors?
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
+
+ CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext());
+ CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress());
+ }
}
}
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
-/// FIXME: This needs to take a CXXCtorType.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
CXXCtorType CtorType) {
const CXXRecordDecl *ClassDecl = CD->getParent();
+
+ llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers;
// FIXME: Add vbase initialization
@@ -945,14 +925,17 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
if (Member->isBaseInitializer())
EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
else
- EmitMemberInitializer(*this, ClassDecl, Member);
-
- // Pop any live temporaries that the initializers might have pushed.
- while (!LiveTemporaries.empty())
- PopCXXTemporary();
+ MemberInitializers.push_back(Member);
}
InitializeVtablePtrs(ClassDecl);
+
+ for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) {
+ assert(LiveTemporaries.empty() &&
+ "Should not have any live temporaries at initializer start!");
+
+ EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I]);
+ }
}
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
@@ -1002,7 +985,6 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
llvm::Value *ThisPtr = LoadCXXThis();
LValue LHS = EmitLValueForField(ThisPtr, Field,
- /*isUnion=*/false,
// FIXME: Qualifiers?
/*CVRQualifiers=*/0);
if (Array) {
@@ -1050,15 +1032,16 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
const CXXBaseSpecifier &Base = *I;
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
// Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
- llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(),
+ true,
+ ClassDecl,
+ BaseClassDecl);
EmitCXXDestructorCall(D, Dtor_Base, V);
}
@@ -1080,7 +1063,7 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
SourceLocation());
-
+ InitializeVtablePtrs(Dtor->getParent());
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
@@ -1263,7 +1246,8 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
llvm::SmallString<16> Name;
llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
QualType R = getContext().VoidTy;
- const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
+ const CGFunctionInfo &FI
+ = CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
@@ -1295,20 +1279,21 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
- if (D->isCopyConstructor()) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
- if (ClassDecl->hasTrivialCopyConstructor()) {
- assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
- "EmitCXXConstructorCall - user declared copy constructor");
- const Expr *E = (*ArgBeg);
- QualType Ty = E->getType();
- llvm::Value *Src = EmitLValue(E).getAddress();
- EmitAggregateCopy(This, Src, Ty);
+ if (D->isTrivial()) {
+ if (ArgBeg == ArgEnd) {
+ // Trivial default constructor, no codegen required.
+ assert(D->isDefaultConstructor() &&
+ "trivial 0-arg ctor not a default ctor");
return;
}
- } else if (D->isTrivial()) {
- // FIXME: Track down why we're trying to generate calls to the trivial
- // default constructor!
+
+ assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor");
+ assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor");
+
+ const Expr *E = (*ArgBeg);
+ QualType Ty = E->getType();
+ llvm::Value *Src = EmitLValue(E).getAddress();
+ EmitAggregateCopy(This, Src, Ty);
return;
}
@@ -1328,8 +1313,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
}
llvm::Value *
-CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
+CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 1ffad3edcac7..5b9c6b055e0e 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -49,19 +49,21 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc);
}
-/// getContext - Get context info for the decl.
-llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
- llvm::DIDescriptor &CompileUnit) {
- if (Decl->isFileVarDecl())
+/// getContextDescriptor - Get context info for the decl.
+llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context,
+ llvm::DIDescriptor &CompileUnit) {
+ if (!Context)
return CompileUnit;
- if (Decl->getDeclContext()->isFunctionOrMethod()) {
- // Find the last subprogram in region stack.
- for (unsigned RI = RegionStack.size(), RE = 0; RI != RE; --RI) {
- llvm::DIDescriptor R(RegionStack[RI - 1]);
- if (R.isSubprogram())
- return R;
- }
- }
+
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
+ I = RegionMap.find(Context);
+ if (I != RegionMap.end())
+ return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(I->second));
+
+ // Check namespace.
+ if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
+ return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl, CompileUnit));
+
return CompileUnit;
}
@@ -78,10 +80,9 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
std::string NS = FD->getNameAsString();
// Copy this name on the side and use its reference.
- unsigned Length = NS.length() + 1;
- char *StrPtr = FunctionNames.Allocate<char>(Length);
- strncpy(StrPtr, NS.c_str(), Length);
- return llvm::StringRef(StrPtr);
+ char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
+ memcpy(StrPtr, NS.data(), NS.length());
+ return llvm::StringRef(StrPtr, NS.length());
}
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
@@ -90,16 +91,15 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
// Get source file information.
const char *FileName = "<unknown>";
SourceManager &SM = CGM.getContext().getSourceManager();
- unsigned FID = 0;
if (Loc.isValid()) {
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
FileName = PLoc.getFilename();
- FID = PLoc.getIncludeLoc().getRawEncoding();
- }
+ unsigned FID = PLoc.getIncludeLoc().getRawEncoding();
- // See if this compile unit has been used before.
- llvm::DICompileUnit &Unit = CompileUnitCache[FID];
- if (!Unit.isNull()) return Unit;
+ // See if this compile unit has been used before for this valid location.
+ llvm::DICompileUnit &Unit = CompileUnitCache[FID];
+ if (!Unit.isNull()) return Unit;
+ }
// Get absolute path name.
llvm::sys::Path AbsFileName(FileName);
@@ -149,9 +149,16 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
// Create new compile unit.
- return Unit = DebugFactory.CreateCompileUnit(
+ llvm::DICompileUnit Unit = DebugFactory.CreateCompileUnit(
LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, isMain,
LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
+
+ if (Loc.isValid()) {
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ unsigned FID = PLoc.getIncludeLoc().getRawEncoding();
+ CompileUnitCache[FID] = Unit;
+ }
+ return Unit;
}
/// CreateType - Get the Basic type from the cache or create a new
@@ -419,17 +426,18 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
- SourceLocation DefLoc = Ty->getDecl()->getLocation();
- llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
-
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
+ PresumedLoc PLoc = SM.getPresumedLoc(Ty->getDecl()->getLocation());
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
+ llvm::DIDescriptor TyContext
+ = getContextDescriptor(dyn_cast<Decl>(Ty->getDecl()->getDeclContext()),
+ Unit);
llvm::DIType DbgTy =
- DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit,
- Ty->getDecl()->getName(),
- DefUnit, Line, 0, 0, 0, 0, Src);
+ DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef,
+ TyContext,
+ Ty->getDecl()->getName(), Unit,
+ Line, 0, 0, 0, 0, Src);
return DbgTy;
}
@@ -463,22 +471,21 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
void CGDebugInfo::
-CollectRecordFields(const RecordDecl *Decl,
- llvm::DICompileUnit Unit,
+CollectRecordFields(const RecordDecl *RD, llvm::DICompileUnit Unit,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
unsigned FieldNo = 0;
SourceManager &SM = CGM.getContext().getSourceManager();
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl);
- for (RecordDecl::field_iterator I = Decl->field_begin(),
- E = Decl->field_end();
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end();
I != E; ++I, ++FieldNo) {
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
llvm::StringRef FieldName = Field->getName();
- // Ignore unnamed fields.
- if (FieldName.empty())
+ // Ignore unnamed fields. Do not ignore unnamed records.
+ if (FieldName.empty() && !isa<RecordType>(Field->getType()))
continue;
// Get the location for the field.
@@ -519,87 +526,264 @@ CollectRecordFields(const RecordDecl *Decl,
}
}
+/// getOrCreateMethodType - CXXMethodDecl's type is a FunctionType. This
+/// function type is not updated to include implicit "this" pointer. Use this
+/// routine to get a method type which includes "this" pointer.
+llvm::DIType
+CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit) {
+ llvm::DIType FnTy = getOrCreateType(Method->getType(), Unit);
+
+ // Static methods do not need "this" pointer argument.
+ if (Method->isStatic())
+ return FnTy;
+
+ // Add "this" pointer.
+
+ llvm::DIArray Args = llvm::DICompositeType(FnTy.getNode()).getTypeArray();
+ assert (Args.getNumElements() && "Invalid number of arguments!");
+
+ llvm::SmallVector<llvm::DIDescriptor, 16> Elts;
+
+ // First element is always return type. For 'void' functions it is NULL.
+ Elts.push_back(Args.getElement(0));
+
+ // "this" pointer is always first argument.
+ ASTContext &Context = CGM.getContext();
+ QualType ThisPtr =
+ Context.getPointerType(Context.getTagDeclType(Method->getParent()));
+ llvm::DIType ThisPtrType =
+ DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit));
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType.getNode();
+ Elts.push_back(ThisPtrType);
+
+ // Copy rest of the arguments.
+ for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i)
+ Elts.push_back(Args.getElement(i));
+
+ llvm::DIArray EltTypeArray =
+ DebugFactory.GetOrCreateArray(Elts.data(), Elts.size());
+
+ return
+ DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, 0, 0, 0, 0,
+ llvm::DIType(), EltTypeArray);
+}
+
+/// CreateCXXMemberFunction - A helper function to create a DISubprogram for
+/// a single member function GlobalDecl.
+llvm::DISubprogram
+CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit,
+ llvm::DICompositeType &RecordTy) {
+ bool IsCtorOrDtor =
+ isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
+
+ llvm::StringRef MethodName = getFunctionName(Method);
+ llvm::StringRef MethodLinkageName;
+ llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit);
+
+ // Since a single ctor/dtor corresponds to multiple functions, it doesn't
+ // make sense to give a single ctor/dtor a linkage name.
+ if (!IsCtorOrDtor)
+ MethodLinkageName = CGM.getMangledName(Method);
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+
+ // Get the location for the method.
+ SourceLocation MethodDefLoc = Method->getLocation();
+ PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc);
+ llvm::DICompileUnit MethodDefUnit;
+ unsigned MethodLine = 0;
+
+ if (!PLoc.isInvalid()) {
+ MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc);
+ MethodLine = PLoc.getLine();
+ }
+
+ // Collect virtual method info.
+ llvm::DIType ContainingType;
+ unsigned Virtuality = 0;
+ unsigned VIndex = 0;
+
+ if (Method->isVirtual()) {
+ if (Method->isPure())
+ Virtuality = llvm::dwarf::DW_VIRTUALITY_pure_virtual;
+ else
+ Virtuality = llvm::dwarf::DW_VIRTUALITY_virtual;
+
+ // It doesn't make sense to give a virtual destructor a vtable index,
+ // since a single destructor has two entries in the vtable.
+ if (!isa<CXXDestructorDecl>(Method))
+ VIndex = CGM.getVtableInfo().getMethodVtableIndex(Method);
+ ContainingType = RecordTy;
+ }
+
+ llvm::DISubprogram SP =
+ DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName,
+ MethodLinkageName,
+ MethodDefUnit, MethodLine,
+ MethodTy, /*isLocalToUnit=*/false,
+ Method->isThisDeclarationADefinition(),
+ Virtuality, VIndex, ContainingType);
+
+ // 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.getNode());
+
+ return SP;
+}
+
/// CollectCXXMemberFunctions - A helper function to collect debug info for
/// C++ member functions.This is used while creating debug info entry for
/// a Record.
void CGDebugInfo::
-CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
- llvm::DICompileUnit Unit,
+CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DICompileUnit Unit,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys,
llvm::DICompositeType &RecordTy) {
- SourceManager &SM = CGM.getContext().getSourceManager();
- for(CXXRecordDecl::method_iterator I = Decl->method_begin(),
- E = Decl->method_end(); I != E; ++I) {
- CXXMethodDecl *Method = *I;
- llvm::StringRef MethodName;
- llvm::StringRef MethodLinkageName;
- llvm::DIType MethodTy = getOrCreateType(Method->getType(), Unit);
- if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(Method)) {
- if (CDecl->isImplicit())
- continue;
- MethodName = Decl->getName();
- // FIXME : Find linkage name.
- } else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(Method)) {
- if (DDecl->isImplicit())
- continue;
- MethodName = getFunctionName(Method);
- // FIXME : Find linkage name.
- } else {
- if (Method->isImplicit())
- continue;
- // regular method
- MethodName = getFunctionName(Method);
- MethodLinkageName = CGM.getMangledName(Method);
- }
-
- // Get the location for the method.
- SourceLocation MethodDefLoc = Method->getLocation();
- PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc);
- llvm::DICompileUnit MethodDefUnit;
- unsigned MethodLine = 0;
-
- if (!PLoc.isInvalid()) {
- MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc);
- MethodLine = PLoc.getLine();
- }
+ for(CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *Method = *I;
+
+ if (Method->isImplicit() && !Method->isUsed())
+ continue;
- llvm::DISubprogram SP =
- DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName,
- MethodLinkageName,
- MethodDefUnit, MethodLine,
- MethodTy, false,
- Method->isThisDeclarationADefinition(),
- 0 /*Virtuality*/, 0 /*VIndex*/,
- llvm::DIType() /*ContainingType*/);
- if (Method->isThisDeclarationADefinition())
- SPCache[cast<FunctionDecl>(Method)] = llvm::WeakVH(SP.getNode());
- EltTys.push_back(SP);
+ EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
}
}
+/// CollectCXXBases - A helper function to collect debug info for
+/// C++ base classes. This is used while creating debug info entry for
+/// a Record.
+void CGDebugInfo::
+CollectCXXBases(const CXXRecordDecl *RD, llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys,
+ llvm::DICompositeType &RecordTy) {
+
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end(); BI != BE; ++BI) {
+ unsigned BFlags = 0;
+ uint64_t BaseOffset;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl());
+
+ if (BI->isVirtual()) {
+ // virtual base offset index is -ve. The code generator emits dwarf
+ // expression where it expects +ve number.
+ BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base);
+ BFlags = llvm::DIType::FlagVirtual;
+ } else
+ BaseOffset = RL.getBaseClassOffset(Base);
+
+ AccessSpecifier Access = BI->getAccessSpecifier();
+ if (Access == clang::AS_private)
+ BFlags |= llvm::DIType::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ BFlags |= llvm::DIType::FlagProtected;
+
+ llvm::DIType DTy =
+ DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance,
+ RecordTy, llvm::StringRef(),
+ llvm::DICompileUnit(), 0, 0, 0,
+ BaseOffset, BFlags,
+ getOrCreateType(BI->getType(),
+ Unit));
+ EltTys.push_back(DTy);
+ }
+}
+
+/// getOrCreateVTablePtrType - Return debug info descriptor for vtable.
+llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DICompileUnit Unit) {
+ if (!VTablePtrType.isNull())
+ return VTablePtrType;
+
+ ASTContext &Context = CGM.getContext();
+
+ /* Function type */
+ llvm::SmallVector<llvm::DIDescriptor, 16> STys;
+ STys.push_back(getOrCreateType(Context.IntTy, Unit));
+ llvm::DIArray SElements =
+ DebugFactory.GetOrCreateArray(STys.data(), STys.size());
+ llvm::DIType SubTy =
+ DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, 0, 0, 0, 0, llvm::DIType(), SElements);
+
+ unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
+ llvm::DIType vtbl_ptr_type
+ = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type,
+ Unit, "__vtbl_ptr_type", llvm::DICompileUnit(),
+ 0, Size, 0, 0, 0, SubTy);
+
+ VTablePtrType = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type,
+ Unit, "", llvm::DICompileUnit(),
+ 0, Size, 0, 0, 0, vtbl_ptr_type);
+ return VTablePtrType;
+}
+
+/// getVtableName - Get vtable name for the given Class.
+llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) {
+ // Otherwise construct gdb compatible name name.
+ std::string Name = "_vptr$" + RD->getNameAsString();
+
+ // Copy this name on the side and use its reference.
+ char *StrPtr = DebugInfoNames.Allocate<char>(Name.length());
+ memcpy(StrPtr, Name.data(), Name.length());
+ return llvm::StringRef(StrPtr, Name.length());
+}
+
+
+/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate
+/// debug info entry in EltTys vector.
+void CGDebugInfo::
+CollectVtableInfo(const CXXRecordDecl *RD, llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+
+ // If there is a primary base then it will hold vtable info.
+ if (RL.getPrimaryBase())
+ return;
+
+ // If this class is not dynamic then there is not any vtable info to collect.
+ if (!RD->isDynamicClass())
+ return;
+
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+ llvm::DIType VPTR
+ = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ getVtableName(RD), llvm::DICompileUnit(),
+ 0, Size, 0, 0, 0,
+ getOrCreateVTablePtrType(Unit));
+ EltTys.push_back(VPTR);
+}
+
/// CreateType - get structure or union type.
llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
llvm::DICompileUnit Unit) {
- RecordDecl *Decl = Ty->getDecl();
+ RecordDecl *RD = Ty->getDecl();
unsigned Tag;
- if (Decl->isStruct())
+ if (RD->isStruct())
Tag = llvm::dwarf::DW_TAG_structure_type;
- else if (Decl->isUnion())
+ else if (RD->isUnion())
Tag = llvm::dwarf::DW_TAG_union_type;
else {
- assert(Decl->isClass() && "Unknown RecordType!");
+ assert(RD->isClass() && "Unknown RecordType!");
Tag = llvm::dwarf::DW_TAG_class_type;
}
SourceManager &SM = CGM.getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(RD->getLocation());
llvm::DICompileUnit DefUnit;
unsigned Line = 0;
if (!PLoc.isInvalid()) {
- DefUnit = getOrCreateCompileUnit(Decl->getLocation());
+ DefUnit = getOrCreateCompileUnit(RD->getLocation());
Line = PLoc.getLine();
}
@@ -610,19 +794,19 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
- // A Decl->getName() is not unique. However, the debug info descriptors
- // are uniqued. The debug info descriptor describing record's context is
- // necessary to keep two Decl's descriptor unique if their name match.
- // FIXME : Use RecordDecl's DeclContext's descriptor. As a temp. step
- // use type's name in FwdDecl.
+ // A RD->getName() is not unique. However, the debug info descriptors
+ // are uniqued so use type name to ensure uniquness.
std::string STy = QualType(Ty, 0).getAsString();
+ llvm::DIDescriptor FDContext =
+ getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit);
llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, STy.c_str(),
+ DebugFactory.CreateCompositeType(Tag, FDContext,
+ STy.c_str(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray());
// If this is just a forward declaration, return it.
- if (!Decl->getDefinition(CGM.getContext()))
+ if (!RD->getDefinition())
return FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
@@ -633,10 +817,25 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
- CollectRecordFields(Decl, Unit, EltTys);
- if (CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(Decl))
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+ if (CXXDecl) {
+ CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl);
+ CollectVtableInfo(CXXDecl, Unit, EltTys);
+ }
+ CollectRecordFields(RD, Unit, EltTys);
+ llvm::MDNode *ContainingType = NULL;
+ if (CXXDecl) {
CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl);
+ // A class's primary base or the class itself contains the vtable.
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ if (const CXXRecordDecl *PBase = RL.getPrimaryBase())
+ ContainingType =
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit).getNode();
+ else if (CXXDecl->isDynamicClass())
+ ContainingType = FwdDecl.getNode();
+ }
+
llvm::DIArray Elements =
DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
@@ -644,10 +843,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ llvm::DIDescriptor RDContext =
+ getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
+ DebugFactory.CreateCompositeType(Tag, RDContext,
+ RD->getName(),
DefUnit, Line, Size, Align, 0, 0,
- llvm::DIType(), Elements);
+ llvm::DIType(), Elements,
+ 0, ContainingType);
// 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.
@@ -659,14 +862,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
/// CreateType - get objective-c interface type.
llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DICompileUnit Unit) {
- ObjCInterfaceDecl *Decl = Ty->getDecl();
+ ObjCInterfaceDecl *ID = Ty->getDecl();
unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
SourceManager &SM = CGM.getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation());
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(ID->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation());
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
@@ -679,13 +882,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
+ DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray(),
RuntimeLang);
// If this is just a forward declaration, return it.
- if (Decl->isForwardDecl())
+ if (ID->isForwardDecl())
return FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
@@ -696,7 +899,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Convert all the elements.
llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
- ObjCInterfaceDecl *SClass = Decl->getSuperClass();
+ ObjCInterfaceDecl *SClass = ID->getSuperClass();
if (SClass) {
llvm::DIType SClassTy =
getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit);
@@ -707,11 +910,11 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
EltTys.push_back(InhTag);
}
- const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(Decl);
+ const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
unsigned FieldNo = 0;
- for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(),
- E = Decl->ivar_end(); I != E; ++I, ++FieldNo) {
+ for (ObjCInterfaceDecl::ivar_iterator I = ID->ivar_begin(),
+ E = ID->ivar_end(); I != E; ++I, ++FieldNo) {
ObjCIvarDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
@@ -769,7 +972,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit,
+ DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(), DefUnit,
Line, Size, Align, 0, 0, llvm::DIType(),
Elements, RuntimeLang);
@@ -782,13 +985,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DICompileUnit Unit) {
- EnumDecl *Decl = Ty->getDecl();
+ EnumDecl *ED = Ty->getDecl();
llvm::SmallVector<llvm::DIDescriptor, 32> Enumerators;
// Create DIEnumerator elements for each enumerator.
for (EnumDecl::enumerator_iterator
- Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end();
+ Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
Enum != EnumEnd; ++Enum) {
Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(),
Enum->getInitVal().getZExtValue()));
@@ -798,7 +1001,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIArray EltArray =
DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size());
- SourceLocation DefLoc = Decl->getLocation();
+ SourceLocation DefLoc = ED->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(DefLoc);
@@ -815,7 +1018,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type,
- Unit, Decl->getName(), DefUnit, Line,
+ Unit, ED->getName(), DefUnit, Line,
Size, Align, 0, 0,
llvm::DIType(), EltArray);
return DbgTy;
@@ -1083,6 +1286,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(FI->second));
if (!SP.isNull() && SP.isSubprogram() && SP.isDefinition()) {
RegionStack.push_back(SP.getNode());
+ RegionMap[D] = llvm::WeakVH(SP.getNode());
return;
}
}
@@ -1113,6 +1317,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
// Push function on region stack.
RegionStack.push_back(SP.getNode());
+ RegionMap[D] = llvm::WeakVH(SP.getNode());
}
@@ -1164,160 +1369,172 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) {
RegionStack.pop_back();
}
-/// EmitDeclare - Emit local variable declaration debug info.
-void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
- llvm::Value *Storage, CGBuilderTy &Builder) {
- assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
-
- // Do not emit variable debug information while generating optimized code.
- // The llvm optimizer and code generator are not yet ready to support
- // optimized code debugging.
- const CodeGenOptions &CGO = CGM.getCodeGenOpts();
- if (CGO.OptimizationLevel)
- return;
-
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
- QualType Type = Decl->getType();
- llvm::DIType Ty = getOrCreateType(Type, Unit);
- if (Decl->hasAttr<BlocksAttr>()) {
- llvm::DICompileUnit DefUnit;
- unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
+// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+// See BuildByRefType.
+llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+ uint64_t *XOffset) {
- llvm::SmallVector<llvm::DIDescriptor, 5> EltTys;
-
- llvm::DIType FieldTy;
+ llvm::SmallVector<llvm::DIDescriptor, 5> EltTys;
- QualType FType;
- uint64_t FieldSize, FieldOffset;
- unsigned FieldAlign;
+ QualType FType;
+ uint64_t FieldSize, FieldOffset;
+ unsigned FieldAlign;
+
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation());
+ QualType Type = VD->getType();
- llvm::DIArray Elements;
- llvm::DIType EltTy;
-
- // Build up structure for the byref. See BuildByRefType.
- FieldOffset = 0;
+ FieldOffset = 0;
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__isa", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__forwarding", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = CGM.getContext().IntTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__flags", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ FType = CGM.getContext().IntTy;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = CGM.getContext().getTypeAlign(FType);
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ "__size", llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
+ if (HasCopyAndDispose) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__isa", DefUnit,
+ "__copy_helper",
+ llvm::DICompileUnit(),
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
-
+
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__forwarding", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__flags", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__size", DefUnit,
+ "__destroy_helper",
+ llvm::DICompileUnit(),
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
+ }
+
+ 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;
- bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
- if (HasCopyAndDispose) {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__copy_helper", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
+ if (NumPaddingBytes > 0) {
+ llvm::APInt pad(32, NumPaddingBytes);
+ FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
+ pad, ArrayType::Normal, 0);
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__destroy_helper", DefUnit,
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
+ Unit, "", llvm::DICompileUnit(),
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
FieldOffset += FieldSize;
}
-
- unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl);
- if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) {
- unsigned AlignedOffsetInBytes
- = llvm::RoundUpToAlignment(FieldOffset/8, Align);
- unsigned NumPaddingBytes
- = AlignedOffsetInBytes - FieldOffset/8;
-
- if (NumPaddingBytes > 0) {
- llvm::APInt pad(32, NumPaddingBytes);
- FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
- pad, ArrayType::Normal, 0);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
- Unit, "", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
- }
- }
-
- FType = Type;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = Align*8;
-
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getName(), DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
-
- unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
+ }
+
+ FType = Type;
+ FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ FieldSize = CGM.getContext().getTypeSize(FType);
+ FieldAlign = Align.getQuantity()*8;
- Ty = DebugFactory.CreateCompositeType(Tag, Unit, "",
+ *XOffset = FieldOffset;
+ FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
+ VD->getName(), llvm::DICompileUnit(),
+ 0, FieldSize, FieldAlign,
+ FieldOffset, 0, FieldTy);
+ EltTys.push_back(FieldTy);
+ FieldOffset += FieldSize;
+
+ llvm::DIArray Elements =
+ DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
+
+ unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
+
+ return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type,
+ Unit, "",
llvm::DICompileUnit(),
0, FieldOffset, 0, 0, Flags,
llvm::DIType(), Elements);
- }
+
+}
+/// EmitDeclare - Emit local variable declaration debug info.
+void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
+ llvm::Value *Storage, CGBuilderTy &Builder) {
+ assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
+
+ // Do not emit variable debug information while generating optimized code.
+ // The llvm optimizer and code generator are not yet ready to support
+ // optimized code debugging.
+ const CodeGenOptions &CGO = CGM.getCodeGenOpts();
+ if (CGO.OptimizationLevel)
+ return;
+
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation());
+ llvm::DIType Ty;
+ uint64_t XOffset = 0;
+ if (VD->hasAttr<BlocksAttr>())
+ Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
+ else
+ Ty = getOrCreateType(VD->getType(), Unit);
// Get location information.
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation());
unsigned Line = 0;
unsigned Column = 0;
- if (!PLoc.isInvalid()) {
+ if (PLoc.isInvalid())
+ PLoc = SM.getPresumedLoc(CurLoc);
+ if (PLoc.isValid()) {
Line = PLoc.getLine();
Column = PLoc.getColumn();
+ Unit = getOrCreateCompileUnit(CurLoc);
} else {
Unit = llvm::DICompileUnit();
}
@@ -1325,7 +1542,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getName(),
+ VD->getName(),
Unit, Line, Ty);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1342,7 +1559,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
llvm::Value *Storage, CGBuilderTy &Builder,
CodeGenFunction *CGF) {
- const ValueDecl *Decl = BDRE->getDecl();
+ const ValueDecl *VD = BDRE->getDecl();
assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
// Do not emit variable debug information while generating optimized code.
@@ -1353,186 +1570,50 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
return;
uint64_t XOffset = 0;
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
- QualType Type = Decl->getType();
- llvm::DIType Ty = getOrCreateType(Type, Unit);
- if (Decl->hasAttr<BlocksAttr>()) {
- llvm::DICompileUnit DefUnit;
- unsigned Tag = llvm::dwarf::DW_TAG_structure_type;
-
- llvm::SmallVector<llvm::DIDescriptor, 5> EltTys;
-
- llvm::DIType FieldTy;
-
- QualType FType;
- uint64_t FieldSize, FieldOffset;
- unsigned FieldAlign;
-
- llvm::DIArray Elements;
- llvm::DIType EltTy;
-
- // Build up structure for the byref. See BuildByRefType.
- FieldOffset = 0;
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__isa", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__forwarding", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__flags", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().IntTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__size", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type);
- if (HasCopyAndDispose) {
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__copy_helper", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "__destroy_helper", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
- }
-
- unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl);
- if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) {
- unsigned AlignedOffsetInBytes
- = llvm::RoundUpToAlignment(FieldOffset/8, Align);
- unsigned NumPaddingBytes
- = AlignedOffsetInBytes - FieldOffset/8;
-
- if (NumPaddingBytes > 0) {
- llvm::APInt pad(32, NumPaddingBytes);
- FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
- pad, ArrayType::Normal, 0);
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
- Unit, "", DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
- }
- }
-
- FType = Type;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = Align*8;
-
- XOffset = FieldOffset;
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getName(), DefUnit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
- Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
-
- unsigned Flags = llvm::DIType::FlagBlockByrefStruct;
-
- Ty = DebugFactory.CreateCompositeType(Tag, Unit, "",
- llvm::DICompileUnit(),
- 0, FieldOffset, 0, 0, Flags,
- llvm::DIType(), Elements);
- }
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(VD->getLocation());
+ llvm::DIType Ty;
+ if (VD->hasAttr<BlocksAttr>())
+ Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
+ else
+ Ty = getOrCreateType(VD->getType(), Unit);
// Get location information.
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(VD->getLocation());
unsigned Line = 0;
if (!PLoc.isInvalid())
Line = PLoc.getLine();
else
Unit = llvm::DICompileUnit();
- CharUnits offset = CGF->BlockDecls[Decl];
+ CharUnits offset = CGF->BlockDecls[VD];
llvm::SmallVector<llvm::Value *, 9> addr;
- llvm::LLVMContext &VMContext = CGM.getLLVMContext();
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpDeref));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpPlus));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()));
+ const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
if (BDRE->isByRef()) {
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpDeref));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus));
// offset of __forwarding field
offset = CharUnits::fromQuantity(CGF->LLVMPointerWidth/8);
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpDeref));
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- llvm::DIFactory::OpPlus));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpDeref));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIFactory::OpPlus));
// offset of x field
offset = CharUnits::fromQuantity(XOffset/8);
- addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset.getQuantity()));
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
}
// Create the descriptor for the variable.
llvm::DIVariable D =
- DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getName(), Unit, Line, Ty,
+ DebugFactory.CreateComplexVariable(Tag,
+ llvm::DIDescriptor(RegionStack.back()),
+ VD->getName(), Unit, Line, Ty,
addr);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
- DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint());
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
llvm::DIScope DS(RegionStack.back());
llvm::DILocation DO(NULL);
@@ -1542,10 +1623,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
Call->setMetadata("dbg", DL.getNode());
}
-void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl,
+void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder) {
- EmitDeclare(Decl, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder);
+ EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder);
}
void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
@@ -1556,24 +1637,24 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
/// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument
/// variable declaration.
-void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
+void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
CGBuilderTy &Builder) {
- EmitDeclare(Decl, llvm::dwarf::DW_TAG_arg_variable, AI, Builder);
+ EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, Builder);
}
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- const VarDecl *Decl) {
-
+ const VarDecl *D) {
+
// Create global variable debug descriptor.
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(D->getLocation());
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(D->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- QualType T = Decl->getType();
+ QualType T = D->getType();
if (T->isIncompleteArrayType()) {
// CodeGen turns int[] into int[1] so we'll do the same here.
@@ -1585,9 +1666,11 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- llvm::StringRef DeclName = Decl->getName();
- DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName,
- llvm::StringRef(), Unit, LineNo,
+ llvm::StringRef DeclName = D->getName();
+ llvm::DIDescriptor DContext =
+ getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit);
+ DebugFactory.CreateGlobalVariable(DContext, DeclName,
+ DeclName, llvm::StringRef(), Unit, LineNo,
getOrCreateType(T, Unit),
Var->hasInternalLinkage(),
true/*definition*/, Var);
@@ -1595,16 +1678,16 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
/// EmitGlobalVariable - Emit information about an objective-c interface.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- ObjCInterfaceDecl *Decl) {
+ ObjCInterfaceDecl *ID) {
// Create global variable debug descriptor.
- llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
+ llvm::DICompileUnit Unit = getOrCreateCompileUnit(ID->getLocation());
SourceManager &SM = CGM.getContext().getSourceManager();
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ PresumedLoc PLoc = SM.getPresumedLoc(ID->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- llvm::StringRef Name = Decl->getName();
+ llvm::StringRef Name = ID->getName();
- QualType T = CGM.getContext().getObjCInterfaceType(Decl);
+ QualType T = CGM.getContext().getObjCInterfaceType(ID);
if (T->isIncompleteArrayType()) {
// CodeGen turns int[] into int[1] so we'll do the same here.
@@ -1622,3 +1705,26 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
Var->hasInternalLinkage(),
true/*definition*/, Var);
}
+
+/// getOrCreateNamesSpace - Return namespace descriptor for the given
+/// namespace decl.
+llvm::DINameSpace
+CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl,
+ llvm::DIDescriptor Unit) {
+ llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH>::iterator I =
+ NameSpaceCache.find(NSDecl);
+ if (I != NameSpaceCache.end())
+ return llvm::DINameSpace(cast<llvm::MDNode>(I->second));
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(NSDecl->getLocation());
+ unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
+
+ llvm::DIDescriptor Context =
+ getContextDescriptor(dyn_cast<Decl>(NSDecl->getDeclContext()), Unit);
+ llvm::DINameSpace NS =
+ DebugFactory.CreateNameSpace(Context, NSDecl->getName(),
+ llvm::DICompileUnit(Unit.getNode()), LineNo);
+ NameSpaceCache[NSDecl] = llvm::WeakVH(NS.getNode());
+ return NS;
+}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index fddd23b4e9c3..b2d3a1f1fa53 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -47,6 +47,8 @@ class CGDebugInfo {
llvm::DIFactory DebugFactory;
SourceLocation CurLoc, PrevLoc;
+
+ llvm::DIType VTablePtrType;
/// CompileUnitCache - Cache of previously constructed CompileUnits.
llvm::DenseMap<unsigned, llvm::DICompileUnit> CompileUnitCache;
@@ -59,12 +61,14 @@ class CGDebugInfo {
llvm::DIType BlockLiteralGeneric;
std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
+ llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
- /// FunctionNames - This is a storage for function names that are
+ /// DebugInfoNames - This is a storage for names that are
/// constructed on demand. For example, C++ destructors, C++ operators etc..
- llvm::BumpPtrAllocator FunctionNames;
+ llvm::BumpPtrAllocator DebugInfoNames;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
+ llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
/// Helper functions for getOrCreateType.
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
@@ -83,16 +87,37 @@ class CGDebugInfo {
llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U);
-
+ llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit);
+ llvm::DIType getOrCreateVTablePtrType(llvm::DICompileUnit Unit);
+ llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N,
+ llvm::DIDescriptor Unit);
+
llvm::DIType CreatePointerLikeType(unsigned Tag,
const Type *Ty, QualType PointeeTy,
llvm::DICompileUnit U);
+
+ llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
+ llvm::DICompileUnit Unit,
+ llvm::DICompositeType &RecordTy);
+
void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
llvm::DICompileUnit U,
llvm::SmallVectorImpl<llvm::DIDescriptor> &E,
llvm::DICompositeType &T);
+ void CollectCXXBases(const CXXRecordDecl *Decl,
+ llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys,
+ llvm::DICompositeType &RecordTy);
+
+
void CollectRecordFields(const RecordDecl *Decl, llvm::DICompileUnit U,
llvm::SmallVectorImpl<llvm::DIDescriptor> &E);
+
+ void CollectVtableInfo(const CXXRecordDecl *Decl,
+ llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys);
+
public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
@@ -150,8 +175,14 @@ private:
void EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, llvm::Value *AI,
CGBuilderTy &Builder, CodeGenFunction *CGF);
- /// getContext - Get context info for the decl.
- llvm::DIDescriptor getContext(const VarDecl *Decl,llvm::DIDescriptor &CU);
+ // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
+ // See BuildByRefType.
+ llvm::DIType EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+ uint64_t *OffSet);
+
+ /// getContextDescriptor - Get context info for the decl.
+ llvm::DIDescriptor getContextDescriptor(const Decl *Decl,
+ llvm::DIDescriptor &CU);
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a
/// new one if necessary.
@@ -168,6 +199,10 @@ private:
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
llvm::StringRef getFunctionName(const FunctionDecl *FD);
+
+ /// getVtableName - Get vtable name for the given Class.
+ llvm::StringRef getVtableName(const CXXRecordDecl *Decl);
+
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 9606a71527a4..793a22050677 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -76,8 +76,21 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) {
case VarDecl::Auto:
case VarDecl::Register:
return EmitLocalBlockVarDecl(D);
- case VarDecl::Static:
- return EmitStaticBlockVarDecl(D);
+ case VarDecl::Static: {
+ llvm::GlobalValue::LinkageTypes Linkage =
+ llvm::GlobalValue::InternalLinkage;
+
+ // If this is a static declaration inside an inline function, it must have
+ // weak linkage so that the linker will merge multiple definitions of it.
+ if (getContext().getLangOptions().CPlusPlus) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) {
+ if (FD->isInlined())
+ Linkage = llvm::GlobalValue::WeakAnyLinkage;
+ }
+ }
+
+ return EmitStaticBlockVarDecl(D, Linkage);
+ }
case VarDecl::Extern:
case VarDecl::PrivateExtern:
// Don't emit it now, allow it to be emitted lazily on its first use.
@@ -120,7 +133,7 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
Ty.isConstant(getContext()), Linkage,
CGM.EmitNullConstant(D.getType()), Name, 0,
D.isThreadSpecified(), Ty.getAddressSpace());
- GV->setAlignment(getContext().getDeclAlignInBytes(&D));
+ GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
return GV;
}
@@ -138,8 +151,13 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
if (!Init) {
if (!getContext().getLangOptions().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
- else
+ else {
+ // Since we have a static initializer, this global variable can't
+ // be constant.
+ GV->setConstant(false);
+
EmitStaticCXXBlockVarDeclInit(D, GV);
+ }
return GV;
}
@@ -172,12 +190,12 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
return GV;
}
-void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
+void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
+ llvm::GlobalValue::LinkageTypes Linkage) {
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
- llvm::GlobalVariable *GV =
- CreateStaticBlockVarDecl(D, ".", llvm::GlobalValue::InternalLinkage);
+ llvm::GlobalVariable *GV = CreateStaticBlockVarDecl(D, ".", Linkage);
// Store into LocalDeclMap before generating initializer to handle
// circular references.
@@ -281,8 +299,8 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) {
}
bool Packed = false;
- unsigned Align = getContext().getDeclAlignInBytes(D);
- if (Align > Target.getPointerAlign(0) / 8) {
+ CharUnits Align = getContext().getDeclAlign(D);
+ if (Align > CharUnits::fromQuantity(Target.getPointerAlign(0) / 8)) {
// We have to insert padding.
// The struct above has 2 32-bit integers.
@@ -294,7 +312,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) {
// Align the offset.
unsigned AlignedOffsetInBytes =
- llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align);
+ llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align.getQuantity());
unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
if (NumPaddingBytes > 0) {
@@ -334,7 +352,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
QualType Ty = D.getType();
bool isByRef = D.hasAttr<BlocksAttr>();
bool needsDispose = false;
- unsigned Align = 0;
+ CharUnits Align = CharUnits::Zero();
bool IsSimpleConstantInitializer = false;
llvm::Value *DeclPtr;
@@ -350,7 +368,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// If this variable is marked 'const', emit the value as a global.
if (CGM.getCodeGenOpts().MergeAllConstants &&
Ty.isConstant(getContext())) {
- EmitStaticBlockVarDecl(D);
+ EmitStaticBlockVarDecl(D, llvm::GlobalValue::InternalLinkage);
return;
}
@@ -364,10 +382,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
Alloc->setName(D.getNameAsString());
- Align = getContext().getDeclAlignInBytes(&D);
+ Align = getContext().getDeclAlign(&D);
if (isByRef)
- Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8));
- Alloc->setAlignment(Align);
+ Align = std::max(Align,
+ CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
+ Alloc->setAlignment(Align.getQuantity());
DeclPtr = Alloc;
} else {
// Targets that don't support recursion emit locals as globals.
@@ -420,7 +439,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Allocate memory for the array.
llvm::AllocaInst *VLA =
Builder.CreateAlloca(llvm::Type::getInt8Ty(VMContext), VLASize, "vla");
- VLA->setAlignment(getContext().getDeclAlignInBytes(&D));
+ VLA->setAlignment(getContext().getDeclAlign(&D).getQuantity());
DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp");
}
@@ -468,7 +487,8 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
assert(Init != 0 && "Wasn't a simple constant init?");
llvm::Value *AlignVal =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align);
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ Align.getQuantity());
const llvm::Type *IntPtr =
llvm::IntegerType::get(VMContext, LLVMPointerWidth);
llvm::Value *SizeVal =
@@ -492,7 +512,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
llvm::GlobalValue::InternalLinkage,
Init, Name, 0, false, 0);
- GV->setAlignment(Align);
+ GV->setAlignment(Align.getQuantity());
llvm::Value *SrcPtr = GV;
if (SrcPtr->getType() != BP)
@@ -501,7 +521,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal);
}
} else if (Ty->isReferenceType()) {
- RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true);
+ RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true);
EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty);
} else if (!hasAggregateLLVMType(Init->getType())) {
llvm::Value *V = EmitScalarExpr(Init);
@@ -554,19 +574,19 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *V1;
V1 = cast<llvm::PointerType>(DeclPtr->getType())->getElementType();
V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- (CGM.getTargetData().getTypeStoreSizeInBits(V1)
- / 8));
+ CGM.GetTargetTypeStoreSize(V1).getQuantity());
Builder.CreateStore(V, size_field);
if (flags & BLOCK_HAS_COPY_DISPOSE) {
BlockHasCopyDispose = true;
llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4);
- Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag, Align),
+ Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag,
+ Align.getQuantity()),
copy_helper);
llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5);
Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag,
- Align),
+ Align.getQuantity()),
destroy_helper);
}
}
@@ -683,25 +703,18 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) {
CanQualType CTy = getContext().getCanonicalType(Ty);
llvm::Value *DeclPtr;
- if (!Ty->isConstantSizeType()) {
- // Variable sized values always are passed by-reference.
+ // If this is an aggregate or variable sized value, reuse the input pointer.
+ if (!Ty->isConstantSizeType() ||
+ CodeGenFunction::hasAggregateLLVMType(Ty)) {
DeclPtr = Arg;
} else {
- // A fixed sized single-value variable becomes an alloca in the entry block.
- const llvm::Type *LTy = ConvertTypeForMem(Ty);
- if (LTy->isSingleValueType()) {
- // TODO: Alignment
- DeclPtr = CreateTempAlloca(LTy);
- DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr"));
-
- // Store the initial value into the alloca.
- EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty);
- } else {
- // Otherwise, if this is an aggregate, just use the input pointer.
- DeclPtr = Arg;
- }
- Arg->setName(D.getNameAsString());
+ // Otherwise, create a temporary to hold the value.
+ DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr");
+
+ // Store the initial value into the alloca.
+ EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty);
}
+ Arg->setName(D.getName());
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 47773a0d69e3..0de3b0be4b1a 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -80,8 +80,13 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
EmitDeclInit(*this, D, DeclPtr);
return;
}
-
- ErrorUnsupported(Init, "global variable that binds to a reference");
+ if (Init->isLvalue(getContext()) == Expr::LV_Valid) {
+ RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true);
+ EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T);
+ return;
+ }
+ ErrorUnsupported(Init,
+ "global variable that binds reference to a non-lvalue");
}
void
@@ -179,57 +184,120 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
+static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
+ // int __cxa_guard_acquire(__int64_t *guard_object);
+
+ const llvm::Type *Int64PtrTy =
+ llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+
+ std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy),
+ Args, /*isVarArg=*/false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
+}
+
+static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) {
+ // void __cxa_guard_release(__int64_t *guard_object);
+
+ const llvm::Type *Int64PtrTy =
+ llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+
+ std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Args, /*isVarArg=*/false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
+}
+
+static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) {
+ // void __cxa_guard_abort(__int64_t *guard_object);
+
+ const llvm::Type *Int64PtrTy =
+ llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
+
+ std::vector<const llvm::Type*> Args(1, Int64PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Args, /*isVarArg=*/false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
+}
+
void
CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
llvm::GlobalVariable *GV) {
- // FIXME: This should use __cxa_guard_{acquire,release}?
-
- assert(!getContext().getLangOptions().ThreadsafeStatics &&
- "thread safe statics are currently not supported!");
-
+ bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics;
+
llvm::SmallString<256> GuardVName;
CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
// Create the guard variable.
- llvm::GlobalValue *GuardV =
- new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext),
+ const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(VMContext);
+ llvm::GlobalValue *GuardVariable =
+ new llvm::GlobalVariable(CGM.getModule(), Int64Ty,
false, GV->getLinkage(),
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
+ llvm::Constant::getNullValue(Int64Ty),
GuardVName.str());
// Load the first byte of the guard variable.
const llvm::Type *PtrTy
= llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
- "tmp");
-
- // Compare it against 0.
- llvm::Value *nullValue
- = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
- llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
+ llvm::Value *V =
+ Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp");
- llvm::BasicBlock *InitBlock = createBasicBlock("init");
+ llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
- // If the guard variable is 0, jump to the initializer code.
- Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
+ // Check if the first byte of the guard variable is zero.
+ Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"),
+ InitCheckBlock, EndBlock);
- EmitBlock(InitBlock);
+ EmitBlock(InitCheckBlock);
+
+ if (ThreadsafeStatics) {
+ // Call __cxa_guard_acquire.
+ V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable);
+
+ llvm::BasicBlock *InitBlock = createBasicBlock("init");
+
+ Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
+ InitBlock, EndBlock);
+
+ EmitBlock(InitBlock);
+
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+
+ // Call __cxa_guard_abort.
+ Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
+ }
+ }
if (D.getType()->isReferenceType()) {
QualType T = D.getType();
// We don't want to pass true for IsInitializer here, because a static
// reference to a temporary does not extend its lifetime.
- RValue RV = EmitReferenceBindingToExpr(D.getInit(), T,
+ RValue RV = EmitReferenceBindingToExpr(D.getInit(),
/*IsInitializer=*/false);
EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T);
} else
EmitDeclInit(*this, D, GV);
- Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
- 1),
- Builder.CreateBitCast(GuardV, PtrTy));
+ if (ThreadsafeStatics) {
+ // Call __cxa_guard_release.
+ Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
+ } else {
+ llvm::Value *One =
+ llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1);
+ Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy));
+ }
EmitBlock(EndBlock);
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index bd0461fd2808..d956c1c3cd85 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -100,10 +100,6 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
-// FIXME: Eventually this will all go into the backend. Set from the target for
-// now.
-static int using_sjlj_exceptions = 0;
-
static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
@@ -112,7 +108,7 @@ static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
false);
- if (using_sjlj_exceptions)
+ if (CGF.CGM.getLangOptions().SjLjExceptions)
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
@@ -194,9 +190,9 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E,
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
CopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- CopyCtor->getType()->getAs<FunctionType>()->getResultType();
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ const FunctionProtoType *FPT
+ = CopyCtor->getType()->getAs<FunctionProtoType>();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, CopyCtor);
CGF.setInvokeDest(PrevLandingPad);
} else
@@ -244,9 +240,10 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
CopyCtor->getParamDecl(0)->getType()));
- QualType ResultType =
- CopyCtor->getType()->getAs<FunctionType>()->getResultType();
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+
+ const FunctionProtoType *FPT
+ = CopyCtor->getType()->getAs<FunctionProtoType>();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, CopyCtor);
} else
llvm_unreachable("uncopyable object");
@@ -316,6 +313,9 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
}
void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
+ if (!Exceptions)
+ return;
+
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
if (FD == 0)
return;
@@ -410,6 +410,9 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
}
void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
+ if (!Exceptions)
+ return;
+
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
if (FD == 0)
return;
@@ -466,6 +469,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
PushCleanupBlock(DtorEpilogue);
+ InitializeVtablePtrs(DD->getParent());
EmitStmt(S.getTryBlock());
CleanupBlockInfo Info = PopCleanupBlock();
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2358bb35923a..830954fd10cc 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -36,16 +36,24 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
}
+llvm::Value *CodeGenFunction::CreateMemTemp(QualType Ty, const llvm::Twine &Name) {
+ llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), Name);
+ // FIXME: Should we prefer the preferred type alignment here?
+ CharUnits Align = getContext().getTypeAlignInChars(Ty);
+ Alloc->setAlignment(Align.getQuantity());
+ return Alloc;
+}
+
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
QualType BoolTy = getContext().BoolTy;
if (E->getType()->isMemberFunctionPointerType()) {
- llvm::Value *Ptr = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Ptr, /*VolatileDest=*/false);
+ LValue LV = EmitAggExprToLValue(E);
// Get the pointer.
- llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr");
+ llvm::Value *FuncPtr = Builder.CreateStructGEP(LV.getAddress(), 0,
+ "src.ptr");
FuncPtr = Builder.CreateLoad(FuncPtr);
llvm::Value *IsNotNull =
@@ -87,13 +95,12 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E,
if (hasAggregateLLVMType(E->getType()) &&
!E->getType()->isAnyComplexType())
- AggLoc = CreateTempAlloca(ConvertType(E->getType()), "agg.tmp");
+ AggLoc = CreateMemTemp(E->getType(), "agg.tmp");
return EmitAnyExpr(E, AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false,
IsInitializer);
}
RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
- QualType DestType,
bool IsInitializer) {
bool ShouldDestroyTemporaries = false;
unsigned OldNumLiveTemporaries = 0;
@@ -114,8 +121,16 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
if (E->isLvalue(getContext()) == Expr::LV_Valid) {
// Emit the expr as an lvalue.
LValue LV = EmitLValue(E);
- if (LV.isSimple())
+ if (LV.isSimple()) {
+ if (ShouldDestroyTemporaries) {
+ // Pop temporaries.
+ while (LiveTemporaries.size() > OldNumLiveTemporaries)
+ PopCXXTemporary();
+ }
+
return RValue::get(LV.getAddress());
+ }
+
Val = EmitLoadOfLValue(LV, E->getType());
if (ShouldDestroyTemporaries) {
@@ -188,8 +203,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
Val = RValue::get(Val.getAggregateAddr());
} else {
// Create a temporary variable that we can bind the reference to.
- llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()),
- "reftmp");
+ llvm::Value *Temp = CreateMemTemp(E->getType(), "reftmp");
if (Val.isScalar())
EmitStoreOfScalar(Val.getScalarVal(), Temp, false, E->getType());
else
@@ -546,6 +560,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
cast<llvm::PointerType>(Ptr->getType())->getElementType();
// Simple scalar l-value.
+ //
+ // FIXME: We shouldn't have to use isSingleValueType here.
if (EltTy->isSingleValueType())
return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(),
ExprType));
@@ -1069,9 +1085,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);
+ // FIXME: the qualifier check does not seem sufficient here
if (E->getQualifier()) {
- // FIXME: the qualifier check does not seem sufficient here
- return EmitPointerToDataMemberLValue(cast<FieldDecl>(ND));
+ const FieldDecl *FD = cast<FieldDecl>(ND);
+ llvm::Value *V = CGM.EmitPointerToDataMember(FD);
+
+ return LValue::MakeAddr(V, MakeQualifiers(FD->getType()));
}
assert(false && "Unhandled DeclRefExpr");
@@ -1166,8 +1185,7 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) {
GlobalVarName += FnName;
std::string FunctionName =
- PredefinedExpr::ComputeName(getContext(), (PredefinedExpr::IdentType)Type,
- CurCodeDecl);
+ PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurCodeDecl);
llvm::Constant *C =
CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str());
@@ -1350,7 +1368,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
llvm::Value *Vec = EmitScalarExpr(E->getBase());
// Store the vector to memory (because LValue wants an address).
- llvm::Value *VecMem =CreateTempAlloca(ConvertType(E->getBase()->getType()));
+ llvm::Value *VecMem = CreateMemTemp(E->getBase()->getType());
Builder.CreateStore(Vec, VecMem);
Base = LValue::MakeAddr(VecMem, Qualifiers());
}
@@ -1381,7 +1399,6 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
- bool isUnion = false;
bool isNonGC = false;
Expr *BaseExpr = E->getBase();
llvm::Value *BaseValue = NULL;
@@ -1392,16 +1409,12 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
BaseValue = EmitScalarExpr(BaseExpr);
const PointerType *PTy =
BaseExpr->getType()->getAs<PointerType>();
- if (PTy->getPointeeType()->isUnionType())
- isUnion = true;
BaseQuals = PTy->getPointeeType().getQualifiers();
} else if (isa<ObjCPropertyRefExpr>(BaseExpr->IgnoreParens()) ||
isa<ObjCImplicitSetterGetterRefExpr>(
BaseExpr->IgnoreParens())) {
RValue RV = EmitObjCPropertyGet(BaseExpr);
BaseValue = RV.getAggregateAddr();
- if (BaseExpr->getType()->isUnionType())
- isUnion = true;
BaseQuals = BaseExpr->getType().getQualifiers();
} else {
LValue BaseLV = EmitLValue(BaseExpr);
@@ -1410,14 +1423,12 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
// FIXME: this isn't right for bitfields.
BaseValue = BaseLV.getAddress();
QualType BaseTy = BaseExpr->getType();
- if (BaseTy->isUnionType())
- isUnion = true;
BaseQuals = BaseTy.getQualifiers();
}
NamedDecl *ND = E->getMemberDecl();
if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
- LValue LV = EmitLValueForField(BaseValue, Field, isUnion,
+ LValue LV = EmitLValueForField(BaseValue, Field,
BaseQuals.getCVRQualifiers());
LValue::SetObjCNonGC(LV, isNonGC);
setObjCGCLValueClass(getContext(), E, LV);
@@ -1461,7 +1472,6 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
const FieldDecl* Field,
- bool isUnion,
unsigned CVRQualifiers) {
if (Field->isBitField())
return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers);
@@ -1470,7 +1480,7 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
// Match union field type.
- if (isUnion) {
+ if (Field->getParent()->isUnion()) {
const llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(Field->getType());
const llvm::PointerType * BaseTy =
@@ -1492,9 +1502,26 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
return LValue::MakeAddr(V, Quals);
}
+LValue
+CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue,
+ const FieldDecl* Field,
+ unsigned CVRQualifiers) {
+ QualType FieldType = Field->getType();
+
+ if (!FieldType->isReferenceType())
+ return EmitLValueForField(BaseValue, Field, CVRQualifiers);
+
+ unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
+
+ assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
+
+ return LValue::MakeAddr(V, MakeQualifiers(FieldType));
+}
+
LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
- const llvm::Type *LTy = ConvertType(E->getType());
- llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral");
+ llvm::Value *DeclPtr = CreateTempAlloca(ConvertTypeForMem(E->getType()),
+ ".compoundliteral");
const Expr* InitExpr = E->getInitializer();
LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType()));
@@ -1527,18 +1554,25 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBlock(LHSBlock);
-
LValue LHS = EmitLValue(E->getLHS());
+ EndConditionalBranch();
+
if (!LHS.isSimple())
return EmitUnsupportedLValue(E, "conditional operator");
+ // FIXME: We shouldn't need an alloca for this.
llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),"condtmp");
Builder.CreateStore(LHS.getAddress(), Temp);
EmitBranch(ContBlock);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBlock(RHSBlock);
LValue RHS = EmitLValue(E->getRHS());
+ EndConditionalBranch();
if (!RHS.isSimple())
return EmitUnsupportedLValue(E, "conditional operator");
@@ -1556,10 +1590,7 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
!E->getType()->isAnyComplexType()) &&
"Unexpected conditional operator!");
- llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Temp, false);
-
- return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ return EmitAggExprToLValue(E);
}
/// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast.
@@ -1606,12 +1637,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
}
- case CastExpr::CK_ToUnion: {
- llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
- EmitAnyExpr(E->getSubExpr(), Temp, false);
-
- return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
- }
+ case CastExpr::CK_ToUnion:
+ return EmitAggExprToLValue(E);
case CastExpr::CK_BaseToDerived: {
const RecordType *BaseClassTy =
E->getSubExpr()->getType()->getAs<RecordType>();
@@ -1646,13 +1673,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
LValue CodeGenFunction::EmitNullInitializationLValue(
const CXXZeroInitValueExpr *E) {
QualType Ty = E->getType();
- const llvm::Type *LTy = ConvertTypeForMem(Ty);
- llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- unsigned Align = getContext().getTypeAlign(Ty)/8;
- Alloc->setAlignment(Align);
- LValue lvalue = LValue::MakeAddr(Alloc, Qualifiers());
- EmitMemSetToZero(lvalue.getAddress(), Ty);
- return lvalue;
+ LValue LV = LValue::MakeAddr(CreateMemTemp(Ty), MakeQualifiers(Ty));
+ EmitMemSetToZero(LV.getAddress(), Ty);
+ return LV;
}
//===--------------------------------------------------------------------===//
@@ -1725,10 +1748,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
return LV;
}
- llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Temp, false);
- // FIXME: Are these qualifiers correct?
- return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ return EmitAggExprToLValue(E);
}
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -1746,13 +1766,11 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
// FIXME: This shouldn't require another copy.
- llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
- EmitAggExpr(E, Temp, false);
- return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+ return EmitAggExprToLValue(E);
}
LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
- llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp");
+ llvm::Value *Temp = CreateMemTemp(E->getType(), "tmp");
EmitCXXConstructExpr(Temp, E);
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
@@ -1840,21 +1858,6 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType()));
}
-
-LValue CodeGenFunction::EmitPointerToDataMemberLValue(const FieldDecl *Field) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext());
- QualType NNSpecTy =
- getContext().getCanonicalType(
- getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(ClassDecl)));
- NNSpecTy = getContext().getPointerType(NNSpecTy);
- llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy));
- LValue MemExpLV = EmitLValueForField(V, Field, /*isUnion=*/false,
- /*Qualifiers=*/0);
- const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType());
- V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember");
- return LValue::MakeAddr(V, MakeQualifiers(Field->getType()));
-}
-
RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg,
@@ -1867,20 +1870,14 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
CalleeType = getContext().getCanonicalType(CalleeType);
- QualType FnType = cast<PointerType>(CalleeType)->getPointeeType();
- QualType ResultType = cast<FunctionType>(FnType)->getResultType();
+ const FunctionType *FnType
+ = cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType());
+ QualType ResultType = FnType->getResultType();
CallArgList Args;
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
- // FIXME: We should not need to do this, it should be part of the function
- // type.
- unsigned CallingConvention = 0;
- if (const llvm::Function *F =
- dyn_cast<llvm::Function>(Callee->stripPointerCasts()))
- CallingConvention = F->getCallingConv();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
- CallingConvention),
+ return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType),
Callee, ReturnValue, Args, TargetDecl);
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index c852d65b859f..97455c7b13cf 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -118,7 +118,7 @@ public:
void VisitVAArgExpr(VAArgExpr *E);
- void EmitInitializationToLValue(Expr *E, LValue Address);
+ void EmitInitializationToLValue(Expr *E, LValue Address, QualType T);
void EmitNullInitializationToLValue(LValue Address, QualType T);
// case Expr::ChooseExprClass:
void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
@@ -147,7 +147,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
return;
// If the source is volatile, we must read from it; to do that, we need
// some place to put it.
- DestPtr = CGF.CreateTempAlloca(CGF.ConvertType(E->getType()), "agg.tmp");
+ DestPtr = CGF.CreateMemTemp(E->getType(), "agg.tmp");
}
if (RequiresGCollection) {
@@ -188,7 +188,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr,
CGF.ConvertType(PtrTy));
EmitInitializationToLValue(E->getSubExpr(),
- LValue::MakeAddr(CastPtr, Qualifiers()));
+ LValue::MakeAddr(CastPtr, Qualifiers()),
+ E->getType());
break;
}
@@ -227,8 +228,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CastExpr::CK_BaseToDerivedMemberPointer: {
QualType SrcType = E->getSubExpr()->getType();
- llvm::Value *Src = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(SrcType),
- "tmp");
+ llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp");
CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified());
llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
@@ -252,8 +252,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
std::swap(DerivedDecl, BaseDecl);
- llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
- if (Adj) {
+ if (llvm::Constant *Adj =
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
else
@@ -326,10 +326,18 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
int64_t Index =
CGF.CGM.getVtableInfo().getMethodVtableIndex(MD);
- FuncPtr = llvm::ConstantInt::get(PtrDiffTy, Index + 1);
+ // Itanium C++ ABI 2.3:
+ // For a non-virtual function, this field is a simple function pointer.
+ // For a virtual function, it is 1 plus the virtual table offset
+ // (in bytes) of the function, represented as a ptrdiff_t.
+ FuncPtr = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
} else {
- FuncPtr = llvm::ConstantExpr::getPtrToInt(CGF.CGM.GetAddrOfFunction(MD),
- PtrDiffTy);
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGF.CGM.getTypes().GetFunctionType(CGF.CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *Fn = CGF.CGM.GetAddrOfFunction(MD, Ty);
+ FuncPtr = llvm::ConstantExpr::getPtrToInt(Fn, PtrDiffTy);
}
Builder.CreateStore(FuncPtr, DstPtr, VolatileDest);
@@ -371,14 +379,14 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (LHS.isPropertyRef()) {
llvm::Value *AggLoc = DestPtr;
if (!AggLoc)
- AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType()));
+ AggLoc = CGF.CreateMemTemp(E->getRHS()->getType());
CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(),
RValue::getAggregate(AggLoc, VolatileDest));
} else if (LHS.isKVCRef()) {
llvm::Value *AggLoc = DestPtr;
if (!AggLoc)
- AggLoc = CGF.CreateTempAlloca(CGF.ConvertType(E->getRHS()->getType()));
+ AggLoc = CGF.CreateMemTemp(E->getRHS()->getType());
CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest);
CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(),
RValue::getAggregate(AggLoc, VolatileDest));
@@ -408,21 +416,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
assert(E->getLHS() && "Must have LHS for aggregate value");
Visit(E->getLHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
CGF.EmitBranch(ContBlock);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(RHSBlock);
Visit(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock);
@@ -449,7 +457,7 @@ void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
// FIXME: volatile
CGF.EmitAggExpr(E->getSubExpr(), Val, false);
@@ -467,7 +475,7 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
if (E->requiresZeroInitialization())
@@ -484,7 +492,7 @@ void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer);
}
@@ -494,7 +502,7 @@ void AggExprEmitter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
LValue LV = LValue::MakeAddr(Val, Qualifiers());
EmitNullInitializationToLValue(LV, E->getType());
@@ -505,23 +513,27 @@ void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
if (!Val) {
// Create a temporary variable.
- Val = CGF.CreateTempAlloca(CGF.ConvertTypeForMem(E->getType()), "tmp");
+ Val = CGF.CreateMemTemp(E->getType(), "tmp");
}
LValue LV = LValue::MakeAddr(Val, Qualifiers());
EmitNullInitializationToLValue(LV, E->getType());
}
-void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
+void
+AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) {
// FIXME: Ignore result?
// FIXME: Are initializers affected by volatile?
if (isa<ImplicitValueInitExpr>(E)) {
- EmitNullInitializationToLValue(LV, E->getType());
- } else if (E->getType()->isComplexType()) {
+ EmitNullInitializationToLValue(LV, T);
+ } else if (T->isReferenceType()) {
+ RValue RV = CGF.EmitReferenceBindingToExpr(E, /*IsInitializer=*/false);
+ CGF.EmitStoreThroughLValue(RV, LV, T);
+ } else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
- } else if (CGF.hasAggregateLLVMType(E->getType())) {
+ } else if (CGF.hasAggregateLLVMType(T)) {
CGF.EmitAnyExpr(E, LV.getAddress(), false);
} else {
- CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, E->getType());
+ CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, T);
}
}
@@ -590,7 +602,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array");
if (i < NumInitElements)
EmitInitializationToLValue(E->getInit(i),
- LValue::MakeAddr(NextVal, Quals));
+ LValue::MakeAddr(NextVal, Quals),
+ ElementType);
else
EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, Quals),
ElementType);
@@ -627,11 +640,11 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// FIXME: volatility
FieldDecl *Field = E->getInitializedFieldInUnion();
- LValue FieldLoc = CGF.EmitLValueForField(DestPtr, Field, true, 0);
+ LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, Field, 0);
if (NumInitElements) {
// Store the initializer into the field
- EmitInitializationToLValue(E->getInit(0), FieldLoc);
+ EmitInitializationToLValue(E->getInit(0), FieldLoc, Field->getType());
} else {
// Default-initialize to null
EmitNullInitializationToLValue(FieldLoc, Field->getType());
@@ -653,12 +666,13 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
continue;
// FIXME: volatility
- LValue FieldLoc = CGF.EmitLValueForField(DestPtr, *Field, false, 0);
+ LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, *Field, 0);
// We never generate write-barries for initialized fields.
LValue::SetObjCNonGC(FieldLoc, true);
if (CurInitVal < NumInitElements) {
// Store the initializer into the field
- EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc);
+ EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc,
+ Field->getType());
} else {
// We're out of initalizers; default-initialize to null
EmitNullInitializationToLValue(FieldLoc, Field->getType());
@@ -674,6 +688,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
/// type. The result is computed into DestPtr. Note that if DestPtr is null,
/// the value of the aggregate expression is not needed. If VolatileDest is
/// true, DestPtr cannot be 0.
+//
+// FIXME: Take Qualifiers object.
void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
bool VolatileDest, bool IgnoreResult,
bool IsInitializer,
@@ -688,6 +704,14 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr,
.Visit(const_cast<Expr*>(E));
}
+LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
+ assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
+ Qualifiers Q = MakeQualifiers(E->getType());
+ llvm::Value *Temp = CreateMemTemp(E->getType());
+ EmitAggExpr(E, Temp, Q.hasVolatile());
+ return LValue::MakeAddr(Temp, Q);
+}
+
void CodeGenFunction::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index e264109f02f0..032862160464 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -42,8 +42,10 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
// And the rest of the call args
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ QualType ResultType = FPT->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
+ FPT->getCallConv(),
+ FPT->getNoReturnAttr()), Callee,
ReturnValue, Args, MD);
}
@@ -60,7 +62,7 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
}
// We can always devirtualize calls on temporary object expressions.
- if (isa<CXXTemporaryObjectExpr>(Base))
+ if (isa<CXXConstructExpr>(Base))
return true;
// And calls on bound temporaries.
@@ -159,12 +161,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
FPT->isVariadic());
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
// Get the member function pointer.
- llvm::Value *MemFnPtr =
- CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
+ llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn");
EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
// Emit the 'this' pointer.
@@ -206,19 +206,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
EmitBlock(FnVirtual);
- const llvm::Type *VTableTy =
- FTy->getPointerTo()->getPointerTo()->getPointerTo();
+ const llvm::Type *VtableTy =
+ FTy->getPointerTo()->getPointerTo();
- llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
- VTable = Builder.CreateLoad(VTable);
+ llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo());
+ Vtable = Builder.CreateLoad(Vtable);
- VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
+ Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy);
+ llvm::Value *VtableOffset =
+ Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1));
- // Since the function pointer is 1 plus the virtual table offset, we
- // subtract 1 by using a GEP.
- VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
+ Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn");
+ Vtable = Builder.CreateBitCast(Vtable, VtableTy);
- llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+ llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn");
EmitBranch(FnEnd);
EmitBlock(FnNonVirtual);
@@ -244,8 +245,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
- QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>();
+ return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee,
ReturnValue, Args);
}
@@ -339,18 +340,20 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
}
else
// Call the constructor.
- EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
+ EmitCXXConstructorCall(CD,
+ E->isBaseInitialization()? Ctor_Base : Ctor_Complete,
+ Dest,
E->arg_begin(), E->arg_end());
}
-static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
+static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
const RecordType *RT = ElementType->getAs<RecordType>();
if (!RT)
- return 0;
+ return CharUnits::Zero();
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
- return 0;
+ return CharUnits::Zero();
// Check if the class has a trivial destructor.
if (RD->hasTrivialDestructor()) {
@@ -372,25 +375,25 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
// No usual deallocation function, we don't need a cookie.
if (!UsualDeallocationFunction)
- return 0;
+ return CharUnits::Zero();
// The usual deallocation function doesn't take a size_t argument, so we
// don't need a cookie.
if (UsualDeallocationFunction->getNumParams() == 1)
- return 0;
+ return CharUnits::Zero();
assert(UsualDeallocationFunction->getNumParams() == 2 &&
"Unexpected deallocation function type!");
}
// Padding is the maximum of sizeof(size_t) and alignof(ElementType)
- return std::max(Ctx.getTypeSize(Ctx.getSizeType()),
- static_cast<uint64_t>(Ctx.getTypeAlign(ElementType))) / 8;
+ return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
+ Ctx.getTypeAlignInChars(ElementType));
}
-static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
+static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
if (!E->isArray())
- return 0;
+ return CharUnits::Zero();
// No cookie is required if the new operator being used is
// ::operator new[](size_t, void*).
@@ -401,7 +404,7 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType());
if (ParamType == Ctx.VoidPtrTy)
- return 0;
+ return CharUnits::Zero();
}
}
@@ -412,25 +415,25 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
const CXXNewExpr *E,
llvm::Value *& NumElements) {
QualType Type = E->getAllocatedType();
- uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8;
+ CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(Type);
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
if (!E->isArray())
- return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes);
+ return llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
- uint64_t CookiePadding = CalculateCookiePadding(CGF.getContext(), E);
+ CharUnits CookiePadding = CalculateCookiePadding(CGF.getContext(), E);
Expr::EvalResult Result;
if (E->getArraySize()->Evaluate(Result, CGF.getContext()) &&
!Result.HasSideEffects && Result.Val.isInt()) {
- uint64_t AllocSize =
- Result.Val.getInt().getZExtValue() * TypeSizeInBytes + CookiePadding;
+ CharUnits AllocSize =
+ Result.Val.getInt().getZExtValue() * TypeSize + CookiePadding;
NumElements =
llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue());
- return llvm::ConstantInt::get(SizeTy, AllocSize);
+ return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity());
}
// Emit the array size expression.
@@ -439,11 +442,13 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// Multiply with the type size.
llvm::Value *V =
CGF.Builder.CreateMul(NumElements,
- llvm::ConstantInt::get(SizeTy, TypeSizeInBytes));
+ llvm::ConstantInt::get(SizeTy,
+ TypeSize.getQuantity()));
// And add the cookie padding if necessary.
- if (CookiePadding)
- V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding));
+ if (!CookiePadding.isZero())
+ V = CGF.Builder.CreateAdd(V,
+ llvm::ConstantInt::get(SizeTy, CookiePadding.getQuantity()));
return V;
}
@@ -538,7 +543,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Emit the call to new.
RValue RV =
- EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy),
CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD);
// If an allocation function is declared with an empty exception specification
@@ -567,20 +572,22 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
Builder.CreateCondBr(IsNull, NewNull, NewNotNull);
EmitBlock(NewNotNull);
}
-
- if (uint64_t CookiePadding = CalculateCookiePadding(getContext(), E)) {
- uint64_t CookieOffset =
- CookiePadding - getContext().getTypeSize(SizeTy) / 8;
+
+ CharUnits CookiePadding = CalculateCookiePadding(getContext(), E);
+ if (!CookiePadding.isZero()) {
+ CharUnits CookieOffset =
+ CookiePadding - getContext().getTypeSizeInChars(SizeTy);
llvm::Value *NumElementsPtr =
- Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset);
+ Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset.getQuantity());
NumElementsPtr = Builder.CreateBitCast(NumElementsPtr,
ConvertType(SizeTy)->getPointerTo());
Builder.CreateStore(NumElements, NumElementsPtr);
// Now add the padding to the new ptr.
- NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, CookiePadding);
+ NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr,
+ CookiePadding.getQuantity());
}
NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
@@ -611,23 +618,24 @@ GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF,
QualType SizeTy = CGF.getContext().getSizeType();
const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
- uint64_t DeleteTypeAlign = CGF.getContext().getTypeAlign(DeleteTy);
- uint64_t CookiePadding = std::max(CGF.getContext().getTypeSize(SizeTy),
- DeleteTypeAlign) / 8;
- assert(CookiePadding && "CookiePadding should not be 0.");
+ CharUnits DeleteTypeAlign = CGF.getContext().getTypeAlignInChars(DeleteTy);
+ CharUnits CookiePadding =
+ std::max(CGF.getContext().getTypeSizeInChars(SizeTy),
+ DeleteTypeAlign);
+ assert(!CookiePadding.isZero() && "CookiePadding should not be 0.");
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- uint64_t CookieOffset =
- CookiePadding - CGF.getContext().getTypeSize(SizeTy) / 8;
+ CharUnits CookieOffset =
+ CookiePadding - CGF.getContext().getTypeSizeInChars(SizeTy);
llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
AllocatedObjectPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
- -CookiePadding);
+ -CookiePadding.getQuantity());
llvm::Value *NumElementsPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
- CookieOffset);
+ CookieOffset.getQuantity());
NumElementsPtr =
CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo());
@@ -651,13 +659,13 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
QualType SizeTy;
if (DeleteFTy->getNumArgs() == 2) {
SizeTy = DeleteFTy->getArgType(1);
- uint64_t DeleteTypeSize = getContext().getTypeSize(DeleteTy) / 8;
- Size = llvm::ConstantInt::get(ConvertType(SizeTy), DeleteTypeSize);
+ CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
+ Size = llvm::ConstantInt::get(ConvertType(SizeTy),
+ DeleteTypeSize.getQuantity());
}
if (DeleteFD->getOverloadedOperator() == OO_Array_Delete &&
-
- CalculateCookiePadding(getContext(), DeleteTy)) {
+ !CalculateCookiePadding(getContext(), DeleteTy).isZero()) {
// We need to get the number of elements in the array from the cookie.
llvm::Value *AllocatedObjectPtr;
llvm::Value *NumElements;
@@ -679,8 +687,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
// Emit the call to delete.
- EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
- DeleteArgs),
+ EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy),
CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
DeleteArgs, DeleteFD);
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 5ec336ce79e9..591534042f51 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -366,7 +366,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
ComplexPairTy Op = Visit(E->getSubExpr());
llvm::Value *ResR, *ResI;
- if (Op.first->getType()->isFloatingPoint()) {
+ if (Op.first->getType()->isFloatingPointTy()) {
ResR = Builder.CreateFNeg(Op.first, "neg.r");
ResI = Builder.CreateFNeg(Op.second, "neg.i");
} else {
@@ -384,7 +384,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
// ~(a+ib) = a + i*-b
ComplexPairTy Op = Visit(E->getSubExpr());
llvm::Value *ResI;
- if (Op.second->getType()->isFloatingPoint())
+ if (Op.second->getType()->isFloatingPointTy())
ResI = Builder.CreateFNeg(Op.second, "conj.i");
else
ResI = Builder.CreateNeg(Op.second, "conj.i");
@@ -395,7 +395,7 @@ ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r");
ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i");
} else {
@@ -407,7 +407,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r");
ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i");
} else {
@@ -422,7 +422,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
using llvm::Value;
Value *ResR, *ResI;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
Value *ResRl = Builder.CreateFMul(Op.LHS.first, Op.RHS.first, "mul.rl");
Value *ResRr = Builder.CreateFMul(Op.LHS.second, Op.RHS.second,"mul.rr");
ResR = Builder.CreateFSub(ResRl, ResRr, "mul.r");
@@ -448,7 +448,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *DSTr, *DSTi;
- if (Op.LHS.first->getType()->isFloatingPoint()) {
+ if (Op.LHS.first->getType()->isFloatingPointTy()) {
// (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
llvm::Value *Tmp1 = Builder.CreateFMul(LHSr, RHSr, "tmp"); // a*c
llvm::Value *Tmp2 = Builder.CreateFMul(LHSi, RHSi, "tmp"); // b*d
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 7d5b3da0b6c6..3df552d75bb6 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -418,12 +418,19 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
-
- // The pointer is 1 + the virtual table offset in bytes.
+
+ // Itanium C++ ABI 2.3:
+ // For a non-virtual function, this field is a simple function pointer.
+ // For a virtual function, it is 1 plus the virtual table offset
+ // (in bytes) of the function, represented as a ptrdiff_t.
Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
} else {
- llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD);
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD, Ty);
Values[0] = llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy);
}
@@ -438,16 +445,16 @@ public:
if (const MemberPointerType *MPT =
E->getType()->getAs<MemberPointerType>()) {
QualType T = MPT->getPointeeType();
- if (T->isFunctionProtoType()) {
- DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
-
- return EmitMemberFunctionPointer(cast<CXXMethodDecl>(DRE->getDecl()));
- }
+ DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
+
+ NamedDecl *ND = DRE->getDecl();
+ if (T->isFunctionProtoType())
+ return EmitMemberFunctionPointer(cast<CXXMethodDecl>(ND));
- // FIXME: Should we handle other member pointer types here too,
- // or should they be handled by Expr::Evaluate?
+ // We have a pointer to data member.
+ return CGM.EmitPointerToDataMember(cast<FieldDecl>(ND));
}
-
+
return 0;
}
@@ -534,8 +541,8 @@ public:
llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C);
// Check if we need to update the adjustment.
- if (llvm::Constant *Offset = CGM.GetCXXBaseClassOffset(DerivedClass,
- BaseClass)) {
+ if (llvm::Constant *Offset =
+ CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) {
llvm::Constant *Values[2];
Values[0] = CS->getOperand(0);
@@ -668,6 +675,40 @@ public:
return 0;
}
+ llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (!E->getConstructor()->isTrivial())
+ return 0;
+
+ QualType Ty = E->getType();
+
+ // FIXME: We should not have to call getBaseElementType here.
+ const RecordType *RT =
+ CGM.getContext().getBaseElementType(Ty)->getAs<RecordType>();
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // If the class doesn't have a trivial destructor, we can't emit it as a
+ // constant expr.
+ if (!RD->hasTrivialDestructor())
+ return 0;
+
+ // Only copy and default constructors can be trivial.
+
+
+ if (E->getNumArgs()) {
+ assert(E->getNumArgs() == 1 && "trivial ctor with > 1 argument");
+ assert(E->getConstructor()->isCopyConstructor() &&
+ "trivial ctor has argument but isn't a copy ctor");
+
+ Expr *Arg = E->getArg(0);
+ assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) &&
+ "argument to copy ctor is of wrong type");
+
+ return Visit(Arg);
+ }
+
+ return CGM.EmitNullConstant(Ty);
+ }
+
llvm::Constant *VisitStringLiteral(StringLiteral *E) {
assert(!E->getType()->isPointerType() && "Strings are always arrays");
@@ -911,7 +952,24 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
return C;
}
-static inline bool isDataMemberPointerType(QualType T) {
+static bool containsPointerToDataMember(CodeGenTypes &Types, QualType T) {
+ // No need to check for member pointers when not compiling C++.
+ if (!Types.getContext().getLangOptions().CPlusPlus)
+ return false;
+
+ T = Types.getContext().getBaseElementType(T);
+
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // FIXME: It would be better if there was a way to explicitly compute the
+ // record layout instead of converting to a type.
+ Types.ConvertTagDeclType(RD);
+
+ const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+ return Layout.containsPointerToDataMember();
+ }
+
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
return !MPT->getPointeeType()->isFunctionType();
@@ -919,43 +977,80 @@ static inline bool isDataMemberPointerType(QualType T) {
}
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
- // No need to check for member pointers when not compiling C++.
- if (!getContext().getLangOptions().CPlusPlus)
+ if (!containsPointerToDataMember(getTypes(), T))
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
-
+
if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
QualType ElementTy = CAT->getElementType();
- // FIXME: Handle arrays of structs that contain member pointers.
- if (isDataMemberPointerType(Context.getBaseElementType(ElementTy))) {
- llvm::Constant *Element = EmitNullConstant(ElementTy);
- uint64_t NumElements = CAT->getSize().getZExtValue();
- std::vector<llvm::Constant *> Array(NumElements);
- for (uint64_t i = 0; i != NumElements; ++i)
- Array[i] = Element;
+ llvm::Constant *Element = EmitNullConstant(ElementTy);
+ unsigned NumElements = CAT->getSize().getZExtValue();
+ std::vector<llvm::Constant *> Array(NumElements);
+ for (unsigned i = 0; i != NumElements; ++i)
+ Array[i] = Element;
- const llvm::ArrayType *ATy =
- cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
- return llvm::ConstantArray::get(ATy, Array);
- }
+ const llvm::ArrayType *ATy =
+ cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
+ return llvm::ConstantArray::get(ATy, Array);
}
if (const RecordType *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- // FIXME: It would be better if there was a way to explicitly compute the
- // record layout instead of converting to a type.
- Types.ConvertTagDeclType(RD);
-
- const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
- if (Layout.containsMemberPointer()) {
- assert(0 && "FIXME: No support for structs with member pointers yet!");
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ assert(!RD->getNumBases() &&
+ "FIXME: Handle zero-initializing structs with bases and "
+ "pointers to data members.");
+ const llvm::StructType *STy =
+ cast<llvm::StructType>(getTypes().ConvertTypeForMem(T));
+ unsigned NumElements = STy->getNumElements();
+ std::vector<llvm::Constant *> Elements(NumElements);
+
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I) {
+ const FieldDecl *FD = *I;
+
+ unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ Elements[FieldNo] = EmitNullConstant(FD->getType());
+ }
+
+ // Now go through all other fields and zero them out.
+ for (unsigned i = 0; i != NumElements; ++i) {
+ if (!Elements[i])
+ Elements[i] = llvm::Constant::getNullValue(STy->getElementType(i));
}
+
+ return llvm::ConstantStruct::get(STy, Elements);
}
- // FIXME: Handle structs that contain member pointers.
- if (isDataMemberPointerType(T))
- return llvm::Constant::getAllOnesValue(getTypes().ConvertTypeForMem(T));
+ assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
+ "Should only see pointers to data members here!");
+
+ // Itanium C++ ABI 2.3:
+ // A NULL pointer is represented as -1.
+ return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1ULL,
+ /*isSigned=*/true);
+}
+
+llvm::Constant *
+CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) {
+
+ // Itanium C++ ABI 2.3:
+ // A pointer to data member is an offset from the base address of the class
+ // object containing it, represented as a ptrdiff_t
+
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(FD->getParent());
+ QualType ClassType =
+ getContext().getTypeDeclType(const_cast<CXXRecordDecl *>(ClassDecl));
+
+ const llvm::StructType *ClassLTy =
+ cast<llvm::StructType>(getTypes().ConvertType(ClassType));
+
+ unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ uint64_t Offset =
+ getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo);
+
+ const llvm::Type *PtrDiffTy =
+ getTypes().ConvertType(getContext().getPointerDiffType());
- return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
+ return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 690a7dc2fded..db0998b4dedc 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -290,7 +290,7 @@ public:
if (CGF.getContext().getLangOptions().OverflowChecking
&& Ops.Ty->isSignedIntegerType())
return EmitOverflowCheckedBinOp(Ops);
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
}
@@ -388,8 +388,6 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
}
if (SrcType->isMemberPointerType()) {
- // FIXME: This is ABI specific.
-
// Compare against -1.
llvm::Value *NegativeOne = llvm::Constant::getAllOnesValue(Src->getType());
return Builder.CreateICmpNE(Src, NegativeOne, "tobool");
@@ -507,7 +505,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateUIToFP(Src, DstTy, "conv");
}
- assert(Src->getType()->isFloatingPoint() && "Unknown real conversion");
+ assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion");
if (isa<llvm::IntegerType>(DstTy)) {
if (DstType->isSignedIntegerType())
return Builder.CreateFPToSI(Src, DstTy, "conv");
@@ -515,7 +513,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateFPToUI(Src, DstTy, "conv");
}
- assert(DstTy->isFloatingPoint() && "Unknown real conversion");
+ assert(DstTy->isFloatingPointTy() && "Unknown real conversion");
if (DstTy->getTypeID() < Src->getType()->getTypeID())
return Builder.CreateFPTrunc(Src, DstTy, "conv");
else
@@ -891,8 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
std::swap(DerivedDecl, BaseDecl);
- llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
- if (Adj) {
+ if (llvm::Constant *Adj =
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
Src = Builder.CreateSub(Src, Adj, "adj");
else
@@ -1009,7 +1007,7 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreResultAssign();
Value *Op = Visit(E->getSubExpr());
- if (Op->getType()->isFPOrFPVector())
+ if (Op->getType()->isFPOrFPVectorTy())
return Builder.CreateFNeg(Op, "neg");
return Builder.CreateNeg(Op, "neg");
}
@@ -1154,7 +1152,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
else if (Ops.Ty->isUnsignedIntegerType())
return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div");
@@ -1261,7 +1259,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
Ops.Ty->isSignedIntegerType())
return EmitOverflowCheckedBinOp(Ops);
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFAdd(Ops.LHS, Ops.RHS, "add");
// Signed integer overflow is undefined behavior.
@@ -1337,7 +1335,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
&& Ops.Ty->isSignedIntegerType())
return EmitOverflowCheckedBinOp(Ops);
- if (Ops.LHS->getType()->isFPOrFPVector())
+ if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub");
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
}
@@ -1505,7 +1503,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
- if (LHS->getType()->isFPOrFPVector()) {
+ if (LHS->getType()->isFPOrFPVectorTy()) {
Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc,
LHS, RHS, "cmp");
} else if (LHSTy->isSignedIntegerType()) {
@@ -1615,10 +1613,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1665,13 +1663,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
// Emit the RHS condition as a bool value.
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1785,7 +1783,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
}
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
@@ -1795,15 +1793,15 @@ VisitConditionalOperator(const ConditionalOperator *E) {
else // Perform promotions, to handle cases like "short ?: int"
LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
LHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
- CGF.StartConditionalBranch();
+ CGF.BeginConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHS = Visit(E->getRHS());
- CGF.FinishConditionalBranch();
+ CGF.EndConditionalBranch();
RHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
@@ -1882,14 +1880,23 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
llvm::Value *V;
// object->isa or (*object).isa
// Generate code as for: *(Class*)object
+ // build Class* type
+ const llvm::Type *ClassPtrTy = ConvertType(E->getType());
+
Expr *BaseExpr = E->getBase();
- if (E->isArrow())
- V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
- else
- V = EmitLValue(BaseExpr).getAddress();
+ if (BaseExpr->isLvalue(getContext()) != Expr::LV_Valid) {
+ V = CreateTempAlloca(ClassPtrTy, "resval");
+ llvm::Value *Src = EmitScalarExpr(BaseExpr);
+ Builder.CreateStore(Src, V);
+ }
+ else {
+ if (E->isArrow())
+ V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
+ else
+ V = EmitLValue(BaseExpr).getAddress();
+ }
// build Class* type
- const llvm::Type *ClassPtrTy = ConvertType(E->getType());
ClassPtrTy = ClassPtrTy->getPointerTo();
V = Builder.CreateBitCast(V, ClassPtrTy);
LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 896d2207ea4b..b62e6ed44366 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -122,7 +122,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
E = OMD->param_end(); PI != E; ++PI)
Args.push_back(std::make_pair(*PI, (*PI)->getType()));
- StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocEnd());
+ StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocStart());
}
/// Generate an Objective-C method. An Objective-C method is a C function with
@@ -190,7 +190,8 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
Args.push_back(std::make_pair(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),
+ RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args,
+ CC_Default, false),
GetPropertyFn, ReturnValueSlot(), Args);
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
@@ -278,7 +279,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
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), SetPropertyFn,
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
+ CC_Default, false), SetPropertyFn,
ReturnValueSlot(), Args);
} else {
// FIXME: Find a clean way to avoid AST node creation.
@@ -450,9 +452,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Fast enumeration state.
QualType StateTy = getContext().getObjCFastEnumerationStateType();
- llvm::AllocaInst *StatePtr = CreateTempAlloca(ConvertType(StateTy),
- "state.ptr");
- StatePtr->setAlignment(getContext().getTypeAlign(StateTy) >> 3);
+ llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr");
EmitMemSetToZero(StatePtr, StateTy);
// Number of elements in the items array.
@@ -470,7 +470,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
getContext().getConstantArrayType(getContext().getObjCIdType(),
llvm::APInt(32, NumItems),
ArrayType::Normal, 0);
- llvm::Value *ItemsPtr = CreateTempAlloca(ConvertType(ItemsTy), "items.ptr");
+ llvm::Value *ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
llvm::Value *Collection = EmitScalarExpr(S.getCollection());
@@ -492,7 +492,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
FastEnumSel,
Collection, false, Args);
- llvm::Value *LimitPtr = CreateTempAlloca(UnsignedLongLTy, "limit.ptr");
+ llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy,
+ "limit.ptr");
Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
llvm::BasicBlock *NoElements = createBasicBlock("noelements");
@@ -506,8 +507,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(SetStartMutations);
- llvm::Value *StartMutationsPtr =
- CreateTempAlloca(UnsignedLongLTy);
+ llvm::Value *StartMutationsPtr = CreateMemTemp(getContext().UnsignedLongTy);
llvm::Value *StateMutationsPtrPtr =
Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
@@ -522,7 +522,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::BasicBlock *LoopStart = createBasicBlock("loopstart");
EmitBlock(LoopStart);
- llvm::Value *CounterPtr = CreateTempAlloca(UnsignedLongLTy, "counter.ptr");
+ llvm::Value *CounterPtr = CreateMemTemp(getContext().UnsignedLongTy,
+ "counter.ptr");
Builder.CreateStore(Zero, CounterPtr);
llvm::BasicBlock *LoopBody = createBasicBlock("loopbody");
@@ -553,7 +554,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
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),
+ EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2,
+ CC_Default, false),
EnumerationMutationFn, ReturnValueSlot(), Args2);
EmitBlock(WasNotMutated);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 77be9fb58231..1d38ef9e2d2f 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -55,6 +55,7 @@ private:
const llvm::PointerType *PtrToInt8Ty;
const llvm::FunctionType *IMPTy;
const llvm::PointerType *IdTy;
+ const llvm::PointerType *PtrToIdTy;
QualType ASTIdTy;
const llvm::IntegerType *IntTy;
const llvm::PointerType *PtrTy;
@@ -65,11 +66,17 @@ private:
std::vector<llvm::Constant*> Classes;
std::vector<llvm::Constant*> Categories;
std::vector<llvm::Constant*> ConstantStrings;
+ llvm::StringMap<llvm::Constant*> ObjCStrings;
llvm::Function *LoadFunction;
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
+ 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;
@@ -114,14 +121,18 @@ private:
llvm::Constant *ExportUniqueString(const std::string &Str, const std::string
prefix);
llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name="",
+ 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, const std::string &Name="",
+ std::vector<llvm::Constant*> &V, llvm::StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
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);
+ }
public:
CGObjCGNU(CodeGen::CodeGenModule &cgm);
virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
@@ -257,12 +268,54 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
} else {
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
}
+ PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
// IMP type
std::vector<const llvm::Type*> IMPArgs;
IMPArgs.push_back(IdTy);
IMPArgs.push_back(SelectorTy);
IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
+
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ // Get selectors needed in GC mode
+ RetainSel = GetNullarySelector("retain", CGM.getContext());
+ ReleaseSel = GetNullarySelector("release", CGM.getContext());
+ AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext());
+
+ // 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);
+ // FIXME: ptrdiff_t
+ Args.push_back(LongTy);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Args, false);
+ IvarAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
+ // id objc_assign_strongCast (id, id*)
+ Args.pop_back();
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ StrongCastAssignFn =
+ CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
+ // id objc_assign_global(id, id*);
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ GlobalAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
+ // id objc_assign_weak(id, id*);
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ WeakAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
+ // 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");
+ // void *objc_memmove_collectable(void*, void *, size_t);
+ Args.clear();
+ Args.push_back(PtrToInt8Ty);
+ Args.push_back(PtrToInt8Ty);
+ // FIXME: size_t
+ Args.push_back(LongTy);
+ FTy = llvm::FunctionType::get(IdTy, Args, false);
+ MemMoveFn = CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
+ }
}
// This has to perform the lookup every time, since posing and related
@@ -340,7 +393,7 @@ llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str,
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name,
+ 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,
@@ -348,7 +401,7 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name,
+ 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,
@@ -357,8 +410,14 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
/// Generate an NSConstantString object.
llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
+
std::string Str(SL->getStrData(), SL->getByteLength());
+ // Look for an existing one
+ llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str);
+ if (old != ObjCStrings.end())
+ return old->getValue();
+
std::vector<llvm::Constant*> Ivars;
Ivars.push_back(NULLPtr);
Ivars.push_back(MakeConstantString(Str));
@@ -366,8 +425,9 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
llvm::Constant *ObjCStr = MakeGlobal(
llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
Ivars, ".objc_str");
- ConstantStrings.push_back(
- llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty));
+ ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty);
+ ObjCStrings[Str] = ObjCStr;
+ ConstantStrings.push_back(ObjCStr);
return ObjCStr;
}
@@ -384,6 +444,14 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (Sel == RetainSel || Sel == AutoreleaseSel) {
+ return RValue::get(Receiver);
+ }
+ if (Sel == ReleaseSel) {
+ return RValue::get(0);
+ }
+ }
llvm::Value *cmd = GetSelector(CGF.Builder, Sel);
CallArgList ActualArgs;
@@ -396,7 +464,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -478,6 +547,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (Sel == RetainSel || Sel == AutoreleaseSel) {
+ return RValue::get(Receiver);
+ }
+ if (Sel == ReleaseSel) {
+ return RValue::get(0);
+ }
+ }
CGBuilderTy &Builder = CGF.Builder;
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
@@ -495,7 +572,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -1517,7 +1595,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
}
// sizeof(ModuleTy)
- llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
+ 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
@@ -1610,7 +1688,8 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
llvm::SmallVector<QualType,16> Params;
Params.push_back(ASTIdTy);
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -1668,7 +1747,6 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(TryHandler);
// Get the correct versions of the exception handling intrinsics
- llvm::TargetData td = llvm::TargetData::TargetData(&TheModule);
llvm::Value *llvm_eh_exception =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
llvm::Value *llvm_eh_selector =
@@ -1899,35 +1977,58 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
- return 0;
+ CGBuilderTy B = CGF.Builder;
+ AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy);
+ return B.CreateCall(WeakReadFn, AddrWeakObj);
}
void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall2(WeakAssignFn, src, dst);
}
void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall2(GlobalAssignFn, src, dst);
}
void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
}
void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ src = EnforceType(B, src, IdTy);
+ dst = EnforceType(B, dst, PtrToIdTy);
+ B.CreateCall2(StrongCastAssignFn, src, dst);
}
void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
QualType Ty) {
- return;
+ CGBuilderTy B = CGF.Builder;
+ DestPtr = EnforceType(B, DestPtr, IdTy);
+ SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy);
+
+ std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty);
+ unsigned long size = TypeInfo.first/8;
+ // FIXME: size_t
+ llvm::Value *N = llvm::ConstantInt::get(LongTy, size);
+
+ B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, N);
}
llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 137ea51721c7..b16a510f98f6 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
@@ -304,7 +305,8 @@ public:
Params.push_back(Ctx.LongTy);
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(IdType, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@@ -322,7 +324,8 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
@@ -333,7 +336,8 @@ public:
llvm::SmallVector<QualType,16> Params;
Params.push_back(Ctx.getObjCIdType());
const llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ CC_Default, false), false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -734,7 +738,8 @@ public:
return CGM.CreateRuntimeFunction(
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
Params, false),
- "_Unwind_Resume_or_Rethrow");
+ (CGM.getLangOptions().SjLjExceptions ? "_Unwind_SjLj_Resume" :
+ "_Unwind_Resume_or_Rethrow"));
}
llvm::Constant *getObjCEndCatchFn() {
@@ -1553,7 +1558,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
const llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -3625,7 +3631,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
Ctx.getObjCIdType(), 0, 0, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
Ctx.getObjCClassType(), 0, 0, false));
- RD->completeDefinition(Ctx);
+ RD->completeDefinition();
SuperCTy = Ctx.getTagDeclType(RD);
SuperPtrCTy = Ctx.getPointerType(SuperCTy);
@@ -4086,7 +4092,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
Ctx.VoidPtrTy, 0, 0, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
Ctx.getObjCSelType(), 0, 0, false));
- RD->completeDefinition(Ctx);
+ RD->completeDefinition();
MessageRefCTy = Ctx.getTagDeclType(RD);
MessageRefCPtrTy = Ctx.getPointerType(MessageRefCTy);
@@ -4224,6 +4230,9 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
/// message dispatch call for all the rest.
///
bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
+ if (CGM.getCodeGenOpts().ObjCLegacyDispatch)
+ return true;
+
if (NonLegacyDispatchMethods.empty()) {
NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
@@ -5085,7 +5094,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
// FIXME. This is too much work to get the ABI-specific result type needed to
// find the message name.
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType,
- llvm::SmallVector<QualType, 16>());
+ llvm::SmallVector<QualType, 16>(),
+ CC_Default, false);
llvm::Constant *Fn = 0;
std::string Name("\01l_");
if (CGM.ReturnTypeUsesSret(FnInfo)) {
@@ -5159,7 +5169,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
ActualArgs.push_back(std::make_pair(RValue::get(Arg1),
ObjCTypes.MessageRefCPtrTy));
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
- const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs);
+ const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs,
+ CC_Default, false);
llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
Callee = CGF.Builder.CreateLoad(Callee);
const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 29552ce4441c..5236d2063489 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -256,6 +256,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!RD->hasDefinition())
+ return false;
+
if (!RD->isDynamicClass())
return false;
@@ -469,7 +472,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (!RD->getNumBases()) {
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
// abi::__class_type_info.
VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
} else if (CanUseSingleInheritance(RD)) {
@@ -566,7 +569,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
case Type::Record: {
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (!RD->getNumBases()) {
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
// We don't need to emit any fields.
break;
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 9f90ec5ff6e0..baafd6836c63 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -108,6 +108,9 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
return true;
}
+ // Check if we have a pointer to data member in this field.
+ CheckForPointerToDataMember(D->getType());
+
assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
uint64_t FieldOffsetInBytes = FieldOffset / 8;
@@ -162,6 +165,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
uint64_t Size = 0;
unsigned Align = 0;
+ bool HasOnlyZeroSizedBitFields = true;
+
unsigned FieldNo = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
@@ -181,6 +186,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
} else
Types.addFieldInfo(*Field, 0);
+ HasOnlyZeroSizedBitFields = false;
+
const llvm::Type *FieldTy =
Types.ConvertTypeForMemRecursive(Field->getType());
unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
@@ -207,7 +214,8 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
}
}
if (!Align) {
- assert((D->field_begin() == D->field_end()) && "LayoutUnion - Align 0");
+ assert(HasOnlyZeroSizedBitFields &&
+ "0-align record did not have all zero-sized bit-fields!");
Align = 1;
}
@@ -333,23 +341,34 @@ uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
return Types.getTargetData().getTypeAllocSize(Ty);
}
-void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) {
+void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
// This record already contains a member pointer.
- if (ContainsMemberPointer)
+ if (ContainsPointerToDataMember)
return;
// Can only have member pointers if we're compiling C++.
if (!Types.getContext().getLangOptions().CPlusPlus)
return;
- QualType Ty = FD->getType();
-
- if (Ty->isMemberPointerType()) {
- // We have a member pointer!
- ContainsMemberPointer = true;
- return;
- }
+ T = Types.getContext().getBaseElementType(T);
+ if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
+ if (!MPT->getPointeeType()->isFunctionType()) {
+ // We have a pointer to data member.
+ ContainsPointerToDataMember = true;
+ }
+ } else if (const RecordType *RT = T->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // FIXME: It would be better if there was a way to explicitly compute the
+ // record layout instead of converting to a type.
+ Types.ConvertTagDeclType(RD);
+
+ const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+
+ if (Layout.containsPointerToDataMember())
+ ContainsPointerToDataMember = true;
+ }
}
CGRecordLayout *
@@ -381,5 +400,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
}
- return new CGRecordLayout(Ty, Builder.ContainsMemberPointer);
+ return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h
index cf84053e1907..eb60ed7b5b1d 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.h
+++ b/lib/CodeGen/CGRecordLayoutBuilder.h
@@ -27,6 +27,7 @@ namespace clang {
class CXXRecordDecl;
class FieldDecl;
class RecordDecl;
+ class QualType;
namespace CodeGen {
class CGRecordLayout;
@@ -38,9 +39,10 @@ class CGRecordLayoutBuilder {
/// Packed - Whether the resulting LLVM struct will be packed or not.
bool Packed;
- /// ContainsMemberPointer - Whether one of the fields is a member pointer
- /// or is a struct that contains a member pointer.
- bool ContainsMemberPointer;
+ /// ContainsPointerToDataMember - Whether one of the fields in this record
+ /// layout is a pointer to data member, or a struct that contains pointer to
+ /// data member.
+ bool ContainsPointerToDataMember;
/// Alignment - Contains the alignment of the RecordDecl.
unsigned Alignment;
@@ -78,7 +80,7 @@ class CGRecordLayoutBuilder {
llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
CGRecordLayoutBuilder(CodeGenTypes &Types)
- : Types(Types), Packed(false), ContainsMemberPointer(false)
+ : Types(Types), Packed(false), ContainsPointerToDataMember(false)
, Alignment(0), AlignmentAsLLVMStruct(1)
, BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
@@ -123,8 +125,9 @@ class CGRecordLayoutBuilder {
unsigned getTypeAlignment(const llvm::Type *Ty) const;
uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
- /// CheckForMemberPointer - Check if the field contains a member pointer.
- void CheckForMemberPointer(const FieldDecl *FD);
+ /// CheckForPointerToDataMember - Check if the given type contains a pointer
+ /// to data member.
+ void CheckForPointerToDataMember(QualType T);
public:
/// ComputeLayout - Return the right record layout for a given record decl.
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index bbd546261800..008a480b9c12 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -861,14 +861,13 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S,
std::string &ConstraintStr) {
llvm::Value *Arg;
if (Info.allowsRegister() || !Info.allowsMemory()) {
- const llvm::Type *Ty = ConvertType(InputExpr->getType());
-
- if (Ty->isSingleValueType()) {
+ if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType())) {
Arg = EmitScalarExpr(InputExpr);
} else {
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
+ const llvm::Type *Ty = ConvertType(InputExpr->getType());
uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty);
if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
Ty = llvm::IntegerType::get(VMContext, Size);
@@ -916,18 +915,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i),
S.getOutputName(i));
- bool result = Target.validateOutputConstraint(Info);
- assert(result && "Failed to parse output constraint"); result=result;
+ assert(Target.validateOutputConstraint(Info) &&
+ "Failed to parse output constraint");
OutputConstraintInfos.push_back(Info);
}
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
TargetInfo::ConstraintInfo Info(S.getInputConstraint(i),
S.getInputName(i));
- bool result = Target.validateInputConstraint(OutputConstraintInfos.data(),
- S.getNumOutputs(),
- Info); result=result;
- assert(result && "Failed to parse input constraint");
+ assert(Target.validateInputConstraint(OutputConstraintInfos.data(),
+ S.getNumOutputs(),
+ Info) &&
+ "Failed to parse input constraint");
InputConstraintInfos.push_back(Info);
}
@@ -1066,10 +1065,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Clobbers
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
- std::string Clobber(S.getClobber(i)->getStrData(),
- S.getClobber(i)->getByteLength());
+ llvm::StringRef Clobber = S.getClobber(i)->getString();
- Clobber = Target.getNormalizedGCCRegisterName(Clobber.c_str());
+ Clobber = Target.getNormalizedGCCRegisterName(Clobber);
if (i != 0 || NumConstraints != 0)
Constraints += ',';
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index e5abfc6f8d57..970bbd777f14 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -16,14 +16,1245 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
#include <cstdio>
using namespace clang;
using namespace CodeGen;
namespace {
+
+/// FinalOverriders - Contains the final overrider member functions for all
+/// member functions in the base subobjects of a class.
+class FinalOverriders {
+public:
+ /// BaseOffset - Represents an offset from a derived class to a direct or
+ /// indirect base class.
+ struct BaseOffset {
+ /// DerivedClass - The derived class.
+ const CXXRecordDecl *DerivedClass;
+
+ /// VirtualBase - If the path from the derived class to the base class
+ /// involves a virtual base class, this holds its declaration.
+ const CXXRecordDecl *VirtualBase;
+
+ /// NonVirtualOffset - The offset from the derived class to the base class.
+ /// 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;
+
+ BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { }
+ BaseOffset(const CXXRecordDecl *DerivedClass,
+ const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset)
+ : DerivedClass(DerivedClass), VirtualBase(VirtualBase),
+ NonVirtualOffset(NonVirtualOffset) { }
+
+ bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; }
+ };
+
+ /// OverriderInfo - Information about a final overrider.
+ struct OverriderInfo {
+ /// Method - The method decl of the overrider.
+ const CXXMethodDecl *Method;
+
+ OverriderInfo() : Method(0) { }
+ };
+
+private:
+ /// MostDerivedClass - The most derived class for which the final overriders
+ /// are stored.
+ const CXXRecordDecl *MostDerivedClass;
+
+ ASTContext &Context;
+
+ /// MostDerivedClassLayout - the AST record layout of the most derived class.
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ /// BaseSubobjectMethodPairTy - Uniquely identifies a member function
+ /// in a base subobject.
+ typedef std::pair<BaseSubobject, const CXXMethodDecl *>
+ BaseSubobjectMethodPairTy;
+
+ typedef llvm::DenseMap<BaseSubobjectMethodPairTy,
+ OverriderInfo> OverridersMapTy;
+
+ /// OverridersMap - The final overriders for all virtual member functions of
+ /// all the base subobjects of the most derived class.
+ OverridersMapTy OverridersMap;
+
+ /// VisitedVirtualBases - A set of all the visited virtual bases, used to
+ /// avoid visiting virtual bases more than once.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+
+ typedef llvm::DenseMap<BaseSubobjectMethodPairTy, BaseOffset>
+ AdjustmentOffsetsMapTy;
+
+ /// ReturnAdjustments - Holds return adjustments for all the overriders that
+ /// need to perform return value adjustments.
+ AdjustmentOffsetsMapTy ReturnAdjustments;
+
+ /// ThisAdjustments - Holds 'this' adjustments for all the overriders that
+ /// need them.
+ AdjustmentOffsetsMapTy ThisAdjustments;
+
+ typedef llvm::SmallVector<uint64_t, 1> OffsetVectorTy;
+
+ /// SubobjectOffsetsMapTy - This map is used for keeping track of all the
+ /// base subobject offsets that a single class declaration might refer to.
+ ///
+ /// For example, in:
+ ///
+ /// struct A { virtual void f(); };
+ /// struct B1 : A { };
+ /// struct B2 : A { };
+ /// struct C : B1, B2 { virtual void f(); };
+ ///
+ /// when we determine that C::f() overrides A::f(), we need to update the
+ /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map
+ /// will have the subobject offsets for both A copies.
+ typedef llvm::DenseMap<const CXXRecordDecl *, OffsetVectorTy>
+ SubobjectOffsetsMapTy;
+
+ /// ComputeFinalOverriders - Compute the final overriders for a given base
+ /// subobject (and all its direct and indirect bases).
+ void ComputeFinalOverriders(BaseSubobject Base,
+ SubobjectOffsetsMapTy &Offsets);
+
+ /// AddOverriders - Add the final overriders for this base subobject to the
+ /// map of final overriders.
+ void AddOverriders(BaseSubobject Base, SubobjectOffsetsMapTy &Offsets);
+
+ /// PropagateOverrider - Propagate the NewMD overrider to all the functions
+ /// that OldMD overrides. For example, if we have:
+ ///
+ /// struct A { virtual void f(); };
+ /// struct B : A { virtual void f(); };
+ /// struct C : B { virtual void f(); };
+ ///
+ /// and we want to override B::f with C::f, we also need to override A::f with
+ /// C::f.
+ void PropagateOverrider(const CXXMethodDecl *OldMD,
+ BaseSubobject NewBase,
+ const CXXMethodDecl *NewMD,
+ SubobjectOffsetsMapTy &Offsets);
+
+ /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting
+ /// the 'this' pointer from the base subobject to the derived subobject.
+ BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+ BaseSubobject Derived);
+
+ static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
+ SubobjectOffsetsMapTy &Offsets);
+
+public:
+ explicit FinalOverriders(const CXXRecordDecl *MostDerivedClass);
+
+ /// getOverrider - Get the final overrider for the given method declaration in
+ /// the given base subobject.
+ OverriderInfo getOverrider(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
+ assert(OverridersMap.count(std::make_pair(Base, MD)) &&
+ "Did not find overrider!");
+
+ return OverridersMap.lookup(std::make_pair(Base, MD));
+ }
+
+ /// getReturnAdjustmentOffset - Get the return adjustment offset for the
+ /// method decl in the given base subobject. Returns an empty base offset if
+ /// no adjustment is needed.
+ BaseOffset getReturnAdjustmentOffset(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
+ return ReturnAdjustments.lookup(std::make_pair(Base, MD));
+ }
+
+ /// getThisAdjustmentOffset - Get the 'this' pointer adjustment offset for the
+ /// method decl in the given base subobject. Returns an empty base offset if
+ /// no adjustment is needed.
+ BaseOffset getThisAdjustmentOffset(BaseSubobject Base,
+ const CXXMethodDecl *MD) const {
+ return ThisAdjustments.lookup(std::make_pair(Base, MD));
+ }
+
+ /// dump - dump the final overriders.
+ void dump() {
+ assert(VisitedVirtualBases.empty() &&
+ "Visited virtual bases aren't empty!");
+ dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0));
+ VisitedVirtualBases.clear();
+ }
+
+ /// dump - dump the final overriders for a base subobject, and all its direct
+ /// and indirect base subobjects.
+ void dump(llvm::raw_ostream &Out, BaseSubobject Base);
+};
+
+FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass)
+ : MostDerivedClass(MostDerivedClass),
+ Context(MostDerivedClass->getASTContext()),
+ MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
+
+ // Compute the final overriders.
+ SubobjectOffsetsMapTy Offsets;
+ ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), Offsets);
+
+ // And dump them (for now).
+ dump();
+
+ // Also dump the base offsets (for now).
+ for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(),
+ E = Offsets.end(); I != E; ++I) {
+ const OffsetVectorTy& OffsetVector = I->second;
+
+ llvm::errs() << "Base offsets for ";
+ llvm::errs() << I->first->getQualifiedNameAsString() << '\n';
+
+ for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I)
+ llvm::errs() << " " << I << " - " << OffsetVector[I] << '\n';
+ }
+}
+
+void FinalOverriders::AddOverriders(BaseSubobject Base,
+ SubobjectOffsetsMapTy &Offsets) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ // First, propagate the overrider.
+ PropagateOverrider(MD, Base, MD, Offsets);
+
+ // Add the overrider as the final overrider of itself.
+ OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)];
+ assert(!Overrider.Method && "Overrider should not exist yet!");
+
+ Overrider.Method = MD;
+ }
+}
+
+static FinalOverriders::BaseOffset
+ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD,
+ const CXXBasePath &Path) {
+ int64_t NonVirtualOffset = 0;
+
+ unsigned NonVirtualStart = 0;
+ const CXXRecordDecl *VirtualBase = 0;
+
+ // First, look for the virtual base class.
+ for (unsigned I = 0, E = Path.size(); I != E; ++I) {
+ const CXXBasePathElement &Element = Path[I];
+
+ if (Element.Base->isVirtual()) {
+ // FIXME: Can we break when we find the first virtual base?
+ // (If we can't, can't we just iterate over the path in reverse order?)
+ NonVirtualStart = I + 1;
+ QualType VBaseType = Element.Base->getType();
+ VirtualBase =
+ cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+ }
+ }
+
+ // Now compute the non-virtual offset.
+ for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
+ const CXXBasePathElement &Element = Path[I];
+
+ // Check the base class offset.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+
+ const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
+ const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+
+ 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 FinalOverriders::BaseOffset(DerivedRD, VirtualBase,
+ NonVirtualOffset / 8);
+
+}
+
+static FinalOverriders::BaseOffset
+ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD,
+ const CXXRecordDecl *DerivedRD) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
+
+ if (!const_cast<CXXRecordDecl *>(DerivedRD)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return FinalOverriders::BaseOffset();
+ }
+
+ return ComputeBaseOffset(Context, DerivedRD, Paths.front());
+}
+
+static FinalOverriders::BaseOffset
+ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
+ const CXXMethodDecl *DerivedMD,
+ const CXXMethodDecl *BaseMD) {
+ const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
+ const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+
+ // Canonicalize the return types.
+ CanQualType CanDerivedReturnType =
+ Context.getCanonicalType(DerivedFT->getResultType());
+ CanQualType CanBaseReturnType =
+ Context.getCanonicalType(BaseFT->getResultType());
+
+ assert(CanDerivedReturnType->getTypeClass() ==
+ CanBaseReturnType->getTypeClass() &&
+ "Types must have same type class!");
+
+ if (CanDerivedReturnType == CanBaseReturnType) {
+ // No adjustment needed.
+ return FinalOverriders::BaseOffset();
+ }
+
+ if (isa<ReferenceType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<ReferenceType>()->getPointeeType();
+ } else if (isa<PointerType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<PointerType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<PointerType>()->getPointeeType();
+ } else {
+ assert(false && "Unexpected return type!");
+ }
+
+ // We need to compare unqualified types here; consider
+ // const T *Base::foo();
+ // T *Derived::foo();
+ if (CanDerivedReturnType.getUnqualifiedType() ==
+ CanBaseReturnType.getUnqualifiedType()) {
+ // No adjustment needed.
+ return FinalOverriders::BaseOffset();
+ }
+
+ const CXXRecordDecl *DerivedRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
+
+ const CXXRecordDecl *BaseRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
+
+ return ComputeBaseOffset(Context, BaseRD, DerivedRD);
+}
+
+FinalOverriders::BaseOffset
+FinalOverriders::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+ BaseSubobject Derived) {
+ const CXXRecordDecl *BaseRD = Base.getBase();
+ const CXXRecordDecl *DerivedRD = Derived.getBase();
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true,
+ /*RecordPaths=*/true, /*DetectVirtual=*/true);
+
+ if (!const_cast<CXXRecordDecl *>(DerivedRD)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return FinalOverriders::BaseOffset();
+ }
+
+ assert(!Paths.getDetectedVirtual() && "FIXME: Handle virtual bases!");
+
+ BaseOffset Offset;
+
+ // FIXME: This is not going to be enough with virtual bases.
+ // FIXME: We should not use / 8 here.
+ int64_t DerivedToBaseOffset =
+ (Base.getBaseOffset() - Derived.getBaseOffset()) / 8;
+
+ Offset.NonVirtualOffset = -DerivedToBaseOffset;
+
+ return Offset;
+}
+
+void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
+ BaseSubobject NewBase,
+ const CXXMethodDecl *NewMD,
+ SubobjectOffsetsMapTy &Offsets) {
+ for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(),
+ E = OldMD->end_overridden_methods(); I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+ const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+
+ // We want to override OverriddenMD in all subobjects, for example:
+ //
+ /// struct A { virtual void f(); };
+ /// struct B1 : A { };
+ /// struct B2 : A { };
+ /// struct C : B1, B2 { virtual void f(); };
+ ///
+ /// When overriding A::f with C::f we need to do so in both A subobjects.
+ const OffsetVectorTy &OffsetVector = Offsets[OverriddenRD];
+
+ // Go through all the subobjects.
+ for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) {
+ uint64_t Offset = OffsetVector[I];
+
+ BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset);
+ BaseSubobjectMethodPairTy SubobjectAndMethod =
+ std::make_pair(OverriddenSubobject, OverriddenMD);
+
+ OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod];
+
+ assert(Overrider.Method && "Did not find existing overrider!");
+
+ // Check if we need return adjustments or base adjustments.
+ // (We don't want to do this for pure virtual member functions).
+ if (!NewMD->isPure()) {
+ // Get the return adjustment base offset.
+ BaseOffset ReturnBaseOffset =
+ ComputeReturnAdjustmentBaseOffset(Context, NewMD, OverriddenMD);
+
+ if (!ReturnBaseOffset.isEmpty()) {
+ // Store the return adjustment base offset.
+ ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset;
+ }
+
+ // Check if we need a 'this' adjustment base offset as well.
+ if (Offset != NewBase.getBaseOffset()) {
+ BaseOffset ThisBaseOffset =
+ ComputeThisAdjustmentBaseOffset(OverriddenSubobject,
+ NewBase);
+ assert(!ThisBaseOffset.isEmpty() &&
+ "Should not get an empty 'this' adjustment!");
+
+ ThisAdjustments[SubobjectAndMethod] = ThisBaseOffset;
+ }
+ }
+
+ // Set the new overrider.
+ Overrider.Method = NewMD;
+
+ // And propagate it further.
+ PropagateOverrider(OverriddenMD, NewBase, NewMD, Offsets);
+ }
+ }
+}
+
+void
+FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
+ SubobjectOffsetsMapTy &Offsets) {
+ // Iterate over the new offsets.
+ for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(),
+ E = NewOffsets.end(); I != E; ++I) {
+ const CXXRecordDecl *NewRD = I->first;
+ const OffsetVectorTy& NewOffsetVector = I->second;
+
+ OffsetVectorTy &OffsetVector = Offsets[NewRD];
+ if (OffsetVector.empty()) {
+ // There were no previous offsets in this vector, just insert all entries
+ // from the new offset vector.
+ OffsetVector.append(NewOffsetVector.begin(), NewOffsetVector.end());
+ continue;
+ }
+
+ // We need to merge the new offsets vector into the old, but we don't want
+ // to have duplicate entries. Do this by inserting the old offsets in a set
+ // so they'll be unique. After this, we iterate over the new offset vector
+ // and only append elements that aren't in the set.
+
+ // First, add the existing offsets to the set.
+ llvm::SmallSet<uint64_t, 4> OffsetSet;
+ for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) {
+ bool Inserted = OffsetSet.insert(OffsetVector[I]);
+ if (!Inserted)
+ assert(false && "Set of offsets should be unique!");
+ }
+
+ // Next, only add the new offsets if they are not already in the set.
+ for (unsigned I = 0, E = NewOffsetVector.size(); I != E; ++I) {
+ uint64_t Offset = NewOffsetVector[I];
+
+ if (OffsetSet.count(Offset)) {
+ // Ignore the offset.
+ continue;
+ }
+
+ // Otherwise, add it to the offsets vector.
+ OffsetVector.push_back(Offset);
+ }
+ }
+}
+
+void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base,
+ SubobjectOffsetsMapTy &Offsets) {
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ SubobjectOffsetsMapTy NewOffsets;
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have any virtual member functions.
+ if (!BaseDecl->isPolymorphic())
+ continue;
+
+ uint64_t BaseOffset;
+ if (I->isVirtual()) {
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ } else {
+ BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
+ }
+
+ // Compute the final overriders for this base.
+ ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), NewOffsets);
+ }
+
+ /// Now add the overriders for this particular subobject.
+ AddOverriders(Base, NewOffsets);
+
+ // And merge the newly discovered subobject offsets.
+ MergeSubobjectOffsets(NewOffsets, Offsets);
+
+ /// Finally, add the offset for our own subobject.
+ Offsets[RD].push_back(Base.getBaseOffset());
+}
+
+void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have any virtual member functions.
+ if (!BaseDecl->isPolymorphic())
+ continue;
+
+ uint64_t BaseOffset;
+ if (I->isVirtual()) {
+ if (!VisitedVirtualBases.insert(BaseDecl)) {
+ // We've visited this base before.
+ continue;
+ }
+
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ } else {
+ BaseOffset = Layout.getBaseClassOffset(BaseDecl) +
+ Base.getBaseOffset();
+ }
+
+ dump(Out, BaseSubobject(BaseDecl, BaseOffset));
+ }
+
+ Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", ";
+ Out << Base.getBaseOffset() << ")\n";
+
+ // Now dump the overriders for this base subobject.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ OverriderInfo Overrider = getOverrider(Base, MD);
+
+ Out << " " << MD->getQualifiedNameAsString() << " - ";
+ Out << Overrider.Method->getQualifiedNameAsString();
+
+ AdjustmentOffsetsMapTy::const_iterator AI =
+ ReturnAdjustments.find(std::make_pair(Base, MD));
+ if (AI != ReturnAdjustments.end()) {
+ const BaseOffset &Offset = AI->second;
+
+ Out << " [ret-adj: ";
+ if (Offset.VirtualBase)
+ Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
+
+ Out << Offset.NonVirtualOffset << " nv]";
+ }
+
+ AI = ThisAdjustments.find(std::make_pair(Base, MD));
+ if (AI != ThisAdjustments.end()) {
+ const BaseOffset &Offset = AI->second;
+
+ Out << " [this-adj: ";
+ if (Offset.VirtualBase)
+ Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
+
+ Out << Offset.NonVirtualOffset << " nv]";
+ }
+
+ Out << "\n";
+ }
+}
+
+/// VtableComponent - Represents a single component in a vtable.
+class VtableComponent {
+public:
+ enum Kind {
+ CK_VCallOffset,
+ CK_VBaseOffset,
+ CK_OffsetToTop,
+ CK_RTTI,
+ CK_FunctionPointer,
+
+ /// CK_CompleteDtorPointer - A pointer to the complete destructor.
+ CK_CompleteDtorPointer,
+
+ /// CK_DeletingDtorPointer - A pointer to the deleting destructor.
+ CK_DeletingDtorPointer
+ };
+
+ static VtableComponent MakeVBaseOffset(int64_t Offset) {
+ return VtableComponent(CK_VBaseOffset, Offset);
+ }
+
+ static VtableComponent MakeOffsetToTop(int64_t Offset) {
+ return VtableComponent(CK_OffsetToTop, Offset);
+ }
+
+ static VtableComponent MakeRTTI(const CXXRecordDecl *RD) {
+ return VtableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
+ }
+
+ static VtableComponent MakeFunction(const CXXMethodDecl *MD) {
+ assert(!isa<CXXDestructorDecl>(MD) &&
+ "Don't use MakeFunction with destructors!");
+
+ return VtableComponent(CK_FunctionPointer,
+ reinterpret_cast<uintptr_t>(MD));
+ }
+
+ static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
+ return VtableComponent(CK_CompleteDtorPointer,
+ reinterpret_cast<uintptr_t>(DD));
+ }
+
+ static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
+ return VtableComponent(CK_DeletingDtorPointer,
+ reinterpret_cast<uintptr_t>(DD));
+ }
+
+ /// getKind - Get the kind of this vtable component.
+ Kind getKind() const {
+ return (Kind)(Value & 0x7);
+ }
+
+ int64_t getVBaseOffset() const {
+ assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
+
+ return getOffset();
+ }
+
+ int64_t getOffsetToTop() const {
+ assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
+
+ return getOffset();
+ }
+
+ const CXXRecordDecl *getRTTIDecl() const {
+ assert(getKind() == CK_RTTI && "Invalid component kind!");
+
+ return reinterpret_cast<CXXRecordDecl *>(getPointer());
+ }
+
+ const CXXMethodDecl *getFunctionDecl() const {
+ assert(getKind() == CK_FunctionPointer);
+
+ return reinterpret_cast<CXXMethodDecl *>(getPointer());
+ }
+
+ const CXXDestructorDecl *getDestructorDecl() const {
+ assert((getKind() == CK_CompleteDtorPointer ||
+ getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
+
+ return reinterpret_cast<CXXDestructorDecl *>(getPointer());
+ }
+
+private:
+ VtableComponent(Kind ComponentKind, int64_t Offset) {
+ assert((ComponentKind == CK_VCallOffset ||
+ ComponentKind == CK_VBaseOffset ||
+ ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
+ assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!");
+
+ Value = ((Offset << 3) | ComponentKind);
+ }
+
+ VtableComponent(Kind ComponentKind, uintptr_t Ptr) {
+ assert((ComponentKind == CK_RTTI ||
+ ComponentKind == CK_FunctionPointer ||
+ ComponentKind == CK_CompleteDtorPointer ||
+ ComponentKind == CK_DeletingDtorPointer) &&
+ "Invalid component kind!");
+
+ assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
+
+ Value = Ptr | ComponentKind;
+ }
+
+ int64_t getOffset() const {
+ assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
+ getKind() == CK_OffsetToTop) && "Invalid component kind!");
+
+ return Value >> 3;
+ }
+
+ uintptr_t getPointer() const {
+ assert((getKind() == CK_RTTI ||
+ getKind() == CK_FunctionPointer ||
+ getKind() == CK_CompleteDtorPointer ||
+ getKind() == CK_DeletingDtorPointer) &&
+ "Invalid component kind!");
+
+ return static_cast<uintptr_t>(Value & ~7ULL);
+ }
+
+ /// The kind is stored in the lower 3 bits of the value. For offsets, we
+ /// make use of the facts that classes can't be larger than 2^55 bytes,
+ /// so we store the offset in the lower part of the 61 bytes that remain.
+ /// (The reason that we're not simply using a PointerIntPair here is that we
+ /// need the offsets to be 64-bit, even when on a 32-bit machine).
+ int64_t Value;
+};
+
+/// VtableBuilder - Class for building vtable layout information.
class VtableBuilder {
public:
+ /// PrimaryBasesSetTy - A set of direct and indirect primary bases.
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 8> PrimaryBasesSetTy;
+
+private:
+ /// VtableInfo - Global vtable information.
+ CGVtableInfo &VtableInfo;
+
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ /// Context - The ASTContext which we will use for layout information.
+ ASTContext &Context;
+
+ /// FinalOverriders - The final overriders of the most derived class.
+ FinalOverriders Overriders;
+
+ /// VCallAndVBaseOffsets - The vcall and vbase offset, of the vtable we're
+ // building (in reverse order).
+ llvm::SmallVector<VtableComponent, 64> VCallAndVBaseOffsets;
+
+ /// Components - The components of the vtable being built.
+ llvm::SmallVector<VtableComponent, 64> Components;
+
+ /// AddressPoints - Address points for the vtable being built.
+ CGVtableInfo::AddressPointsMapTy AddressPoints;
+
+ /// ReturnAdjustment - A return adjustment.
+ struct ReturnAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
+ int64_t NonVirtual;
+
+ /// VBaseOffsetOffset - The offset, in bytes, relative to the address point
+ /// of the virtual base class offset.
+ int64_t VBaseOffsetOffset;
+
+ ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
+
+ bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
+ };
+
+ /// ReturnAdjustments - The return adjustments needed in this vtable.
+ llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16>
+ ReturnAdjustments;
+
+ /// ThisAdjustment - A 'this' pointer adjustment thunk.
+ struct ThisAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
+ int64_t NonVirtual;
+
+ /// FIXME: Add VCallOffsetOffset here.
+
+ ThisAdjustment() : NonVirtual(0) { }
+
+ bool isEmpty() const { return !NonVirtual; }
+ };
+
+ /// ThisAdjustments - The 'this' pointer adjustments needed in this vtable.
+ llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16>
+ ThisAdjustments;
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
+
+ /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
+ /// given class.
+ void AddVCallAndVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// AddVBaseOffsets - Add vbase offsets for the given class.
+ void AddVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// ComputeReturnAdjustment - Compute the return adjustment given a return
+ /// adjustment base offset.
+ ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset);
+
+ /// ComputeThisAdjustment - Compute the 'this' pointer adjustment given a
+ /// 'this' pointer adjustment base offset.
+ ThisAdjustment ComputeThisAdjustment(FinalOverriders::BaseOffset Offset);
+
+ /// AddMethod - Add a single virtual member function to the vtable
+ /// components vector.
+ void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment,
+ ThisAdjustment ThisAdjustment);
+
+ /// AddMethods - Add the methods of this base subobject and all its
+ /// primary bases to the vtable components vector.
+ void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases);
+
+ /// LayoutVtable - Layout a vtable and all its secondary vtables.
+ void LayoutVtable(BaseSubobject Base);
+
+public:
+ VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass)
+ : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass),
+ Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass) {
+
+ LayoutVtable(BaseSubobject(MostDerivedClass, 0));
+ }
+
+ /// dumpLayout - Dump the vtable layout.
+ void dumpLayout(llvm::raw_ostream&);
+};
+
+/// OverridesMethodInPrimaryBase - Checks whether whether this virtual member
+/// function overrides a member function in a direct or indirect primary base.
+/// Returns the overridden member function, or null if none was found.
+static const CXXMethodDecl *
+OverridesMethodInPrimaryBase(const CXXMethodDecl *MD,
+ VtableBuilder::PrimaryBasesSetTy &PrimaryBases) {
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods(); I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+ const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+ assert(OverriddenMD->isCanonicalDecl() &&
+ "Should have the canonical decl of the overridden RD!");
+
+ if (PrimaryBases.count(OverriddenRD))
+ return OverriddenMD;
+ }
+
+ return 0;
+}
+
+VtableBuilder::ReturnAdjustment
+VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) {
+ ReturnAdjustment Adjustment;
+
+ if (!Offset.isEmpty()) {
+ if (Offset.VirtualBase) {
+ // Get the virtual base offset offset.
+ Adjustment.VBaseOffsetOffset =
+ VtableInfo.getVirtualBaseOffsetIndex(Offset.DerivedClass,
+ Offset.VirtualBase);
+ // FIXME: Once the assert in getVirtualBaseOffsetIndex is back again,
+ // we can get rid of this assert.
+ assert(Adjustment.VBaseOffsetOffset != 0 &&
+ "Invalid base offset offset!");
+ }
+
+ Adjustment.NonVirtual = Offset.NonVirtualOffset;
+ }
+
+ return Adjustment;
+}
+
+VtableBuilder::ThisAdjustment
+VtableBuilder::ComputeThisAdjustment(FinalOverriders::BaseOffset Offset) {
+ ThisAdjustment Adjustment;
+
+ if (!Offset.isEmpty()) {
+ assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!");
+ Adjustment.NonVirtual = Offset.NonVirtualOffset;
+ }
+
+ return Adjustment;
+}
+
+void
+VtableBuilder::AddVCallAndVBaseOffsets(const CXXRecordDecl *RD,
+ int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // Itanium C++ ABI 2.5.2:
+ // ..in classes sharing a virtual table with a primary base class, the vcall
+ // and vbase offsets added by the derived class all come before the vcall
+ // and vbase offsets required by the base class, so that the latter may be
+ // laid out as required by the base class without regard to additions from
+ // the derived class(es).
+
+ // (Since we're emitting the vcall and vbase offsets in reverse order, we'll
+ // emit them for the primary base first).
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase())
+ AddVCallAndVBaseOffsets(PrimaryBase, OffsetToTop, VBases);
+
+ AddVBaseOffsets(RD, OffsetToTop, VBases);
+}
+
+void VtableBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
+ int64_t OffsetToTop,
+ VisitedVirtualBasesSetTy &VBases) {
+ const ASTRecordLayout &MostDerivedClassLayout =
+ Context.getASTRecordLayout(MostDerivedClass);
+
+ // Add vbase offsets.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Check if this is a virtual base that we haven't visited before.
+ if (I->isVirtual() && VBases.insert(BaseDecl)) {
+ // FIXME: We shouldn't use / 8 here.
+ uint64_t Offset =
+ OffsetToTop + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl) / 8;
+
+ VCallAndVBaseOffsets.push_back(VtableComponent::MakeVBaseOffset(Offset));
+ }
+
+ // Check the base class looking for more vbase offsets.
+ AddVBaseOffsets(BaseDecl, OffsetToTop, VBases);
+ }
+}
+
+void
+VtableBuilder::AddMethod(const CXXMethodDecl *MD,
+ ReturnAdjustment ReturnAdjustment,
+ ThisAdjustment ThisAdjustment) {
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ assert(ReturnAdjustment.isEmpty() &&
+ "Destructor can't have return adjustment!");
+ // Add the 'this' pointer adjustments if necessary.
+ if (!ThisAdjustment.isEmpty()) {
+ ThisAdjustments.push_back(std::make_pair(Components.size(),
+ ThisAdjustment));
+ ThisAdjustments.push_back(std::make_pair(Components.size() + 1,
+ ThisAdjustment));
+ }
+
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VtableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VtableComponent::MakeDeletingDtor(DD));
+ } else {
+ // Add the return adjustment if necessary.
+ if (!ReturnAdjustment.isEmpty())
+ ReturnAdjustments.push_back(std::make_pair(Components.size(),
+ ReturnAdjustment));
+
+ // Add the 'this' pointer adjustment if necessary.
+ if (!ThisAdjustment.isEmpty())
+ ThisAdjustments.push_back(std::make_pair(Components.size(),
+ ThisAdjustment));
+
+ // Add the function.
+ Components.push_back(VtableComponent::MakeFunction(MD));
+ }
+}
+
+void
+VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+ if (Layout.getPrimaryBaseWasVirtual())
+ assert(false && "FIXME: Handle vbases here.");
+ else
+ assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
+
+ AddMethods(BaseSubobject(PrimaryBase, Base.getBaseOffset()), PrimaryBases);
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ assert(false && "Found a duplicate primary base!");
+ }
+
+ // Now go through all virtual member functions and add them.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ // Get the final overrider.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(Base, MD);
+
+ // Check if this virtual member function overrides a method in a primary
+ // base. If this is the case, and the return type doesn't require adjustment
+ // then we can just use the member function from the primary base.
+ if (const CXXMethodDecl *OverriddenMD =
+ OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+ if (ComputeReturnAdjustmentBaseOffset(Context, MD,
+ OverriddenMD).isEmpty())
+ continue;
+ }
+
+ // Check if this overrider needs a return adjustment.
+ FinalOverriders::BaseOffset ReturnAdjustmentOffset =
+ Overriders.getReturnAdjustmentOffset(Base, MD);
+
+ ReturnAdjustment ReturnAdjustment =
+ ComputeReturnAdjustment(ReturnAdjustmentOffset);
+
+ // Check if this overrider needs a 'this' pointer adjustment.
+ FinalOverriders::BaseOffset ThisAdjustmentOffset =
+ Overriders.getThisAdjustmentOffset(Base, MD);
+
+ ThisAdjustment ThisAdjustment = ComputeThisAdjustment(ThisAdjustmentOffset);
+
+ AddMethod(Overrider.Method, ReturnAdjustment, ThisAdjustment);
+ }
+}
+
+void VtableBuilder::LayoutVtable(BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
+ assert(RD->isDynamicClass() && "class does not have a vtable!");
+
+ int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8;
+
+ // Add vcall and vbase offsets for this vtable.
+ VisitedVirtualBasesSetTy VBases;
+ AddVCallAndVBaseOffsets(RD, OffsetToTop, VBases);
+
+ // Reverse them and add them to the vtable components.
+ std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end());
+ Components.append(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end());
+ VCallAndVBaseOffsets.clear();
+
+ // Add the offset to top.
+ // FIXME: This is not going to be right for construction vtables.
+ // FIXME: We should not use / 8 here.
+ Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop));
+
+ // Next, add the RTTI.
+ Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass));
+
+ uint64_t AddressPoint = Components.size();
+
+ // Now go through all virtual member functions and add them.
+ PrimaryBasesSetTy PrimaryBases;
+ AddMethods(Base, PrimaryBases);
+
+ // Record the address point.
+ AddressPoints.insert(std::make_pair(Base, AddressPoint));
+
+ // Record the address points for all primary bases.
+ for (PrimaryBasesSetTy::const_iterator I = PrimaryBases.begin(),
+ E = PrimaryBases.end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl = *I;
+
+ // We know that all the primary bases have the same offset as the base
+ // subobject.
+ BaseSubobject PrimaryBase(BaseDecl, Base.getBaseOffset());
+ AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint));
+ }
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ // Layout secondary vtables.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore bases that don't have a vtable.
+ if (!BaseDecl->isDynamicClass())
+ continue;
+
+ // Ignore the primary base.
+ if (BaseDecl == PrimaryBase)
+ continue;
+
+ // Ignore virtual bases, we'll emit them later.
+ if (I->isVirtual())
+ continue;
+
+ // Get the base offset of this base.
+ uint64_t BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
+
+ // Layout this secondary vtable.
+ LayoutVtable(BaseSubobject(BaseDecl, BaseOffset));
+ }
+
+ // FIXME: Emit vtables for virtual bases here.
+}
+
+/// dumpLayout - Dump the vtable layout.
+void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
+
+ Out << "Vtable for '" << MostDerivedClass->getQualifiedNameAsString();
+ Out << "' (" << Components.size() << " entries).\n";
+
+ // Iterate through the address points and insert them into a new map where
+ // they are keyed by the index and not the base object.
+ // Since an address point can be shared by multiple subobjects, we use an
+ // STL multimap.
+ std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
+ for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
+ AddressPoints.begin(), E = AddressPoints.end(); I != E; ++I) {
+ const BaseSubobject& Base = I->first;
+ uint64_t Index = I->second;
+
+ AddressPointsByIndex.insert(std::make_pair(Index, Base));
+ }
+
+ unsigned NextReturnAdjustmentIndex = 0;
+ unsigned NextThisAdjustmentIndex = 0;
+ for (unsigned I = 0, E = Components.size(); I != E; ++I) {
+ uint64_t Index = I;
+
+ if (AddressPointsByIndex.count(I)) {
+ if (AddressPointsByIndex.count(Index) == 1) {
+ const BaseSubobject &Base = AddressPointsByIndex.find(Index)->second;
+
+ // FIXME: Instead of dividing by 8, we should be using CharUnits.
+ Out << " -- (" << Base.getBase()->getQualifiedNameAsString();
+ Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n";
+ } else {
+ uint64_t BaseOffset =
+ AddressPointsByIndex.lower_bound(Index)->second.getBaseOffset();
+
+ // We store the class names in a set to get a stable order.
+ std::set<std::string> ClassNames;
+ for (std::multimap<uint64_t, BaseSubobject>::const_iterator I =
+ AddressPointsByIndex.lower_bound(Index), E =
+ AddressPointsByIndex.upper_bound(Index); I != E; ++I) {
+ assert(I->second.getBaseOffset() == BaseOffset &&
+ "Invalid base offset!");
+ const CXXRecordDecl *RD = I->second.getBase();
+ ClassNames.insert(RD->getQualifiedNameAsString());
+ }
+
+ 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 << llvm::format("%4d | ", I);
+
+ const VtableComponent &Component = Components[I];
+
+ // Dump the component.
+ switch (Component.getKind()) {
+ // FIXME: Remove this default case.
+ default:
+ assert(false && "Unhandled component kind!");
+ break;
+
+ case VtableComponent::CK_VBaseOffset:
+ Out << "vbase_offset (" << Component.getVBaseOffset() << ")";
+ break;
+
+ case VtableComponent::CK_OffsetToTop:
+ Out << "offset_to_top (" << Component.getOffsetToTop() << ")";
+ break;
+
+ case VtableComponent::CK_RTTI:
+ Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
+ break;
+
+ case VtableComponent::CK_FunctionPointer: {
+ const CXXMethodDecl *MD = Component.getFunctionDecl();
+
+ std::string Str =
+ PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
+ MD);
+ Out << Str;
+ if (MD->isPure())
+ Out << " [pure]";
+
+ // If this function pointer has a return adjustment, dump it.
+ if (NextReturnAdjustmentIndex < ReturnAdjustments.size() &&
+ ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
+ const ReturnAdjustment Adjustment =
+ ReturnAdjustments[NextReturnAdjustmentIndex].second;
+
+ Out << "\n [return adjustment: ";
+ Out << Adjustment.NonVirtual << " non-virtual";
+
+ if (Adjustment.VBaseOffsetOffset)
+ Out << ", " << Adjustment.VBaseOffsetOffset << " vbase offset offset";
+ Out << ']';
+
+ NextReturnAdjustmentIndex++;
+ }
+
+ // If this function pointer has a 'this' pointer adjustment, dump it.
+ if (NextThisAdjustmentIndex < ThisAdjustments.size() &&
+ ThisAdjustments[NextThisAdjustmentIndex].first == I) {
+ const ThisAdjustment Adjustment =
+ ThisAdjustments[NextThisAdjustmentIndex].second;
+
+ Out << "\n [this adjustment: ";
+ Out << Adjustment.NonVirtual << " non-virtual";
+
+ Out << ']';
+
+ NextThisAdjustmentIndex++;
+ }
+
+ break;
+ }
+
+ case VtableComponent::CK_CompleteDtorPointer: {
+ const CXXDestructorDecl *DD = Component.getDestructorDecl();
+
+ Out << DD->getQualifiedNameAsString() << "() [complete]";
+ if (DD->isPure())
+ Out << " [pure]";
+
+ break;
+ }
+
+ case VtableComponent::CK_DeletingDtorPointer: {
+ const CXXDestructorDecl *DD = Component.getDestructorDecl();
+
+ Out << DD->getQualifiedNameAsString() << "() [deleting]";
+ if (DD->isPure())
+ Out << " [pure]";
+
+ break;
+ }
+
+ }
+
+ Out << '\n';
+ }
+
+}
+
+}
+
+namespace {
+class OldVtableBuilder {
+public:
/// Index_t - Vtable index type.
typedef uint64_t Index_t;
typedef std::vector<std::pair<GlobalDecl,
@@ -57,10 +1288,11 @@ private:
llvm::LLVMContext &VMContext;
CodeGenModule &CGM; // Per-module state.
- llvm::DenseMap<GlobalDecl, Index_t> VCall;
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
llvm::DenseMap<GlobalDecl, Index_t> VCallOffset;
+ llvm::DenseMap<GlobalDecl, Index_t> VCallOffsetForVCall;
// This is the offset to the nearest virtual base
- llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset;
+ llvm::DenseMap<const CXXMethodDecl *, Index_t> NonVirtualOffset;
llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
/// PureVirtualFunction - Points to __cxa_pure_virtual.
@@ -180,6 +1412,196 @@ private:
return *ref;
}
+ bool DclIsSame(const FunctionDecl *New, const FunctionDecl *Old) {
+ FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
+
+ // C++ [temp.fct]p2:
+ // A function template can be overloaded with other function templates
+ // and with normal (non-template) functions.
+ if ((OldTemplate == 0) != (NewTemplate == 0))
+ return false;
+
+ // Is the function New an overload of the function Old?
+ QualType OldQType = CGM.getContext().getCanonicalType(Old->getType());
+ QualType NewQType = CGM.getContext().getCanonicalType(New->getType());
+
+ // Compare the signatures (C++ 1.3.10) of the two functions to
+ // determine whether they are overloads. If we find any mismatch
+ // in the signature, they are overloads.
+
+ // If either of these functions is a K&R-style function (no
+ // prototype), then we consider them to have matching signatures.
+ if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) ||
+ isa<FunctionNoProtoType>(NewQType.getTypePtr()))
+ return true;
+
+ FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
+ FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType);
+
+ // The signature of a function includes the types of its
+ // parameters (C++ 1.3.10), which includes the presence or absence
+ // of the ellipsis; see C++ DR 357).
+ if (OldQType != NewQType &&
+ (OldType->getNumArgs() != NewType->getNumArgs() ||
+ OldType->isVariadic() != NewType->isVariadic() ||
+ !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
+ NewType->arg_type_begin())))
+ return false;
+
+#if 0
+ // C++ [temp.over.link]p4:
+ // The signature of a function template consists of its function
+ // signature, its return type and its template parameter list. The names
+ // of the template parameters are significant only for establishing the
+ // relationship between the template parameters and the rest of the
+ // signature.
+ //
+ // We check the return type and template parameter lists for function
+ // templates first; the remaining checks follow.
+ if (NewTemplate &&
+ (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ TPL_TemplateMatch) ||
+ OldType->getResultType() != NewType->getResultType()))
+ return false;
+#endif
+
+ // If the function is a class member, its signature includes the
+ // cv-qualifiers (if any) on the function itself.
+ //
+ // As part of this, also check whether one of the member functions
+ // is static, in which case they are not overloads (C++
+ // 13.1p2). While not part of the definition of the signature,
+ // this check is important to determine whether these functions
+ // can be overloaded.
+ const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ if (OldMethod && NewMethod &&
+ !OldMethod->isStatic() && !NewMethod->isStatic() &&
+ OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers())
+ return false;
+
+ // The signatures match; this is not an overload.
+ return true;
+ }
+
+ typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl*>
+ ForwardUnique_t;
+ ForwardUnique_t ForwardUnique;
+ llvm::DenseMap<const CXXMethodDecl*, const CXXMethodDecl*> UniqueOverrider;
+
+ void BuildUniqueOverrider(const CXXMethodDecl *U, const CXXMethodDecl *MD) {
+ const CXXMethodDecl *PrevU = UniqueOverrider[MD];
+ assert(U && "no unique overrider");
+ if (PrevU == U)
+ return;
+ if (PrevU != U && PrevU != 0) {
+ // If already set, note the two sets as the same
+ if (0)
+ printf("%s::%s same as %s::%s\n",
+ PrevU->getParent()->getNameAsCString(),
+ PrevU->getNameAsCString(),
+ U->getParent()->getNameAsCString(),
+ U->getNameAsCString());
+ ForwardUnique[PrevU] = U;
+ return;
+ }
+
+ // Not set, set it now
+ if (0)
+ printf("marking %s::%s %p override as %s::%s\n",
+ MD->getParent()->getNameAsCString(),
+ MD->getNameAsCString(),
+ (void*)MD,
+ U->getParent()->getNameAsCString(),
+ U->getNameAsCString());
+ UniqueOverrider[MD] = U;
+
+ for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
+ me = MD->end_overridden_methods(); mi != me; ++mi) {
+ BuildUniqueOverrider(U, *mi);
+ }
+ }
+
+ void BuildUniqueOverriders(const CXXRecordDecl *RD) {
+ if (0) printf("walking %s\n", RD->getNameAsCString());
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+ if (!MD->isVirtual())
+ continue;
+
+ if (UniqueOverrider[MD] == 0) {
+ // Only set this, if it hasn't been set yet.
+ BuildUniqueOverrider(MD, MD);
+ if (0)
+ printf("top set is %s::%s %p\n",
+ MD->getParent()->getNameAsCString(),
+ MD->getNameAsCString(),
+ (void*)MD);
+ ForwardUnique[MD] = MD;
+ }
+ }
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ BuildUniqueOverriders(Base);
+ }
+ }
+
+ static int DclCmp(const void *p1, const void *p2) {
+ const CXXMethodDecl *MD1 = *(const CXXMethodDecl *const *)p1;
+ const CXXMethodDecl *MD2 = *(const CXXMethodDecl *const *)p2;
+
+ return (DeclarationName::compare(MD1->getDeclName(), MD2->getDeclName()));
+ }
+
+ void MergeForwarding() {
+ typedef llvm::SmallVector<const CXXMethodDecl *, 100> A_t;
+ A_t A;
+ for (ForwardUnique_t::iterator I = ForwardUnique.begin(),
+ E = ForwardUnique.end(); I != E; ++I) {
+ if (I->first == I->second)
+ // Only add the roots of all trees
+ A.push_back(I->first);
+ }
+ llvm::array_pod_sort(A.begin(), A.end(), DclCmp);
+ for (A_t::iterator I = A.begin(),
+ E = A.end(); I != E; ++I) {
+ A_t::iterator J = I;
+ while (++J != E && DclCmp(I, J) == 0)
+ if (DclIsSame(*I, *J)) {
+ if (0) printf("connecting %s\n", (*I)->getNameAsCString());
+ ForwardUnique[*J] = *I;
+ }
+ }
+ }
+
+ const CXXMethodDecl *getUnique(const CXXMethodDecl *MD) {
+ const CXXMethodDecl *U = UniqueOverrider[MD];
+ assert(U && "unique overrider not found");
+ while (ForwardUnique.count(U)) {
+ const CXXMethodDecl *NU = ForwardUnique[U];
+ if (NU == U) break;
+ U = NU;
+ }
+ return U;
+ }
+
+ GlobalDecl getUnique(GlobalDecl GD) {
+ const CXXMethodDecl *Unique = getUnique(cast<CXXMethodDecl>(GD.getDecl()));
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Unique))
+ return GlobalDecl(CD, GD.getCtorType());
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Unique))
+ return GlobalDecl(DD, GD.getDtorType());
+
+ return Unique;
+ }
+
/// getPureVirtualFn - Return the __cxa_pure_virtual function.
llvm::Constant* getPureVirtualFn() {
if (!PureVirtualFn) {
@@ -193,7 +1615,7 @@ private:
}
public:
- VtableBuilder(const CXXRecordDecl *MostDerivedClass,
+ OldVtableBuilder(const CXXRecordDecl *MostDerivedClass,
const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm,
bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints)
: BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l),
@@ -209,6 +1631,8 @@ public:
QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass);
rtti = CGM.GetAddrOfRTTIDescriptor(ClassType);
}
+ BuildUniqueOverriders(MostDerivedClass);
+ MergeForwarding();
}
// getVtableComponents - Returns a reference to the vtable components.
@@ -384,17 +1808,24 @@ public:
// entry.
Methods.AddMethod(GD);
- VCallOffset[GD] = Offset/8;
+ VCallOffset[GD] = Offset/8 - CurrentVBaseOffset/8;
+
if (MorallyVirtual) {
- Index_t &idx = VCall[GD];
+ GlobalDecl UGD = getUnique(GD);
+ const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
+
+ assert(UMD && "final overrider not found");
+
+ Index_t &idx = VCall[UMD];
// Allocate the first one, after that, we reuse the previous one.
if (idx == 0) {
- NonVirtualOffset[GD] = CurrentVBaseOffset/8 - Offset/8;
+ VCallOffsetForVCall[UGD] = Offset/8;
+ NonVirtualOffset[UMD] = Offset/8 - CurrentVBaseOffset/8;
idx = VCalls.size()+1;
- VCalls.push_back(0);
+ VCalls.push_back(Offset/8 - CurrentVBaseOffset/8);
D1(printf(" vcall for %s at %d with delta %d\n",
dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(),
- (int)-VCalls.size()-3, 0));
+ (int)-VCalls.size()-3, (int)VCalls[idx-1]));
}
}
}
@@ -459,6 +1890,9 @@ public:
}
VCalls.clear();
VCall.clear();
+ VCallOffsetForVCall.clear();
+ VCallOffset.clear();
+ NonVirtualOffset.clear();
}
void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset,
@@ -699,84 +2133,7 @@ public:
};
} // end anonymous namespace
-/// TypeConversionRequiresAdjustment - Returns whether conversion from a
-/// derived type to a base type requires adjustment.
-static bool
-TypeConversionRequiresAdjustment(ASTContext &Ctx,
- const CXXRecordDecl *DerivedDecl,
- const CXXRecordDecl *BaseDecl) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/true);
- if (!const_cast<CXXRecordDecl *>(DerivedDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return false;
- }
-
- // If we found a virtual base we always want to require adjustment.
- if (Paths.getDetectedVirtual())
- return true;
-
- const CXXBasePath &Path = Paths.front();
-
- for (size_t Start = 0, End = Path.size(); Start != End; ++Start) {
- const CXXBasePathElement &Element = Path[Start];
-
- // Check the base class offset.
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class);
-
- const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
- const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
-
- if (Layout.getBaseClassOffset(Base) != 0) {
- // This requires an adjustment.
- return true;
- }
- }
-
- return false;
-}
-
-static bool
-TypeConversionRequiresAdjustment(ASTContext &Ctx,
- QualType DerivedType, QualType BaseType) {
- // Canonicalize the types.
- QualType CanDerivedType = Ctx.getCanonicalType(DerivedType);
- QualType CanBaseType = Ctx.getCanonicalType(BaseType);
-
- assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() &&
- "Types must have same type class!");
-
- if (CanDerivedType == CanBaseType) {
- // No adjustment needed.
- return false;
- }
-
- if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) {
- CanDerivedType = RT->getPointeeType();
- CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType();
- } else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) {
- CanDerivedType = PT->getPointeeType();
- CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType();
- } else {
- assert(false && "Unexpected return type!");
- }
-
- if (CanDerivedType == CanBaseType) {
- // No adjustment needed.
- return false;
- }
-
- const CXXRecordDecl *DerivedDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
-
- return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
-}
-
-bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
+bool OldVtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
Index_t OverrideOffset, Index_t Offset,
int64_t CurrentVBaseOffset) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
@@ -788,6 +2145,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
e = MD->end_overridden_methods(); mi != e; ++mi) {
GlobalDecl OGD;
+ GlobalDecl OGD2;
const CXXMethodDecl *OMD = *mi;
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
@@ -801,6 +2159,8 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
if (!Methods.getIndex(OGD, Index))
continue;
+ OGD2 = OGD;
+
// Get the original method, which we should be computing thunks, etc,
// against.
OGD = Methods.getOrigMethod(Index);
@@ -812,8 +2172,8 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
OMD->getType()->getAs<FunctionType>()->getResultType();
// Check if we need a return type adjustment.
- if (TypeConversionRequiresAdjustment(CGM.getContext(), ReturnType,
- OverriddenReturnType)) {
+ if (!ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
+ OMD).isEmpty()) {
CanQualType &BaseReturnType = BaseReturnTypes[Index];
// Insert the base return type.
@@ -824,26 +2184,39 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
Methods.OverrideMethod(OGD, GD);
+ GlobalDecl UGD = getUnique(GD);
+ const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
+ assert(UGD.getDecl() && "unique overrider not found");
+ assert(UGD == getUnique(OGD) && "unique overrider not unique");
+
ThisAdjustments.erase(Index);
- if (MorallyVirtual || VCall.count(OGD)) {
- Index_t &idx = VCall[OGD];
+ if (MorallyVirtual || VCall.count(UMD)) {
+
+ Index_t &idx = VCall[UMD];
if (idx == 0) {
- NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8;
- VCallOffset[GD] = OverrideOffset/8;
+ VCallOffset[GD] = VCallOffset[OGD];
+ // NonVirtualOffset[UMD] = CurrentVBaseOffset/8 - OverrideOffset/8;
+ NonVirtualOffset[UMD] = VCallOffset[OGD];
+ VCallOffsetForVCall[UMD] = OverrideOffset/8;
idx = VCalls.size()+1;
- VCalls.push_back(0);
+ VCalls.push_back(OverrideOffset/8 - CurrentVBaseOffset/8);
D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
MD->getNameAsString().c_str(), (int)-idx-3,
(int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
} else {
- NonVirtualOffset[GD] = NonVirtualOffset[OGD];
- VCallOffset[GD] = VCallOffset[OGD];
- VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8;
+ VCallOffset[GD] = NonVirtualOffset[UMD];
+ VCalls[idx-1] = -VCallOffsetForVCall[UGD] + OverrideOffset/8;
D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
MD->getNameAsString().c_str(), (int)-idx-3,
(int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
}
- int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
+ int64_t NonVirtualAdjustment = -VCallOffset[OGD];
+ QualType DerivedType = MD->getThisType(CGM.getContext());
+ QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
+ int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
+ if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
+ NonVirtualAdjustment = NonVirtualAdjustment2;
+ }
int64_t VirtualAdjustment =
-((idx + extra + 2) * LLVMPointerWidth / 8);
@@ -859,12 +2232,19 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
SavedAdjustments.push_back(
std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
}
- VCall[GD] = idx;
return true;
}
- int64_t NonVirtualAdjustment = -VCallOffset[OGD] + OverrideOffset/8;
+ VCallOffset[GD] = VCallOffset[OGD2] - OverrideOffset/8;
+ int64_t NonVirtualAdjustment = -VCallOffset[GD];
+ QualType DerivedType = MD->getThisType(CGM.getContext());
+ QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
+ int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
+ if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
+ NonVirtualAdjustment = NonVirtualAdjustment2;
+ }
+
if (NonVirtualAdjustment) {
ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
@@ -880,7 +2260,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
return false;
}
-void VtableBuilder::AppendMethodsToVtable() {
+void OldVtableBuilder::AppendMethodsToVtable() {
if (!BuildVtable) {
VtableComponents.insert(VtableComponents.end(), Methods.size(),
(llvm::Constant *)0);
@@ -948,13 +2328,13 @@ void VtableBuilder::AppendMethodsToVtable() {
void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Itanium C++ ABI 2.5.2:
- // The order of the virtual function pointers in a virtual table is the
- // order of declaration of the corresponding member functions in the class.
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
//
- // There is an entry for any virtual function declared in a class,
- // whether it is a new function or overrides a base class function,
- // unless it overrides a function from the primary base, and conversion
- // between their return types does not require an adjustment.
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
int64_t CurrentIndex = 0;
@@ -972,7 +2352,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Collect all the primary bases, so we can check whether methods override
// a method from the base.
- llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases;
+ VtableBuilder::PrimaryBasesSetTy PrimaryBases;
for (ASTRecordLayout::primary_base_info_iterator
I = Layout.primary_base_begin(), E = Layout.primary_base_end();
I != E; ++I)
@@ -988,51 +2368,33 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
if (!MD->isVirtual())
continue;
- bool ShouldAddEntryForMethod = true;
-
// Check if this method overrides a method in the primary base.
- for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
- e = MD->end_overridden_methods(); i != e; ++i) {
- const CXXMethodDecl *OverriddenMD = *i;
- const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
- assert(OverriddenMD->isCanonicalDecl() &&
- "Should have the canonical decl of the overridden RD!");
-
- if (PrimaryBases.count(OverriddenRD)) {
- // Check if converting from the return type of the method to the
- // return type of the overridden method requires conversion.
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- QualType OverriddenReturnType =
- OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
-
- if (!TypeConversionRequiresAdjustment(CGM.getContext(),
- ReturnType, OverriddenReturnType)) {
- // This index is shared between the index in the vtable of the primary
- // base class.
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- const CXXDestructorDecl *OverriddenDD =
- cast<CXXDestructorDecl>(OverriddenMD);
-
- // Add both the complete and deleting entries.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
- } else {
- MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
- }
+ if (const CXXMethodDecl *OverriddenMD =
+ OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+ // Check if converting from the return type of the method to the
+ // return type of the overridden method requires conversion.
+ if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
+ OverriddenMD).isEmpty()) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
- // We don't need to add an entry for this method.
- ShouldAddEntryForMethod = false;
- break;
- }
+ // Add both the complete and deleting entries.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ continue;
}
}
- if (!ShouldAddEntryForMethod)
- continue;
-
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
if (MD->isImplicit()) {
assert(!ImplicitVirtualDtor &&
@@ -1054,8 +2416,8 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
if (ImplicitVirtualDtor) {
// Itanium C++ ABI 2.5.2:
- // If a class has an implicitly-defined virtual destructor,
- // its entries come after the declared virtual function pointers.
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
// Add the complete dtor.
MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
@@ -1107,12 +2469,12 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) {
return 0;
AddressPointsMapTy AddressPoints;
- VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
+ OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
- for (VtableBuilder::SavedAdjustmentsVectorTy::iterator
+ for (OldVtableBuilder::SavedAdjustmentsVectorTy::iterator
i = b.getSavedAdjustments().begin(),
e = b.getSavedAdjustments().end(); i != e; i++)
SavedAdjustments[i->first].push_back(i->second);
@@ -1136,7 +2498,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
AddressPointsMapTy AddressPoints;
- VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
+ OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -1150,6 +2512,12 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
}
I = VirtualBaseClassIndicies.find(ClassPair);
+ // FIXME: The assertion below assertion currently fails with the old vtable
+ /// layout code if there is a non-virtual thunk adjustment in a vtable.
+ // Once the new layout is in place, this return should be removed.
+ if (I == VirtualBaseClassIndicies.end())
+ return 0;
+
assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
return I->second;
@@ -1168,6 +2536,13 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *LayoutClass,
const CXXRecordDecl *RD, uint64_t Offset,
AddressPointsMapTy& AddressPoints) {
+ if (GenerateDefinition && CGM.getLangOptions().DumpVtableLayouts &&
+ LayoutClass == RD) {
+ VtableBuilder Builder(*this, RD);
+
+ Builder.dumpLayout(llvm::errs());
+ }
+
llvm::SmallString<256> OutName;
if (LayoutClass != RD)
CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
@@ -1179,8 +2554,8 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 ||
GV->isDeclaration()) {
- VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
- AddressPoints);
+ OldVtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
+ AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f0a5c64d2fdf..5a4f94e3e092 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -171,6 +171,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
CurFn = Fn;
assert(CurFn->isDeclaration() && "Function already has body?");
+ // Pass inline keyword to optimizer if it appears explicitly on any
+ // declaration.
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
+ RE = FD->redecls_end(); RI != RE; ++RI)
+ if (RI->isInlineSpecified()) {
+ Fn->addFnAttr(llvm::Attribute::InlineHint);
+ break;
+ }
+
llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
// Create a marker to make it easy to insert allocas into the entryblock
@@ -196,7 +206,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
// FIXME: Leaked.
- CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args);
+ // CC info is ignored, hopefully?
+ CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args,
+ CC_Default, false);
if (RetTy->isVoidType()) {
// Void type; nothing to return.
@@ -281,6 +293,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
PushCleanupBlock(DtorEpilogue);
+ InitializeVtablePtrs(DD->getParent());
+
EmitStmt(S);
CleanupBlockInfo Info = PopCleanupBlock();
@@ -431,7 +445,11 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock);
EmitBlock(LHSTrue);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ EndConditionalBranch();
+
return;
} else if (CondBOp->getOpcode() == BinaryOperator::LOr) {
// If we have "0 || X", simplify the code. "1 || X" would have constant
@@ -454,7 +472,11 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse);
EmitBlock(LHSFalse);
+ // Any temporaries created here are conditional.
+ BeginConditionalBranch();
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ EndConditionalBranch();
+
return;
}
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 30ad663771be..fb2e5fee7309 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -268,7 +268,7 @@ public:
/// this behavior for branches?
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
- /// StartConditionalBranch - Should be called before a conditional part of an
+ /// BeginConditionalBranch - Should be called before a conditional part of an
/// expression is emitted. For example, before the RHS of the expression below
/// is emitted:
///
@@ -276,13 +276,16 @@ public:
///
/// This is used to make sure that any temporaries created in the conditional
/// branch are only destroyed if the branch is taken.
- void StartConditionalBranch() {
+ void BeginConditionalBranch() {
++ConditionalBranchLevel;
}
- /// FinishConditionalBranch - Should be called after a conditional part of an
+ /// EndConditionalBranch - Should be called after a conditional part of an
/// expression has been emitted.
- void FinishConditionalBranch() {
+ void EndConditionalBranch() {
+ assert(ConditionalBranchLevel != 0 &&
+ "Conditional branch mismatch!");
+
--ConditionalBranchLevel;
}
@@ -472,7 +475,7 @@ public:
const BlockInfo& Info,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- CharUnits &Size, uint64_t &Align,
+ CharUnits &Size, CharUnits &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose);
@@ -569,6 +572,9 @@ public:
const llvm::Type *ConvertTypeForMem(QualType T);
const llvm::Type *ConvertType(QualType T);
+ const llvm::Type *ConvertType(const TypeDecl *T) {
+ return ConvertType(getContext().getTypeDeclType(T));
+ }
/// LoadObjCSelf - Load the value of self. This function is only valid while
/// generating code for an Objective-C method.
@@ -652,10 +658,15 @@ public:
}
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
- /// block.
+ /// block. The caller is responsible for setting an appropriate alignment on
+ /// the alloca.
llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
const llvm::Twine &Name = "tmp");
+ /// CreateMemTemp - Create a temporary memory object of the given type, with
+ /// appropriate alignment.
+ llvm::Value *CreateMemTemp(QualType T, const llvm::Twine &Name = "tmp");
+
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *EvaluateExprAsBool(const Expr *E);
@@ -732,11 +743,16 @@ public:
/// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
/// virtual bases.
llvm::Value *LoadCXXVTT();
+
+ /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
+ /// complete class down to one of its virtual bases.
+ llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value,
+ bool IsVirtual,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base);
/// GetAddressOfBaseClass - This function will add the necessary delta to the
/// load of 'this' and returns address of the base class.
- // FIXME. This currently only does a derived to non-virtual base conversion.
- // Other kinds of conversions will come later.
llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl,
@@ -747,10 +763,9 @@ public:
const CXXRecordDecl *DerivedClassDecl,
bool NullCheckValue);
- llvm::Value *
- GetVirtualCXXBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
+ llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
llvm::Value *SrcValue,
@@ -843,7 +858,8 @@ public:
/// This function can be called with a null (unreachable) insert point.
void EmitLocalBlockVarDecl(const VarDecl &D);
- void EmitStaticBlockVarDecl(const VarDecl &D);
+ void EmitStaticBlockVarDecl(const VarDecl &D,
+ llvm::GlobalValue::LinkageTypes Linkage);
/// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
void EmitParmDecl(const VarDecl &D, llvm::Value *Arg);
@@ -1005,12 +1021,18 @@ public:
LValue EmitCastLValue(const CastExpr *E);
LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E);
- LValue EmitPointerToDataMemberLValue(const FieldDecl *Field);
-
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field,
- bool isUnion, unsigned CVRQualifiers);
+ unsigned CVRQualifiers);
+
+ /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that
+ /// if the Field is a reference, this will return the address of the reference
+ /// and not the address of the value stored in the reference.
+ LValue EmitLValueForFieldInitialization(llvm::Value* Base,
+ const FieldDecl* Field,
+ unsigned CVRQualifiers);
+
LValue EmitLValueForIvar(QualType ObjectTy,
llvm::Value* Base, const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers);
@@ -1103,8 +1125,7 @@ public:
/// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
/// expression. Will emit a temporary variable if E is not an LValue.
- RValue EmitReferenceBindingToExpr(const Expr* E, QualType DestType,
- bool IsInitializer = false);
+ RValue EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer = false);
//===--------------------------------------------------------------------===//
// Expression Emission
@@ -1135,6 +1156,10 @@ public:
bool IgnoreResult = false, bool IsInitializer = false,
bool RequiresGCollection = false);
+ /// EmitAggExprToLValue - Emit the computation of the specified expression of
+ /// aggregate type into a temporary LValue.
+ LValue EmitAggExprToLValue(const Expr *E);
+
/// EmitGCMemmoveCollectable - Emit special API for structs with object
/// pointers.
void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index cf504a7c2a0c..5a552c490ac6 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -20,6 +20,7 @@
#include "TargetInfo.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -131,6 +132,10 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const {
}
}
+ // This decl should have the same visibility as its parent.
+ if (const DeclContext *DC = D->getDeclContext())
+ return getDeclVisibilityMode(cast<Decl>(DC));
+
return getLangOptions().getVisibilityMode();
}
@@ -254,34 +259,40 @@ void CodeGenModule::EmitAnnotations() {
static CodeGenModule::GVALinkage
GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
const LangOptions &Features) {
- // Everything located semantically within an anonymous namespace is
- // always internal.
- if (FD->isInAnonymousNamespace())
- return CodeGenModule::GVA_Internal;
+ CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
- // "static" functions get internal linkage.
- if (FD->getStorageClass() == FunctionDecl::Static && !isa<CXXMethodDecl>(FD))
- return CodeGenModule::GVA_Internal;
+ Linkage L = FD->getLinkage();
+ if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
+ FD->getType()->getLinkage() == UniqueExternalLinkage)
+ L = UniqueExternalLinkage;
- // The kind of external linkage this function will have, if it is not
- // inline or static.
- CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
- if (Context.getLangOptions().CPlusPlus) {
- TemplateSpecializationKind TSK = FD->getTemplateSpecializationKind();
+ switch (L) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return CodeGenModule::GVA_Internal;
- if (TSK == TSK_ExplicitInstantiationDefinition) {
- // If a function has been explicitly instantiated, then it should
- // always have strong external linkage.
+ case ExternalLinkage:
+ switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ External = CodeGenModule::GVA_StrongExternal;
+ break;
+
+ case TSK_ExplicitInstantiationDefinition:
+ // FIXME: explicit instantiation definitions should use weak linkage
return CodeGenModule::GVA_StrongExternal;
- }
-
- if (TSK == TSK_ImplicitInstantiation)
+
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ImplicitInstantiation:
External = CodeGenModule::GVA_TemplateInstantiation;
+ break;
+ }
}
if (!FD->isInlined())
return External;
-
+
if (!Features.CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
@@ -402,11 +413,13 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
SetCommonAttributes(D, F);
}
-void CodeGenModule::SetFunctionAttributes(const FunctionDecl *FD,
+void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
llvm::Function *F,
bool IsIncompleteFunction) {
+ const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
if (!IsIncompleteFunction)
- SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(FD), F);
+ SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(GD), F);
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
@@ -580,14 +593,24 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Static data may be deferred, but out-of-line static data members
// cannot be.
- if (VD->isInAnonymousNamespace())
- return true;
- if (VD->getLinkage() == VarDecl::InternalLinkage) {
+ Linkage L = VD->getLinkage();
+ if (L == ExternalLinkage && getContext().getLangOptions().CPlusPlus &&
+ VD->getType()->getLinkage() == UniqueExternalLinkage)
+ L = UniqueExternalLinkage;
+
+ switch (L) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
// Initializer has side effects?
if (VD->getInit() && VD->getInit()->HasSideEffects(Context))
return false;
return !(VD->isStaticDataMember() && VD->isOutOfLine());
+
+ case ExternalLinkage:
+ break;
}
+
return false;
}
@@ -608,20 +631,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- if (getLangOptions().CPlusPlus && !VD->getInit()) {
- // In C++, if this is marked "extern", defer code generation.
- if (VD->getStorageClass() == VarDecl::Extern || VD->isExternC())
- return;
-
- // If this is a declaration of an explicit specialization of a static
- // data member in a class template, don't emit it.
- if (VD->isStaticDataMember() &&
- VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return;
- }
-
- // In C, if this isn't a definition, defer code generation.
- if (!getLangOptions().CPlusPlus && !VD->getInit())
+ if (VD->isThisDeclarationADefinition() != VarDecl::Definition)
return;
}
@@ -715,8 +725,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
"", &getModule());
F->setName(MangledName);
if (D.getDecl())
- SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F,
- IsIncompleteFunction);
+ SetFunctionAttributes(D, F, IsIncompleteFunction);
Entry = F;
// This is the first use or definition of a mangled name. If there is a
@@ -774,7 +783,7 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
}
static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) {
- if (!D->getType().isConstant(Context))
+ if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType())
return false;
if (Context.getLangOptions().CPlusPlus &&
Context.getBaseElementType(D->getType())->getAs<RecordType>()) {
@@ -941,16 +950,30 @@ CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) {
static CodeGenModule::GVALinkage
GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
- // Everything located semantically within an anonymous namespace is
- // always internal.
- if (VD->isInAnonymousNamespace())
+ // If this is a static data member, compute the kind of template
+ // specialization. Otherwise, this variable is not part of a
+ // template.
+ TemplateSpecializationKind TSK = TSK_Undeclared;
+ if (VD->isStaticDataMember())
+ TSK = VD->getTemplateSpecializationKind();
+
+ Linkage L = VD->getLinkage();
+ if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus &&
+ VD->getType()->getLinkage() == UniqueExternalLinkage)
+ L = UniqueExternalLinkage;
+
+ switch (L) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
return CodeGenModule::GVA_Internal;
- // Handle linkage for static data members.
- if (VD->isStaticDataMember()) {
- switch (VD->getTemplateSpecializationKind()) {
+ case ExternalLinkage:
+ switch (TSK) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
+
+ // FIXME: ExplicitInstantiationDefinition should be weak!
case TSK_ExplicitInstantiationDefinition:
return CodeGenModule::GVA_StrongExternal;
@@ -959,22 +982,26 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
// Fall through to treat this like any other instantiation.
case TSK_ImplicitInstantiation:
- return CodeGenModule::GVA_TemplateInstantiation;
+ return CodeGenModule::GVA_TemplateInstantiation;
}
}
- if (VD->getLinkage() == VarDecl::InternalLinkage)
- return CodeGenModule::GVA_Internal;
-
return CodeGenModule::GVA_StrongExternal;
}
+CharUnits CodeGenModule::GetTargetTypeStoreSize(const llvm::Type *Ty) const {
+ return CharUnits::fromQuantity(
+ TheTargetData.getTypeStoreSizeInBits(Ty) / Context.getCharWidth());
+}
+
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = 0;
QualType ASTTy = D->getType();
bool NonConstInit = false;
- if (D->getInit() == 0) {
+ const Expr *InitExpr = D->getAnyInitializer();
+
+ if (!InitExpr) {
// This is a tentative definition; tentative definitions are
// implicitly initialized with { 0 }.
//
@@ -987,10 +1014,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
Init = EmitNullConstant(D->getType());
} else {
- Init = EmitConstantExpr(D->getInit(), D->getType());
+ Init = EmitConstantExpr(InitExpr, D->getType());
if (!Init) {
- QualType T = D->getInit()->getType();
+ QualType T = InitExpr->getType();
if (getLangOptions().CPlusPlus) {
EmitCXXGlobalVarDeclInitFunc(D);
Init = EmitNullConstant(T);
@@ -1058,7 +1085,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (!NonConstInit && DeclIsConstantGlobal(Context, D))
GV->setConstant(true);
- GV->setAlignment(getContext().getDeclAlignInBytes(D));
+ GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
// Set the llvm linkage type as appropriate.
GVALinkage Linkage = GetLinkageForVariable(getContext(), D);
@@ -1256,8 +1283,8 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) {
const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
// Unique the name through the identifier table.
- const char *AliaseeName = AA->getAliasee().c_str();
- AliaseeName = getContext().Idents.get(AliaseeName).getNameStart();
+ const char *AliaseeName =
+ getContext().Idents.get(AA->getAliasee()).getNameStart();
// Create a reference to the named value. This ensures that it is emitted
// if a deferred decl.
@@ -1473,11 +1500,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
// String pointer.
llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str());
- const char *Sect = 0;
llvm::GlobalValue::LinkageTypes Linkage;
bool isConstant;
if (isUTF16) {
- Sect = getContext().Target.getUnicodeStringSection();
// FIXME: why do utf strings get "_" labels instead of "L" labels?
Linkage = llvm::GlobalValue::InternalLinkage;
// Note: -fwritable-strings doesn't make unicode CFStrings writable, but
@@ -1491,11 +1516,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
".str");
- if (Sect)
- GV->setSection(Sect);
if (isUTF16) {
- unsigned Align = getContext().getTypeAlign(getContext().ShortTy)/8;
- GV->setAlignment(Align);
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
+ GV->setAlignment(Align.getQuantity());
}
Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 81f39791fcd0..8280766c7035 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -53,6 +53,7 @@ namespace clang {
class ObjCProtocolDecl;
class ObjCEncodeExpr;
class BlockExpr;
+ class CharUnits;
class Decl;
class Expr;
class Stmt;
@@ -238,10 +239,11 @@ public:
BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
const CovariantThunkAdjustment &Adjustment);
- /// GetCXXBaseClassOffset - Returns the offset from a derived class to its
- /// base class. Returns null if the offset is 0.
- llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
+ /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to
+ /// its base class. Returns null if the offset is 0.
+ llvm::Constant *
+ GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl);
/// ComputeThunkAdjustment - Returns the two parts required to compute the
/// offset for an object.
@@ -346,6 +348,8 @@ public:
llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
const AnnotateAttr *AA, unsigned LineNo);
+ llvm::Constant *EmitPointerToDataMember(const FieldDecl *FD);
+
/// 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
@@ -417,6 +421,10 @@ public:
/// and type information of the given class.
static llvm::GlobalVariable::LinkageTypes
getVtableLinkage(const CXXRecordDecl *RD);
+
+ /// GetTargetTypeStoreSize - Return the store size, in character units, of
+ /// the given LLVM type.
+ CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const;
private:
/// UniqueMangledName - Unique a name by (if necessary) inserting it into the
@@ -443,7 +451,7 @@ private:
/// SetFunctionAttributes - Set function attributes for a function
/// declaration.
- void SetFunctionAttributes(const FunctionDecl *FD,
+ void SetFunctionAttributes(GlobalDecl GD,
llvm::Function *F,
bool IsIncompleteFunction);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 838f62a5cb1d..3c20934baf25 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -84,7 +84,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) {
const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) {
const llvm::Type *ResultType = ConvertTypeRecursive(T);
- if (ResultType->isInteger(1))
+ if (ResultType->isIntegerTy(1))
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));
// FIXME: Should assert that the llvm type and AST type has the same size.
@@ -99,7 +99,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
const llvm::Type *R = ConvertType(T);
// If this is a non-bool type, don't map it.
- if (!R->isInteger(1))
+ if (!R->isIntegerTy(1))
return R;
// Otherwise, return an integer of the target-specified size.
@@ -399,18 +399,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
/// enum.
const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
- // FIXME. This may have to move to a better place.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- ConvertTagDeclType(Base);
- }
- }
- }
-
// TagDecl's are not necessarily unique, instead use the (clang)
// type connected to the decl.
const Type *Key =
@@ -422,8 +410,8 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
if (TDTI != TagDeclTypes.end())
return TDTI->second;
- // If this is still a forward definition, just define an opaque type to use
- // for this tagged decl.
+ // If this is still a forward declaration, just define an opaque
+ // type to use for this tagged decl.
if (!TD->isDefinition()) {
llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext());
TagDeclTypes.insert(std::make_pair(Key, ResultType));
@@ -446,6 +434,18 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
const RecordDecl *RD = cast<const RecordDecl>(TD);
+ // Force conversion of non-virtual base classes recursively.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ ConvertTagDeclType(Base);
+ }
+ }
+ }
+
// Layout fields.
CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD);
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 7e342526e84b..87ba0bcfba1d 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -20,7 +20,7 @@
#include <vector>
#include "CGCall.h"
-#include "CGCXX.h"
+#include "GlobalDecl.h"
namespace llvm {
class FunctionType;
@@ -60,21 +60,24 @@ namespace CodeGen {
/// LLVMType - The LLVMType corresponding to this record layout.
const llvm::Type *LLVMType;
- /// ContainsMemberPointer - Whether one of the fields in this record layout
- /// is a member pointer, or a struct that contains a member pointer.
- bool ContainsMemberPointer;
+ /// ContainsPointerToDataMember - Whether one of the fields in this record
+ /// layout is a pointer to data member, or a struct that contains pointer to
+ /// data member.
+ bool ContainsPointerToDataMember;
public:
- CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer)
- : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { }
+ CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember)
+ : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) { }
/// getLLVMType - Return llvm type associated with this record.
const llvm::Type *getLLVMType() const {
return LLVMType;
}
- bool containsMemberPointer() const {
- return ContainsMemberPointer;
+ /// containsPointerToDataMember - Whether this struct contains pointers to
+ /// data members.
+ bool containsPointerToDataMember() const {
+ return ContainsPointerToDataMember;
}
};
@@ -187,6 +190,8 @@ private:
public:
/// getFunctionInfo - Get the function info for the specified function decl.
+ const CGFunctionInfo &getFunctionInfo(GlobalDecl GD);
+
const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
@@ -195,6 +200,12 @@ public:
const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D,
CXXDtorType Type);
+ const CGFunctionInfo &getFunctionInfo(const CallArgList &Args,
+ const FunctionType *Ty) {
+ return getFunctionInfo(Ty->getResultType(), Args,
+ Ty->getCallConv(), Ty->getNoReturnAttr());
+ }
+
// getFunctionInfo - Get the function info for a member function.
const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
@@ -204,13 +215,16 @@ public:
/// specified, the "C" calling convention will be used.
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const CallArgList &Args,
- unsigned CallingConvention = 0);
+ CallingConv CC,
+ bool NoReturn);
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
- unsigned CallingConvention = 0);
+ CallingConv CC,
+ bool NoReturn);
const CGFunctionInfo &getFunctionInfo(QualType RetTy,
const llvm::SmallVector<QualType, 16> &ArgTys,
- unsigned CallingConvention = 0);
+ CallingConv CC,
+ bool NoReturn);
public: // These are internal details of CGT that shouldn't be used externally.
/// addFieldInfo - Assign field number to field FD.
diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h
index b054312a0185..b8a98d7c03b6 100644
--- a/lib/CodeGen/GlobalDecl.h
+++ b/lib/CodeGen/GlobalDecl.h
@@ -15,6 +15,10 @@
#ifndef CLANG_CODEGEN_GLOBALDECL_H
#define CLANG_CODEGEN_GLOBALDECL_H
+#include "CGCXX.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+
namespace clang {
namespace CodeGen {
diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile
index 108490b71d48..83cb36738709 100644
--- a/lib/CodeGen/Makefile
+++ b/lib/CodeGen/Makefile
@@ -15,7 +15,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangCodeGen
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
ifdef CLANG_VENDOR
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index d873cfec1bd7..a302225c7f77 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -26,6 +26,13 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "CGVtable.h"
+
+#define MANGLE_CHECKER 0
+
+#if MANGLE_CHECKER
+#include <cxxabi.h>
+#endif
+
using namespace clang;
using namespace CodeGen;
@@ -44,6 +51,8 @@ static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
return MD;
}
+
+static const unsigned UnknownArity = ~0U;
/// CXXNameMangler - Manage the mangling of a single name.
class CXXNameMangler {
@@ -55,6 +64,8 @@ class CXXNameMangler {
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+ ASTContext &getASTContext() const { return Context.getASTContext(); }
+
public:
CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res)
: Context(C), Out(Res), Structor(0), StructorType(0) { }
@@ -65,6 +76,17 @@ public:
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { }
+#if MANGLE_CHECKER
+ ~CXXNameMangler() {
+ if (Out.str()[0] == '\01')
+ return;
+
+ int status = 0;
+ char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status);
+ assert(status == 0 && "Could not demangle mangled name!");
+ free(result);
+ }
+#endif
llvm::raw_svector_ostream &getStream() { return Out; }
void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
@@ -89,10 +111,19 @@ private:
void addSubstitution(QualType T);
void addSubstitution(uintptr_t Ptr);
+ void mangleUnresolvedScope(NestedNameSpecifier *Qualifier);
+ void mangleUnresolvedName(NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity = UnknownArity);
+
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleUnqualifiedName(const NamedDecl *ND);
+ void mangleUnqualifiedName(const NamedDecl *ND) {
+ mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity);
+ }
+ void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name,
+ unsigned KnownArity);
void mangleUnscopedName(const NamedDecl *ND);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleSourceName(const IdentifierInfo *II);
@@ -119,6 +150,11 @@ private:
bool MangleReturnType);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
+ void mangleMemberExpr(const Expr *Base, bool IsArrow,
+ NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity);
+ void mangleCalledExpression(const Expr *E, unsigned KnownArity);
void mangleExpression(const Expr *E);
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
@@ -171,14 +207,14 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
isInExternCSystemHeader(D->getLocation()))
return false;
- // Variables at global scope are not mangled.
+ // Variables at global scope with non-internal linkage are not mangled
if (!FD) {
const DeclContext *DC = D->getDeclContext();
// Check for extern variable declared locally.
if (isa<FunctionDecl>(DC) && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = DC->getParent();
- if (DC->isTranslationUnit())
+ if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
return false;
}
@@ -199,13 +235,10 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
return;
}
- // <mangled-name> ::= _Z [L] <encoding>
+ // <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
Out << Prefix;
- if (D->getLinkage() == NamedDecl::InternalLinkage) // match gcc behavior
- Out << 'L';
-
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
mangleFunctionEncoding(FD);
else
@@ -367,6 +400,13 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
if (mangleSubstitution(ND))
return;
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
+
mangleUnscopedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -401,28 +441,69 @@ void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) {
Out << '_';
}
-void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
+void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
+ Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier);
+ switch (Qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ // nothing
+ break;
+ case NestedNameSpecifier::Namespace:
+ mangleName(Qualifier->getAsNamespace());
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ mangleType(QualType(Qualifier->getAsType(), 0));
+ break;
+ case NestedNameSpecifier::Identifier:
+ mangleUnresolvedScope(Qualifier->getPrefix());
+ 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 ::
+
+ mangleUnqualifiedName(0, Name, KnownArity);
+}
+
+void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name,
+ unsigned KnownArity) {
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
- DeclarationName Name = ND->getDeclName();
switch (Name.getNameKind()) {
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 &&
+ ND->getDeclContext()->isFileContext())
+ Out << 'L';
+
+ mangleSourceName(II);
+ break;
+ }
+
+ // Otherwise, an anonymous entity. We must have a declaration.
+ assert(ND && "mangling empty name without declaration");
+
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
- // This is how gcc mangles these names. It's apparently
- // always '1', no matter how many different anonymous
- // namespaces appear in a context.
+ // This is how gcc mangles these names.
Out << "12_GLOBAL__N_1";
break;
}
}
- if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
- mangleSourceName(II);
- break;
- }
-
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
@@ -484,13 +565,18 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
break;
case DeclarationName::CXXOperatorName: {
- unsigned Arity = cast<FunctionDecl>(ND)->getNumParams();
+ unsigned Arity;
+ if (ND) {
+ Arity = cast<FunctionDecl>(ND)->getNumParams();
- // If we have a C++ member function, we need to include the 'this' pointer.
- // FIXME: This does not make sense for operators that are static, but their
- // names stay the same regardless of the arity (operator new for instance).
- if (isa<CXXMethodDecl>(ND))
- Arity++;
+ // If we have a C++ member function, we need to include the 'this' pointer.
+ // FIXME: This does not make sense for operators that are static, but their
+ // names stay the same regardless of the arity (operator new for instance).
+ if (isa<CXXMethodDecl>(ND))
+ Arity++;
+ } else
+ Arity = KnownArity;
+
mangleOperatorName(Name.getCXXOverloadedOperator(), Arity);
break;
}
@@ -596,15 +682,21 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
// ::= <substitution>
+ // <template-template-param> ::= <template-param>
+ // <substitution>
if (mangleSubstitution(ND))
return;
- // FIXME: <template-param>
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND->getTemplatedDecl());
-
addSubstitution(ND);
}
@@ -1013,7 +1105,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
-
+ assert(TD && "FIXME: Support dependent template names");
mangleTemplatePrefix(TD);
mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
addSubstitution(QualType(TST, 0));
@@ -1049,23 +1141,151 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
}
+void CXXNameMangler::mangleCalledExpression(const Expr *E, unsigned Arity) {
+ if (E->getType() != getASTContext().OverloadTy)
+ mangleExpression(E);
+ // propagate arity to dependent overloads?
+
+ llvm::PointerIntPair<OverloadExpr*,1> R
+ = OverloadExpr::find(const_cast<Expr*>(E));
+ if (R.getInt())
+ Out << "an"; // &
+ const OverloadExpr *Ovl = R.getPointer();
+ if (const UnresolvedMemberExpr *ME = dyn_cast<UnresolvedMemberExpr>(Ovl)) {
+ mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(),
+ ME->getMemberName(), Arity);
+ return;
+ }
+
+ mangleUnresolvedName(Ovl->getQualifier(), Ovl->getName(), Arity);
+}
+
+/// 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.
+///
+/// The standard ABI does not describe how member expressions should
+/// be mangled, so this is very unstandardized. We mangle as if it
+/// were a binary operator, except that the RHS is mangled as an
+/// abstract name.
+///
+/// The standard ABI also does not assign a mangling to the dot
+/// operator, so we arbitrarily select 'me'.
+void CXXNameMangler::mangleMemberExpr(const Expr *Base,
+ bool IsArrow,
+ NestedNameSpecifier *Qualifier,
+ DeclarationName Member,
+ unsigned Arity) {
+ Out << (IsArrow ? "pt" : "me");
+ mangleExpression(Base);
+ mangleUnresolvedName(Qualifier, Member, Arity);
+}
+
void CXXNameMangler::mangleExpression(const Expr *E) {
// <expression> ::= <unary operator-name> <expression>
- // ::= <binary operator-name> <expression> <expression>
- // ::= <trinary operator-name> <expression> <expression> <expression>
- // ::= cl <expression>* E # call
+ // ::= <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)
+ // ::= st <type> # sizeof (a type)
// ::= at <type> # alignof (a type)
// ::= <template-param>
// ::= <function-param>
// ::= sr <type> <unqualified-name> # dependent name
// ::= sr <type> <unqualified-name> <template-args> # dependent template-id
// ::= sZ <template-param> # size of a parameter pack
- // ::= <expr-primary>
+ // ::= <expr-primary>
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ // ::= L <type <value float> E # floating literal
+ // ::= L <mangled-name> E # external name
switch (E->getStmtClass()) {
- default: assert(false && "Unhandled expression kind!");
+ default:
+ llvm_unreachable("unexpected statement kind");
+ break;
+
+ case Expr::CallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+ Out << "cl";
+ mangleCalledExpression(CE->getCallee(), CE->getNumArgs());
+ for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
+ mangleExpression(CE->getArg(I));
+ Out << "E";
+ break;
+ }
+
+ case Expr::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMemberDecl()->getDeclName(),
+ UnknownArity);
+ break;
+ }
+
+ case Expr::UnresolvedMemberExprClass: {
+ const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMemberName(),
+ UnknownArity);
+ break;
+ }
+
+ case Expr::CXXDependentScopeMemberExprClass: {
+ const CXXDependentScopeMemberExpr *ME
+ = cast<CXXDependentScopeMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMember(),
+ UnknownArity);
+ 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(), UnknownArity);
+ break;
+ }
+
+ case Expr::CXXUnresolvedConstructExprClass: {
+ const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
+ unsigned N = CE->arg_size();
+
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << "_";
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << "E";
+ break;
+ }
+
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXConstructExprClass: {
+ const CXXConstructExpr *CE = cast<CXXConstructExpr>(E);
+ unsigned N = CE->getNumArgs();
+
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << "_";
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << "E";
+ break;
+ }
+
+ case Expr::SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E);
+ if (SAE->isSizeOf()) Out << "s";
+ else Out << "a";
+ if (SAE->isArgumentType()) {
+ Out << "t";
+ mangleType(SAE->getArgumentType());
+ } else {
+ Out << "z";
+ mangleExpression(SAE->getArgumentExpr());
+ }
+ break;
+ }
case Expr::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(E);
@@ -1082,7 +1302,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
mangleExpression(BO->getLHS());
mangleExpression(BO->getRHS());
break;
- }
+ }
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *CO = cast<ConditionalOperator>(E);
@@ -1093,6 +1313,24 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::ImplicitCastExprClass: {
+ mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr());
+ break;
+ }
+
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXStaticCastExprClass:
+ case Expr::CXXDynamicCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXConstCastExprClass:
+ case Expr::CXXFunctionalCastExprClass: {
+ const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
+ Out << "cv";
+ mangleType(ECE->getType());
+ mangleExpression(ECE->getSubExpr());
+ break;
+ }
+
case Expr::CXXOperatorCallExprClass: {
const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
unsigned NumArgs = CE->getNumArgs();
@@ -1139,6 +1377,20 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::FloatingLiteralClass: {
+ const FloatingLiteral *FL = cast<FloatingLiteral>(E);
+ Out << "L";
+ mangleType(FL->getType());
+
+ // TODO: avoid this copy with careful stream management.
+ llvm::SmallVector<char,20> Buffer;
+ FL->getValue().bitcastToAPInt().toString(Buffer, 16, false);
+ Out.write(Buffer.data(), Buffer.size());
+
+ Out << "E";
+ break;
+ }
+
case Expr::IntegerLiteralClass:
mangleIntegerLiteral(E->getType(),
llvm::APSInt(cast<IntegerLiteral>(E)->getValue()));
@@ -1216,6 +1468,8 @@ void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) {
mangleType(A.getAsType());
break;
case TemplateArgument::Template:
+ assert(A.getAsTemplate().getAsTemplateDecl() &&
+ "FIXME: Support dependent template names");
mangleName(A.getAsTemplate().getAsTemplateDecl());
break;
case TemplateArgument::Expression:
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 4454662a9304..a7c0caa299e7 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -271,6 +271,10 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
return ABIArgInfo::getIndirect(0);
} else {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -321,6 +325,9 @@ class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p)
:TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {}
+
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const;
};
}
@@ -358,6 +365,8 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
const RecordType *RT = Ty->getAs<RecordType>();
if (!RT) return false;
+ // FIXME: Traverse bases here too.
+
// Structure types are passed in register if all fields would be
// passed in a register.
for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
@@ -404,7 +413,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getDirect();
} else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- if (const RecordType *RT = RetTy->getAsStructureType()) {
+ if (const RecordType *RT = RetTy->getAs<RecordType>()) {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
if (hasNonTrivialDestructorOrCopyConstructor(RT))
@@ -463,6 +472,10 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getIndirect(0);
} else {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -484,10 +497,16 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
// FIXME: Set alignment on indirect arguments.
if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
// Structures with flexible arrays are always indirect.
- if (const RecordType *RT = Ty->getAsStructureType())
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (hasNonTrivialDestructorOrCopyConstructor(RT))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
if (RT->getDecl()->hasFlexibleArrayMember())
return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
Context));
+ }
// Ignore empty structs.
if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0)
@@ -503,6 +522,9 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
} else {
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -532,6 +554,20 @@ llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return AddrTyped;
}
+void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
+ llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
+ // Get the LLVM function.
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+
+ // Now add the 'alignstack' attribute with a value of 16.
+ Fn->addFnAttr(llvm::Attribute::constructStackAlignmentFromInt(16));
+ }
+ }
+}
+
namespace {
/// X86_64ABIInfo - The X86_64 ABI information.
class X86_64ABIInfo : public ABIInfo {
@@ -927,6 +963,11 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) {
// Integer and pointer types will end up in a general purpose
// register.
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
if (Ty->isIntegralType() || Ty->hasPointerRepresentation())
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
@@ -948,9 +989,14 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
ASTContext &Context) const {
// If this is a scalar LLVM value then assume LLVM will pass it in the right
// place naturally.
- if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
@@ -1319,14 +1365,14 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
const llvm::Type *TyLo = ST->getElementType(0);
const llvm::Type *TyHi = ST->getElementType(1);
- assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) &&
+ assert((TyLo->isFloatingPointTy() ^ TyHi->isFloatingPointTy()) &&
"Unexpected ABI info for mixed regs");
const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
- llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr;
- llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr;
+ llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr : GPAddr;
+ llvm::Value *RegHiAddr = TyLo->isFloatingPointTy() ? GPAddr : FPAddr;
llvm::Value *V =
CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
@@ -1526,9 +1572,14 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
ASTContext &Context,
llvm::LLVMContext &VMContext) const {
- if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
// Ignore empty records.
if (isEmptyRecord(Context, Ty, true))
@@ -1577,9 +1628,9 @@ static bool isIntegerLikeType(QualType Ty,
if (Ty->getAs<BuiltinType>() || Ty->isPointerType())
return true;
- // Complex types "should" be ok by the definition above, but they are not.
- if (Ty->isAnyComplexType())
- return false;
+ // Small complex integer types are "integer like".
+ if (const ComplexType *CT = Ty->getAs<ComplexType>())
+ return isIntegerLikeType(CT->getElementType(), Context, VMContext);
// Single element and zero sized arrays should be allowed, by the definition
// above, but they are not.
@@ -1603,30 +1654,30 @@ static bool isIntegerLikeType(QualType Ty,
i != e; ++i, ++idx) {
const FieldDecl *FD = *i;
- // Check if this field is at offset 0.
- uint64_t Offset = Layout.getFieldOffset(idx);
- if (Offset != 0) {
- // Allow padding bit-fields, but only if they are all at the end of the
- // structure (despite the wording above, this matches gcc).
- if (FD->isBitField() &&
- !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
- for (; i != e; ++i)
- if (!i->isBitField() ||
- i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
- return false;
-
- // All remaining fields are padding, allow this.
- return true;
- }
+ // Bit-fields are not addressable, we only need to verify they are "integer
+ // like". We still have to disallow a subsequent non-bitfield, for example:
+ // struct { int : 0; int x }
+ // is non-integer like according to gcc.
+ if (FD->isBitField()) {
+ if (!RD->isUnion())
+ HadField = true;
- return false;
+ if (!isIntegerLikeType(FD->getType(), Context, VMContext))
+ return false;
+
+ continue;
}
+ // Check if this field is at offset 0.
+ if (Layout.getFieldOffset(idx) != 0)
+ return false;
+
if (!isIntegerLikeType(FD->getType(), Context, VMContext))
return false;
- // Only allow at most one field in a structure. Again this doesn't match the
- // wording above, but follows gcc.
+ // Only allow at most one field in a structure. This doesn't match the
+ // wording above, but follows gcc in situations with a field following an
+ // empty structure.
if (!RD->isUnion()) {
if (HadField)
return false;
@@ -1644,15 +1695,28 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
- if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
+ if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
// Are we following APCS?
if (getABIKind() == APCS) {
if (isEmptyRecord(Context, RetTy, false))
return ABIArgInfo::getIgnore();
+ // Complex types are all returned as packed integers.
+ //
+ // FIXME: Consider using 2 x vector types if the back end handles them
+ // correctly.
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(
+ VMContext, Context.getTypeSize(RetTy)));
+
// Integer like structures are returned in r0.
if (isIntegerLikeType(RetTy, Context, VMContext)) {
// Return in the smallest viable integer type.
@@ -1721,6 +1785,10 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
} else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
return ABIArgInfo::getIndirect(0);
} else {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
return (RetTy->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 852a018e10f4..15df767d9707 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -50,8 +50,8 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple),
DefaultImageName(_DefaultImageName),
Host(0),
- CCCIsCXX(false), CCCEcho(false), CCCPrintBindings(false),
- CCCGenericGCCName("gcc"), CCCUseClang(true),
+ CCCGenericGCCName("gcc"), CCCIsCXX(false), CCCEcho(false),
+ CCCPrintBindings(false), CheckInputsExist(true), CCCUseClang(true),
CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true),
SuppressMissingInputWarning(false) {
if (IsProduction) {
@@ -158,10 +158,8 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
llvm::Triple::ArchType Arch =
llvm::Triple(Split.first, "", "").getArch();
- if (Arch == llvm::Triple::UnknownArch) {
- Diag(clang::diag::err_drv_invalid_arch_name) << Arch;
- continue;
- }
+ if (Arch == llvm::Triple::UnknownArch)
+ Diag(clang::diag::err_drv_invalid_arch_name) << Split.first;
CCCClangArchs.insert(Arch);
}
@@ -579,10 +577,9 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
Ty = InputType;
}
- // Check that the file exists. It isn't clear this is worth doing, since
- // the tool presumably does this anyway, and this just adds an extra stat
- // to the equation, but this is gcc compatible.
- if (memcmp(Value, "-", 2) != 0 && !llvm::sys::Path(Value).exists())
+ // Check that the file exists, if enabled.
+ if (CheckInputsExist && memcmp(Value, "-", 2) != 0 &&
+ !llvm::sys::Path(Value).exists())
Diag(clang::diag::err_drv_no_such_file) << A->getValue(Args);
else
Inputs.push_back(std::make_pair(Ty, A));
@@ -625,6 +622,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
// -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
} else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT_rewrite_objc)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT__analyze,
options::OPT__analyze_auto)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) ||
@@ -745,6 +743,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
if (Args.hasArg(options::OPT_fsyntax_only)) {
return new CompileJobAction(Input, types::TY_Nothing);
+ } else if (Args.hasArg(options::OPT_rewrite_objc)) {
+ return new CompileJobAction(Input, types::TY_RewrittenObjC);
} else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
return new AnalyzeJobAction(Input, types::TY_Plist);
} else if (Args.hasArg(options::OPT_emit_ast)) {
@@ -866,6 +866,44 @@ void Driver::BuildJobs(Compilation &C) const {
}
}
+static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
+ const JobAction *JA,
+ const ActionList *&Inputs) {
+ const Tool *ToolForJob = 0;
+
+ // See if we should look for a compiler with an integrated assembler. We match
+ // bottom up, so what we are actually looking for is an assembler job with a
+ // compiler input.
+ if (C.getArgs().hasArg(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ TC->IsIntegratedAssemblerDefault()) &&
+ !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()));
+ if (Compiler.hasIntegratedAssembler()) {
+ Inputs = &(*Inputs)[0]->getInputs();
+ ToolForJob = &Compiler;
+ }
+ }
+
+ // Otherwise use the tool for the current job.
+ if (!ToolForJob)
+ ToolForJob = &TC->SelectTool(C, *JA);
+
+ // See if we should use an integrated preprocessor. We do so when we have
+ // exactly one input, since this is the only use case we care about
+ // (irrelevant since we don't support combine yet).
+ if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin()) &&
+ !C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
+ !C.getArgs().hasArg(options::OPT_traditional_cpp) &&
+ !C.getArgs().hasArg(options::OPT_save_temps) &&
+ ToolForJob->hasIntegratedCPP())
+ Inputs = &(*Inputs)[0]->getInputs();
+
+ return *ToolForJob;
+}
+
void Driver::BuildJobsForAction(Compilation &C,
const Action *A,
const ToolChain *TC,
@@ -906,21 +944,10 @@ void Driver::BuildJobsForAction(Compilation &C,
return;
}
- const JobAction *JA = cast<JobAction>(A);
- const Tool &T = TC->SelectTool(C, *JA);
-
- // See if we should use an integrated preprocessor. We do so when we have
- // exactly one input, since this is the only use case we care about
- // (irrelevant since we don't support combine yet).
const ActionList *Inputs = &A->getInputs();
- if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) {
- if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
- !C.getArgs().hasArg(options::OPT_traditional_cpp) &&
- !C.getArgs().hasArg(options::OPT_save_temps) &&
- T.hasIntegratedCPP()) {
- Inputs = &(*Inputs)[0]->getInputs();
- }
- }
+
+ const JobAction *JA = cast<JobAction>(A);
+ const Tool &T = SelectToolForJob(C, TC, JA, Inputs);
// Only use pipes when there is exactly one input.
bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput();
@@ -1147,8 +1174,10 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
return false;
}
- // Always use clang for precompiling and AST generation, regardless of archs.
- if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST)
+ // Always use clang for precompiling, AST generation, and rewriting,
+ // regardless of archs.
+ if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST ||
+ JA.getType() == types::TY_RewrittenObjC)
return true;
// Finally, don't use clang if this isn't one of the user specified archs to
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index ed73b17d75f1..18bb78659305 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -106,7 +106,7 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
if (Arg *A = Args.getLastArg(options::OPT_arch)) {
// The gcc driver behavior with multiple -arch flags wasn't consistent for
// things which rely on a default architecture. We just use the last -arch
- // to find the default tool chain (assuming it is valid..
+ // to find the default tool chain (assuming it is valid).
Arch = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
// If it was invalid just use the host, we will reject this command line
@@ -146,10 +146,10 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
// If we recognized the arch, match it to the toolchains we support.
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, DarwinVersion, GCCVersion,
- false);
+ TC = new toolchains::DarwinGCC(*this, TCTriple, DarwinVersion,
+ GCCVersion);
} else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
- TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion, true);
+ TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion);
else
TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple);
}
@@ -159,8 +159,7 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
// Unknown Host Info
-/// UnknownHostInfo - Generic host information to use for unknown
-/// hosts.
+/// UnknownHostInfo - Generic host information to use for unknown hosts.
class UnknownHostInfo : public HostInfo {
/// Cache of tool chains we have created.
mutable llvm::StringMap<ToolChain*> ToolChains;
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
index dbacf8be0141..371bda781c67 100644
--- a/lib/Driver/Makefile
+++ b/lib/Driver/Makefile
@@ -10,7 +10,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangDriver
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index a9c6a68ceb8a..a7cd711df1bc 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -31,20 +31,12 @@ using namespace clang::driver::toolchains;
/// Darwin - Darwin tool chain for i386 and x86_64.
Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&_DarwinVersion)[3], bool _IsIPhoneOS)
- : ToolChain(Host, Triple),
- IsIPhoneOS(_IsIPhoneOS)
+ const unsigned (&_DarwinVersion)[3])
+ : ToolChain(Host, Triple), TargetInitialized(false)
{
- DarwinVersion[0] = _DarwinVersion[0];
- DarwinVersion[1] = _DarwinVersion[1];
- DarwinVersion[2] = _DarwinVersion[2];
-
llvm::raw_string_ostream(MacosxVersionMin)
- << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.'
- << DarwinVersion[1];
-
- // FIXME: Lift default up.
- IPhoneOSVersionMin = "3.0";
+ << "10." << std::max(0, (int)_DarwinVersion[0] - 4) << '.'
+ << _DarwinVersion[1];
}
// FIXME: Can we tablegen this?
@@ -112,8 +104,8 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
const unsigned (&DarwinVersion)[3],
- const unsigned (&_GCCVersion)[3], bool IsIPhoneOS)
- : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS)
+ const unsigned (&_GCCVersion)[3])
+ : Darwin(Host, Triple, DarwinVersion)
{
GCCVersion[0] = _GCCVersion[0];
GCCVersion[1] = _GCCVersion[1];
@@ -245,8 +237,7 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- unsigned MacosxVersionMin[3];
- getMacosxVersionMin(Args, MacosxVersionMin);
+ // 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)) {
@@ -256,7 +247,7 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lgcc_eh");
} else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
// Derived from darwin_iphoneos_libgcc spec.
- if (isIPhoneOS()) {
+ if (isTargetIPhoneOS()) {
CmdArgs.push_back("-lgcc_s.1");
} else {
CmdArgs.push_back("-lgcc_s.10.5");
@@ -266,20 +257,20 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
options::OPT_fno_exceptions) ||
Args.hasArg(options::OPT_fgnu_runtime)) {
// FIXME: This is probably broken on 10.3?
- if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ if (isMacosxVersionLT(10, 5))
CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ else if (isMacosxVersionLT(10, 6))
CmdArgs.push_back("-lgcc_s.10.5");
} else {
- if (isMacosxVersionLT(MacosxVersionMin, 10, 3, 9))
+ if (isMacosxVersionLT(10, 3, 9))
; // Do nothing.
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ else if (isMacosxVersionLT(10, 5))
CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ else if (isMacosxVersionLT(10, 6))
CmdArgs.push_back("-lgcc_s.10.5");
}
- if (isIPhoneOS() || isMacosxVersionLT(MacosxVersionMin, 10, 6)) {
+ if (isTargetIPhoneOS() || isMacosxVersionLT(10, 6)) {
CmdArgs.push_back("-lgcc");
CmdArgs.push_back("-lSystem");
} else {
@@ -290,9 +281,8 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
}
DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3],
- bool IsIPhoneOS)
- : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS)
+ const unsigned (&DarwinVersion)[3])
+ : Darwin(Host, Triple, DarwinVersion)
{
// We expect 'as', 'ld', etc. to be adjacent to our install dir.
getProgramPaths().push_back(getDriver().Dir);
@@ -325,7 +315,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// Select the dynamic runtime library and the target specific static library.
const char *DarwinStaticLib = 0;
- if (isIPhoneOS()) {
+ if (isTargetIPhoneOS()) {
CmdArgs.push_back("-lgcc_s.1");
// We may need some static functions for armv6/thumb which are required to
@@ -333,20 +323,17 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
if (getDarwinArchName(Args) == "armv6")
DarwinStaticLib = "libclang_rt.armv6.a";
} else {
- unsigned MacosxVersionMin[3];
- getMacosxVersionMin(Args, MacosxVersionMin);
-
// The dynamic runtime library was merged with libSystem for 10.6 and
// beyond; only 10.4 and 10.5 need an additional runtime library.
- if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ if (isMacosxVersionLT(10, 5))
CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ else if (isMacosxVersionLT(10, 6))
CmdArgs.push_back("-lgcc_s.10.5");
// For OS X, we only need a static runtime library when targetting 10.4, to
// provide versions of the static functions which were omitted from
// 10.4.dylib.
- if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ if (isMacosxVersionLT(10, 5))
DarwinStaticLib = "libclang_rt.10.4.a";
}
@@ -367,21 +354,6 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
-void Darwin::getMacosxVersionMin(const ArgList &Args,
- unsigned (&Res)[3]) const {
- if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) {
- bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Res[0], Res[1], Res[2],
- HadExtra) ||
- HadExtra) {
- const Driver &D = getDriver();
- D.Diag(clang::diag::err_drv_invalid_version_number)
- << A->getAsString(Args);
- }
- } else
- return getMacosxVersion(Res);
-}
-
DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
const char *BoundArch) const {
DerivedArgList *DAL = new DerivedArgList(Args, false);
@@ -394,34 +366,84 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
// have something that works, we should reevaluate each translation
// and try to push it down into tool specific logic.
- Arg *OSXVersion =
- Args.getLastArgNoClaim(options::OPT_mmacosx_version_min_EQ);
- Arg *iPhoneVersion =
- Args.getLastArgNoClaim(options::OPT_miphoneos_version_min_EQ);
+ Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
+ Arg *iPhoneVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
if (OSXVersion && iPhoneVersion) {
getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
<< iPhoneVersion->getAsString(Args);
+ iPhoneVersion = 0;
} else if (!OSXVersion && !iPhoneVersion) {
- // Chose the default version based on the arch.
+ // If neither OS X nor iPhoneOS targets were specified, check for
+ // environment defines.
+ const char *OSXTarget = ::getenv("MACOSX_DEPLOYMENT_TARGET");
+ const char *iPhoneOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET");
+
+ // Ignore empty strings.
+ if (OSXTarget && OSXTarget[0] == '\0')
+ OSXTarget = 0;
+ if (iPhoneOSTarget && iPhoneOSTarget[0] == '\0')
+ iPhoneOSTarget = 0;
+
+ // Diagnose conflicting deployment targets, and choose default platform
+ // based on the tool chain.
//
- // FIXME: Are there iPhone overrides for this?
-
- if (!isIPhoneOS()) {
- // Look for MACOSX_DEPLOYMENT_TARGET, otherwise use the version
- // from the host.
- const char *Version = ::getenv("MACOSX_DEPLOYMENT_TARGET");
- if (!Version)
- Version = MacosxVersionMin.c_str();
+ // 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?
+ if (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb)
+ OSXVersion = 0;
+ else
+ iPhoneVersion = 0;
+ }
+
+ if (OSXTarget) {
const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
- DAL->append(DAL->MakeJoinedArg(0, O, Version));
- } else {
- const char *Version = IPhoneOSVersionMin.c_str();
+ OSXVersion = DAL->MakeJoinedArg(0, O, OSXTarget);
+ DAL->append(OSXVersion);
+ } else if (iPhoneOSTarget) {
const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
- DAL->append(DAL->MakeJoinedArg(0, O, Version));
+ iPhoneVersion = DAL->MakeJoinedArg(0, O, iPhoneOSTarget);
+ DAL->append(iPhoneVersion);
+ } else {
+ // Otherwise, choose a default platform based on the tool chain.
+ //
+ // FIXME: Don't hardcode default here.
+ if (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb) {
+ const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
+ iPhoneVersion = DAL->MakeJoinedArg(0, O, "3.0");
+ DAL->append(iPhoneVersion);
+ } else {
+ const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ OSXVersion = DAL->MakeJoinedArg(0, O, MacosxVersionMin);
+ DAL->append(OSXVersion);
+ }
}
}
+ // Set the tool chain target information.
+ unsigned Major, Minor, Micro;
+ bool HadExtra;
+ if (OSXVersion) {
+ assert(!iPhoneVersion && "Unknown target platform!");
+ if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor,
+ Micro, HadExtra) || HadExtra ||
+ Major != 10 || Minor >= 10 || Micro >= 10)
+ 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,
+ Micro, HadExtra) || HadExtra ||
+ Major >= 10 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(clang::diag::err_drv_invalid_version_number)
+ << iPhoneVersion->getAsString(Args);
+ }
+ setTarget(iPhoneVersion, Major, Minor, Micro);
+
for (ArgList::iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) {
Arg *A = *it;
@@ -618,6 +640,12 @@ bool Darwin::UseDwarfDebugFlags() const {
return false;
}
+bool Darwin::UseSjLjExceptions() const {
+ // Darwin uses SjLj exceptions on ARM.
+ return (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb);
+}
+
const char *Darwin::GetDefaultRelocationModel() const {
return "pic";
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 3ca6ad88972c..fda08758c9bc 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -47,42 +47,60 @@ public:
class VISIBILITY_HIDDEN Darwin : public ToolChain {
mutable llvm::DenseMap<unsigned, Tool*> Tools;
- /// Darwin version of tool chain.
- unsigned DarwinVersion[3];
-
- /// Whether this is this an iPhoneOS toolchain.
+ /// Whether the information on the target has been initialized.
//
- // FIXME: This should go away, such differences should be completely
- // determined by the target triple.
- bool IsIPhoneOS;
+ // FIXME: This should be eliminated. What we want to do is make this part of
+ // the "default target for arguments" selection process, once we get out of
+ // the argument translation business.
+ mutable bool TargetInitialized;
+
+ /// Whether we are targetting iPhoneOS target.
+ mutable bool TargetIsIPhoneOS;
+
+ /// The OS version we are targetting.
+ mutable unsigned TargetVersion[3];
/// The default macosx-version-min of this tool chain; empty until
/// initialized.
- mutable std::string MacosxVersionMin;
-
- /// The default iphoneos-version-min of this tool chain.
- std::string IPhoneOSVersionMin;
-
- const char *getMacosxVersionMin() const;
+ std::string MacosxVersionMin;
public:
Darwin(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3], bool IsIPhoneOS);
+ const unsigned (&DarwinVersion)[3]);
~Darwin();
/// @name Darwin Specific Toolchain API
/// {
- void getDarwinVersion(unsigned (&Res)[3]) const {
- Res[0] = DarwinVersion[0];
- Res[1] = DarwinVersion[1];
- Res[2] = DarwinVersion[2];
+ // 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 {
+ // 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 &&
+ TargetVersion[0] == Major && TargetVersion[1] == Minor &&
+ TargetVersion[2] == Micro)
+ return;
+
+ assert(!TargetInitialized && "Target already initialized!");
+ TargetInitialized = true;
+ TargetIsIPhoneOS = isIPhoneOS;
+ TargetVersion[0] = Major;
+ TargetVersion[1] = Minor;
+ TargetVersion[2] = Micro;
}
- void getMacosxVersion(unsigned (&Res)[3]) const {
- Res[0] = 10;
- Res[1] = DarwinVersion[0] - 4;
- Res[2] = DarwinVersion[1];
+ bool isTargetIPhoneOS() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetIsIPhoneOS;
+ }
+
+ void getTargetVersion(unsigned (&Res)[3]) const {
+ assert(TargetInitialized && "Target not initialized!");
+ Res[0] = TargetVersion[0];
+ Res[1] = TargetVersion[1];
+ Res[2] = TargetVersion[2];
}
/// getDarwinArchName - Get the "Darwin" arch name for a particular compiler
@@ -90,11 +108,7 @@ public:
/// distinct architectures.
llvm::StringRef getDarwinArchName(const ArgList &Args) const;
- /// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is
- /// either the -mmacosx-version-min, or the current version if unspecified.
- void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const;
-
- static bool isMacosxVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
+ static bool isVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
for (unsigned i=0; i < 3; ++i) {
if (A[i] > B[i]) return false;
if (A[i] < B[i]) return true;
@@ -102,18 +116,16 @@ public:
return false;
}
- static bool isMacosxVersionLT(unsigned (&A)[3],
- unsigned V0, unsigned V1=0, unsigned V2=0) {
+ bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
+ assert(isTargetIPhoneOS() && "Unexpected call for OS X target!");
unsigned B[3] = { V0, V1, V2 };
- return isMacosxVersionLT(A, B);
+ return isVersionLT(TargetVersion, B);
}
- const char *getMacosxVersionStr() const {
- return MacosxVersionMin.c_str();
- }
-
- const char *getIPhoneOSVersionStr() const {
- return IPhoneOSVersionMin.c_str();
+ bool isMacosxVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
+ assert(!isTargetIPhoneOS() && "Unexpected call for iPhoneOS target!");
+ unsigned B[3] = { V0, V1, V2 };
+ return isVersionLT(TargetVersion, B);
}
/// AddLinkSearchPathArgs - Add the linker search paths to \arg CmdArgs.
@@ -129,8 +141,6 @@ public:
virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const = 0;
- bool isIPhoneOS() const { return IsIPhoneOS; }
-
/// }
/// @name ToolChain Implementation
/// {
@@ -141,24 +151,33 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
virtual bool IsBlocksDefault() const {
- // Blocks default to on for 10.6 (darwin10) and beyond.
- return (DarwinVersion[0] > 9);
+ // Blocks default to on for OS X 10.6 and iPhoneOS 3.0 and beyond.
+ if (isTargetIPhoneOS())
+ return !isIPhoneOSVersionLT(3);
+ else
+ return !isMacosxVersionLT(10, 6);
}
virtual bool IsObjCNonFragileABIDefault() const {
- // Non-fragile ABI default to on for 10.5 (darwin9) and beyond on x86-64.
- return (DarwinVersion[0] >= 9 &&
- getTriple().getArch() == llvm::Triple::x86_64);
+ // Non-fragile ABI default to on for iPhoneOS and x86-64.
+ return isTargetIPhoneOS() || getTriple().getArch() == llvm::Triple::x86_64;
+ }
+ virtual bool IsObjCLegacyDispatchDefault() const {
+ // This is only used with the non-fragile ABI.
+ return (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb);
}
virtual bool IsUnwindTablesDefault() const;
virtual unsigned GetDefaultStackProtectorLevel() const {
- // Stack protectors default to on for 10.6 (darwin10) and beyond.
- return (DarwinVersion[0] > 9) ? 1 : 0;
+ // Stack protectors default to on for 10.6 and beyond.
+ return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 6);
}
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
virtual bool UseDwarfDebugFlags() const;
+ virtual bool UseSjLjExceptions() const;
+
/// }
};
@@ -166,7 +185,7 @@ public:
class VISIBILITY_HIDDEN DarwinClang : public Darwin {
public:
DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3], bool IsIPhoneOS);
+ const unsigned (&DarwinVersion)[3]);
/// @name Darwin ToolChain Implementation
/// {
@@ -190,8 +209,8 @@ class VISIBILITY_HIDDEN DarwinGCC : public Darwin {
public:
DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
- const unsigned (&DarwinVersion)[3], const unsigned (&GCCVersion)[3],
- bool IsIPhoneOS);
+ const unsigned (&DarwinVersion)[3],
+ const unsigned (&GCCVersion)[3]);
/// @name Darwin ToolChain Implementation
/// {
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index afb22a236767..aff70bc7ba0d 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -512,7 +512,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
// Select the default CPU if none was given (or detection failed).
if (!CPUName) {
// FIXME: Need target hooks.
- if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) {
+ if (getToolChain().getOS().startswith("darwin")) {
if (getToolChain().getArchName() == "x86_64")
CPUName = "core2";
else if (getToolChain().getArchName() == "i386")
@@ -586,43 +586,35 @@ static std::string getEffectiveClangTriple(const Driver &D,
const ArgList &Args) {
llvm::Triple Triple(getLLVMTriple(TC, Args));
+ // Handle -mmacosx-version-min and -miphoneos-version-min.
if (Triple.getOS() != llvm::Triple::Darwin) {
// Diagnose use of -mmacosx-version-min and -miphoneos-version-min on
// non-Darwin.
if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ,
options::OPT_miphoneos_version_min_EQ))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
- return Triple.getTriple();
- }
-
- // If -mmacosx-version-min=10.3.9 is specified, change the effective triple
- // from being something like powerpc-apple-darwin9 to powerpc-apple-darwin7.
- if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) {
- unsigned Major, Minor, Micro;
- bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro,
- HadExtra) || HadExtra ||
- Major != 10)
- D.Diag(clang::diag::err_drv_invalid_version_number)
- << A->getAsString(Args);
+ } else {
+ const toolchains::Darwin &DarwinTC(
+ reinterpret_cast<const toolchains::Darwin&>(TC));
+ unsigned Version[3];
+ DarwinTC.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 (!DarwinTC.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");
+ }
- // Mangle the MacOS version min number into the Darwin number: e.g. 10.3.9
- // is darwin7.9.
- llvm::SmallString<16> Str;
- llvm::raw_svector_ostream(Str) << "darwin" << Minor + 4 << "." << Micro;
- Triple.setOSName(Str.str());
- } else if (Arg *A = Args.getLastArg(options::OPT_miphoneos_version_min_EQ)) {
- unsigned Major, Minor, Micro;
- bool HadExtra;
- if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro,
- HadExtra) || HadExtra)
- D.Diag(clang::diag::err_drv_invalid_version_number)
- << A->getAsString(Args);
-
- // Mangle the iPhoneOS version number into the Darwin number: e.g. 2.0 is 2
- // -> 9.2.0.
llvm::SmallString<16> Str;
- llvm::raw_svector_ostream(Str) << "darwin9." << Major << "." << Minor;
+ llvm::raw_svector_ostream(Str) << "darwin" << Version[0]
+ << "." << Version[1] << "." << Version[2];
Triple.setOSName(Str.str());
}
@@ -659,6 +651,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-Eonly");
else
CmdArgs.push_back("-E");
+ } else if (isa<AssembleJobAction>(JA)) {
+ CmdArgs.push_back("-emit-obj");
} else if (isa<PrecompileJobAction>(JA)) {
// Use PCH if the user requested it, except for C++ (for now).
bool UsePCH = D.CCCUsePCH;
@@ -682,12 +676,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-S");
} else if (JA.getType() == types::TY_AST) {
CmdArgs.push_back("-emit-pch");
+ } else if (JA.getType() == types::TY_RewrittenObjC) {
+ CmdArgs.push_back("-rewrite-objc");
+ } else {
+ assert(JA.getType() == types::TY_PP_Asm &&
+ "Unexpected output type!");
}
}
// The make clang go fast button.
CmdArgs.push_back("-disable-free");
+ // Disable the verification pass in -asserts builds.
+#ifdef NDEBUG
+ CmdArgs.push_back("-disable-llvm-verifier");
+#endif
+
// Set the main file name, so that debug info works even with
// -save-temps.
CmdArgs.push_back("-main-file-name");
@@ -707,14 +711,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
- CmdArgs.push_back("-warn-dead-stores");
- CmdArgs.push_back("-warn-security-syntactic");
- CmdArgs.push_back("-checker-cfref");
+ CmdArgs.push_back("-analyzer-check-dead-stores");
+ CmdArgs.push_back("-analyzer-check-security-syntactic");
+ CmdArgs.push_back("-analyzer-check-objc-mem");
CmdArgs.push_back("-analyzer-eagerly-assume");
- CmdArgs.push_back("-warn-objc-methodsigs");
+ CmdArgs.push_back("-analyzer-check-objc-methodsigs");
// Do not enable the missing -dealloc check.
- // '-warn-objc-missing-dealloc',
- CmdArgs.push_back("-warn-objc-unused-ivars");
+ // '-analyzer-check-objc-missing-dealloc',
+ CmdArgs.push_back("-analyzer-check-objc-unused-ivars");
}
// Set the output format. The default is plist, for (lame) historical
@@ -909,8 +913,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->render(Args, CmdArgs);
} else {
// Honor -std-default.
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
+ //
+ // FIXME: Clang doesn't correctly handle -std= when the input language
+ // doesn't match. For the time being just ignore this for C++ inputs;
+ // eventually we want to do all the standard defaulting here instead of
+ // splitting it between the driver and clang -cc1.
+ if (!types::isCXX(InputType))
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+ "-std=", /*Joined=*/true);
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
}
@@ -1004,6 +1014,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");
+ if (getToolChain().UseSjLjExceptions())
+ CmdArgs.push_back("-fsjlj-exceptions");
+
// -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
@@ -1013,6 +1026,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
isSignedCharDefault(getToolChain().getTriple())))
CmdArgs.push_back("-fno-signed-char");
+ // -fthreadsafe-static is default.
+ if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
+ options::OPT_fno_threadsafe_statics))
+ CmdArgs.push_back("-fno-threadsafe-statics");
+
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
@@ -1026,10 +1044,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fobjc-nonfragile-abi=0 is default.
if (types::isObjC(InputType)) {
if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) ||
- getToolChain().IsObjCNonFragileABIDefault())
+ getToolChain().IsObjCNonFragileABIDefault()) {
CmdArgs.push_back("-fobjc-nonfragile-abi");
+
+ // -fobjc-legacy-dispatch is only relevant with the nonfragile-abi, and
+ // defaults to off.
+ if (Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ getToolChain().IsObjCLegacyDispatchDefault()))
+ CmdArgs.push_back("-fobjc-legacy-dispatch");
+ }
}
+ if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
+ options::OPT_fno_assume_sane_operator_new))
+ CmdArgs.push_back("-fno-assume-sane-operator-new");
+
// -fshort-wchar default varies depending on platform; only
// pass if specified.
if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) {
@@ -1066,6 +1096,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_diagnostics_fixit_info))
CmdArgs.push_back("-fno-diagnostics-fixit-info");
+ Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_binary);
+
// Enable -fdiagnostics-show-option by default.
if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
options::OPT_fno_diagnostics_show_option))
@@ -1213,7 +1245,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- RenderExtraToolArgs(CmdArgs);
+ RenderExtraToolArgs(JA, CmdArgs);
// If using a driver driver, force the arch.
const std::string &Arch = getToolChain().getArchName();
@@ -1291,23 +1323,39 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
-void gcc::Preprocess::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
CmdArgs.push_back("-E");
}
-void gcc::Precompile::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Precompile::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
// The type is good enough.
}
-void gcc::Compile::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-S");
+void gcc::Compile::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+
+ // If -flto, etc. are present then make sure not to force assembly output.
+ if (JA.getType() == types::TY_LLVMBC)
+ CmdArgs.push_back("-c");
+ else {
+ if (JA.getType() != types::TY_PP_Asm)
+ D.Diag(clang::diag::err_drv_invalid_gcc_output_type)
+ << getTypeName(JA.getType());
+
+ CmdArgs.push_back("-S");
+ }
}
-void gcc::Assemble::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Assemble::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
CmdArgs.push_back("-c");
}
-void gcc::Link::RenderExtraToolArgs(ArgStringList &CmdArgs) const {
+void gcc::Link::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
// The types are (hopefully) good enough.
}
@@ -1703,6 +1751,10 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
else if (Output.getType() == types::TY_AST)
D.Diag(clang::diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
+ else if (JA.getType() != types::TY_PP_Asm &&
+ JA.getType() != types::TY_PCH)
+ D.Diag(clang::diag::err_drv_invalid_gcc_output_type)
+ << getTypeName(JA.getType());
ArgStringList OutputArgs;
if (Output.getType() != types::TY_PCH) {
@@ -1798,7 +1850,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// Derived from asm spec.
AddDarwinArch(Args, CmdArgs);
- if (!getDarwinToolChain().isIPhoneOS() ||
+ if (!getDarwinToolChain().isTargetIPhoneOS() ||
Args.hasArg(options::OPT_force__cpusubtype__ALL))
CmdArgs.push_back("-force_cpusubtype_ALL");
@@ -1921,7 +1973,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddLastArg(CmdArgs, options::OPT_all__load);
Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
- if (getDarwinToolChain().isIPhoneOS())
+ if (getDarwinToolChain().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);
@@ -1933,20 +1985,11 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_image__base);
Args.AddAllArgs(CmdArgs, options::OPT_init);
- if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ) &&
- !Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
- // Add default version min.
- if (!getDarwinToolChain().isIPhoneOS()) {
- CmdArgs.push_back("-macosx_version_min");
- CmdArgs.push_back(getDarwinToolChain().getMacosxVersionStr());
- } else {
- CmdArgs.push_back("-iphoneos_version_min");
- CmdArgs.push_back(getDarwinToolChain().getIPhoneOSVersionStr());
- }
- }
-
- // Adding all arguments doesn't make sense here but this is what
- // gcc does.
+ // 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,
@@ -1978,7 +2021,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot");
- if (getDarwinToolChain().isIPhoneOS()) {
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
if (!Args.hasArg(options::OPT_isysroot)) {
CmdArgs.push_back("-syslibroot");
CmdArgs.push_back("/Developer/SDKs/Extra");
@@ -2037,26 +2080,32 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
-
- unsigned MacosxVersionMin[3];
- getDarwinToolChain().getMacosxVersionMin(Args, MacosxVersionMin);
-
if (!Args.hasArg(options::OPT_A) &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
// Derived from startfile spec.
if (Args.hasArg(options::OPT_dynamiclib)) {
// Derived from darwin_dylib1 spec.
- if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5))
- CmdArgs.push_back("-ldylib1.o");
- else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6))
- CmdArgs.push_back("-ldylib1.10.5.o");
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-ldylib1.o");
+ } else {
+ if (getDarwinToolChain().isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-ldylib1.o");
+ else if (getDarwinToolChain().isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-ldylib1.10.5.o");
+ }
} else {
if (Args.hasArg(options::OPT_bundle)) {
if (!Args.hasArg(options::OPT_static)) {
// Derived from darwin_bundle1 spec.
- if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6))
- CmdArgs.push_back("-lbundle1.o");
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lbundle1.o");
+ } else {
+ if (getDarwinToolChain().isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lbundle1.o");
+ }
}
} else {
if (Args.hasArg(options::OPT_pg)) {
@@ -2076,26 +2125,29 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lcrt0.o");
} else {
// Derived from darwin_crt1 spec.
- if (getDarwinToolChain().isIPhoneOS()) {
- CmdArgs.push_back("-lcrt1.o");
- } else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin,
- 10, 5))
- CmdArgs.push_back("-lcrt1.o");
- else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin,
- 10, 6))
- CmdArgs.push_back("-lcrt1.10.5.o");
- else
- CmdArgs.push_back("-lcrt1.10.6.o");
-
- // darwin_crt2 spec is empty.
+ if (getDarwinToolChain().isTargetIPhoneOS()) {
+ if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lcrt1.o");
+ else
+ CmdArgs.push_back("-lcrt1.3.1.o");
+ } else {
+ if (getDarwinToolChain().isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-lcrt1.o");
+ else if (getDarwinToolChain().isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lcrt1.10.5.o");
+ else
+ CmdArgs.push_back("-lcrt1.10.6.o");
+
+ // darwin_crt2 spec is empty.
+ }
}
}
}
}
- if (Args.hasArg(options::OPT_shared_libgcc) &&
- !Args.hasArg(options::OPT_miphoneos_version_min_EQ) &&
- getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5)) {
+ if (!getDarwinToolChain().isTargetIPhoneOS() &&
+ Args.hasArg(options::OPT_shared_libgcc) &&
+ getDarwinToolChain().isMacosxVersionLT(10, 5)) {
const char *Str =
Args.MakeArgString(getToolChain().GetFilePath(C, "crt3.o"));
CmdArgs.push_back(Str);
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index abd8cfc6d42f..db596417a9d2 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -41,6 +41,7 @@ namespace tools {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasIntegratedAssembler() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
@@ -66,7 +67,8 @@ namespace gcc {
/// RenderExtraToolArgs - Render any arguments necessary to force
/// the particular tool mode.
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const = 0;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const = 0;
};
@@ -78,7 +80,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return true; }
virtual bool hasIntegratedCPP() const { return false; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Precompile : public Common {
@@ -89,7 +92,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return false; }
virtual bool hasIntegratedCPP() const { return true; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Compile : public Common {
@@ -100,7 +104,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Assemble : public Common {
@@ -111,7 +116,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return false; }
virtual bool hasIntegratedCPP() const { return false; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
class VISIBILITY_HIDDEN Link : public Common {
@@ -122,7 +128,8 @@ namespace gcc {
virtual bool canPipeOutput() const { return false; }
virtual bool hasIntegratedCPP() const { return false; }
- virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const;
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
};
} // end namespace gcc
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 33cb94e02dc3..ebbd720ceb63 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -564,7 +564,7 @@ public:
if (RD->isInvalidDecl())
continue;
- if (!RD->getDefinition(C))
+ if (!RD->getDefinition())
continue;
// FIXME: Do we really need to hard code this?
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
new file mode 100644
index 000000000000..2228ea45df33
--- /dev/null
+++ b/lib/Frontend/ASTMerge.cpp
@@ -0,0 +1,103 @@
+//===-- ASTMerge.cpp - AST Merging Frontent Action --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTImporter.h"
+
+using namespace clang;
+
+ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return AdaptedAction->CreateASTConsumer(CI, InFile);
+}
+
+bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
+ llvm::StringRef Filename) {
+ // FIXME: This is a hack. We need a better way to communicate the
+ // AST file, compiler instance, and file name than member variables
+ // of FrontendAction.
+ AdaptedAction->setCurrentFile(getCurrentFile(), takeCurrentASTUnit());
+ AdaptedAction->setCompilerInstance(&CI);
+ return AdaptedAction->BeginSourceFileAction(CI, Filename);
+}
+
+void ASTMergeAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ CI.getDiagnostics().getClient()->BeginSourceFile(
+ CI.getASTContext().getLangOptions());
+ CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ &CI.getASTContext());
+ for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
+ ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], CI.getDiagnostics(),
+ false);
+ if (!Unit)
+ continue;
+
+ ASTImporter Importer(CI.getDiagnostics(),
+ CI.getASTContext(),
+ CI.getFileManager(),
+ Unit->getASTContext(),
+ Unit->getFileManager());
+
+ TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
+ for (DeclContext::decl_iterator D = TU->decls_begin(),
+ DEnd = TU->decls_end();
+ D != DEnd; ++D) {
+ // Don't re-import __va_list_tag, __builtin_va_list.
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ if (IdentifierInfo *II = ND->getIdentifier())
+ if (II->isStr("__va_list_tag") || II->isStr("__builtin_va_list"))
+ continue;
+
+ Importer.Import(*D);
+ }
+
+ delete Unit;
+ }
+
+ AdaptedAction->ExecuteAction();
+ CI.getDiagnostics().getClient()->EndSourceFile();
+}
+
+void ASTMergeAction::EndSourceFileAction() {
+ return AdaptedAction->EndSourceFileAction();
+}
+
+ASTMergeAction::ASTMergeAction(FrontendAction *AdaptedAction,
+ std::string *ASTFiles, unsigned NumASTFiles)
+ : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles, ASTFiles + NumASTFiles) {
+ assert(AdaptedAction && "ASTMergeAction needs an action to adapt");
+}
+
+ASTMergeAction::~ASTMergeAction() {
+ delete AdaptedAction;
+}
+
+bool ASTMergeAction::usesPreprocessorOnly() const {
+ return AdaptedAction->usesPreprocessorOnly();
+}
+
+bool ASTMergeAction::usesCompleteTranslationUnit() {
+ return AdaptedAction->usesCompleteTranslationUnit();
+}
+
+bool ASTMergeAction::hasPCHSupport() const {
+ return AdaptedAction->hasPCHSupport();
+}
+
+bool ASTMergeAction::hasASTSupport() const {
+ return AdaptedAction->hasASTSupport();
+}
+
+bool ASTMergeAction::hasCodeCompletionSupport() const {
+ return AdaptedAction->hasCodeCompletionSupport();
+}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 2fb47cbd8a85..a0c4889c1631 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -98,13 +98,12 @@ const std::string &ASTUnit::getOriginalSourceFileName() {
const std::string &ASTUnit::getPCHFileName() {
assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
- return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName();
+ return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
}
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Diagnostic &Diags,
bool OnlyLocalDecls,
- bool UseBumpAllocator,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles) {
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
@@ -184,7 +183,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
PP.getIdentifierTable(),
PP.getSelectorTable(),
PP.getBuiltinInfo(),
- /* FreeMemory = */ !UseBumpAllocator,
+ /* FreeMemory = */ false,
/* size_reserve = */0));
ASTContext &Context = *AST->Ctx.get();
@@ -230,7 +229,7 @@ public:
}
-ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
+ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
Diagnostic &Diags,
bool OnlyLocalDecls) {
// Create the compiler instance to use for building the AST.
@@ -238,7 +237,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
llvm::OwningPtr<ASTUnit> AST;
llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
- Clang.getInvocation() = CI;
+ Clang.setInvocation(CI);
Clang.setDiagnostics(&Diags);
Clang.setDiagnosticClient(Diags.getClient());
@@ -294,7 +293,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
Clang.takeDiagnosticClient();
Clang.takeDiagnostics();
+ Clang.takeInvocation();
+ AST->Invocation.reset(Clang.takeInvocation());
return AST.take();
error:
@@ -310,7 +311,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
Diagnostic &Diags,
llvm::StringRef ResourceFilesPath,
bool OnlyLocalDecls,
- bool UseBumpAllocator,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles) {
llvm::SmallVector<const char *, 16> Args;
@@ -324,6 +324,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
"a.out", 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()));
@@ -345,19 +349,19 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
}
const driver::ArgStringList &CCArgs = Cmd->getArguments();
- CompilerInvocation CI;
- CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(),
+ llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
+ CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
(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);
+ CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
// Override the resources path.
- CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+ CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
- CI.getFrontendOpts().DisableFree = UseBumpAllocator;
- return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls);
+ CI->getFrontendOpts().DisableFree = true;
+ return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls);
}
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index 45a3b15caecc..d764fd078968 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -18,14 +18,15 @@
#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/Analysis/LocalCheckers.h"
-#include "clang/Analysis/ManagerRegistry.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Analysis/PathSensitive/AnalysisManager.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/Checkers/LocalCheckers.h"
+#include "clang/Checker/ManagerRegistry.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PathDiagnosticClients.h"
@@ -64,13 +65,17 @@ 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 TranslationUnitActions;
+ TUActions TranslationUnitActions;
public:
ASTContext* Ctx;
@@ -133,11 +138,11 @@ public:
}
}
}
-
+
void DisplayFunction(const Decl *D) {
if (!Opts.AnalyzerDisplayProgress || declDisplayed)
return;
-
+
declDisplayed = true;
SourceManager &SM = Mgr->getASTContext().getSourceManager();
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
@@ -162,7 +167,7 @@ public:
ObjCImplementationActions.push_back(action);
}
- void addTranslationUnitAction(CodeAction action) {
+ void addTranslationUnitAction(TUAction action) {
TranslationUnitActions.push_back(action);
}
@@ -191,7 +196,7 @@ public:
namespace llvm {
template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> {
- static inline void Profile(AnalysisConsumer::CodeAction X,
+ static inline void Profile(AnalysisConsumer::CodeAction X,
FoldingSetNodeID& ID) {
ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
}
@@ -204,42 +209,30 @@ namespace llvm {
void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
switch (D->getKind()) {
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::CXXMethod:
case Decl::Function: {
FunctionDecl* FD = cast<FunctionDecl>(D);
-
if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
- break;
+ FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
+ break;
- Stmt* Body = FD->getBody();
- if (Body) HandleCode(FD, Body, FunctionActions);
+ if (Stmt *Body = FD->getBody())
+ HandleCode(FD, Body, FunctionActions);
break;
}
case Decl::ObjCMethod: {
ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
- if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
return;
- Stmt* Body = MD->getBody();
- if (Body) HandleCode(MD, Body, ObjCMethodActions);
- break;
- }
-
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::CXXMethod: {
- CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D);
-
- if (Opts.AnalyzeSpecificFunction.size() > 0 &&
- Opts.AnalyzeSpecificFunction != CXXMD->getName())
- return;
-
- Stmt *Body = CXXMD->getBody();
- if (Body) HandleCode(CXXMD, Body, FunctionActions);
+ if (Stmt* Body = MD->getBody())
+ HandleCode(MD, Body, ObjCMethodActions);
break;
}
@@ -249,30 +242,12 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
}
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
-
+
TranslationUnitDecl *TU = C.getTranslationUnitDecl();
-
- if (!TranslationUnitActions.empty()) {
- // Find the entry function definition (if any).
- FunctionDecl *FD = 0;
- // Must specify an entry function.
- if (!Opts.AnalyzeSpecificFunction.empty()) {
- for (DeclContext::decl_iterator I=TU->decls_begin(), E=TU->decls_end();
- I != E; ++I) {
- if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I))
- if (fd->isThisDeclarationADefinition() &&
- fd->getNameAsString() == Opts.AnalyzeSpecificFunction) {
- FD = fd;
- break;
- }
- }
- }
- if (FD) {
- for (Actions::iterator I = TranslationUnitActions.begin(),
- E = TranslationUnitActions.end(); I != E; ++I)
- (*I)(*this, *Mgr, FD);
- }
+ for (TUActions::iterator I = TranslationUnitActions.begin(),
+ E = TranslationUnitActions.end(); I != E; ++I) {
+ (*I)(*this, *Mgr, *TU);
}
if (!ObjCImplementationActions.empty()) {
@@ -293,7 +268,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
WL.push_back(BD);
-
+
for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
I!=E; ++I)
if (DeclContext *DC = dyn_cast<DeclContext>(*I))
@@ -314,14 +289,14 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
// Clear the AnalysisManager of old AnalysisContexts.
Mgr->ClearContexts();
-
+
// Dispatch on the actions.
llvm::SmallVector<Decl*, 10> WL;
WL.push_back(D);
-
+
if (Body && Opts.AnalyzeNestedBlocks)
FindBlocks(cast<DeclContext>(D), WL);
-
+
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)
@@ -351,7 +326,7 @@ static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D,
+ Decl *D,
GRTransferFuncs* tf) {
llvm::OwningPtr<GRTransferFuncs> TF(tf);
@@ -363,18 +338,18 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
// information to see if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
if (!mgr.getLiveVariables(D))
- return;
-
+ return;
+
GRExprEngine Eng(mgr, TF.take());
-
+
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
-
+
RegisterAppleChecks(Eng, *D);
-
+
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
-
+
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
if (mgr.shouldVisualizeUbigraph()) {
@@ -397,7 +372,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
Eng.getBugReporter().FlushReports();
}
-static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr,
+static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D, bool GCEnabled) {
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
@@ -407,23 +382,23 @@ static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr,
ActionGRExprEngine(C, mgr, D, TF);
}
-static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr,
+static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
switch (mgr.getLangOptions().getGCMode()) {
default:
assert (false && "Invalid GC mode.");
case LangOptions::NonGC:
- ActionCheckerCFRefAux(C, mgr, D, false);
+ ActionObjCMemCheckerAux(C, mgr, D, false);
break;
case LangOptions::GCOnly:
- ActionCheckerCFRefAux(C, mgr, D, true);
+ ActionObjCMemCheckerAux(C, mgr, D, true);
break;
case LangOptions::HybridGC:
- ActionCheckerCFRefAux(C, mgr, D, false);
- ActionCheckerCFRefAux(C, mgr, D, true);
+ ActionObjCMemCheckerAux(C, mgr, D, false);
+ ActionObjCMemCheckerAux(C, mgr, D, true);
break;
}
}
@@ -457,6 +432,13 @@ static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
CheckSecuritySyntaxOnly(D, BR);
}
+static void ActionLLVMConventionChecker(AnalysisConsumer &C,
+ AnalysisManager &mgr,
+ TranslationUnitDecl &TU) {
+ BugReporter BR(mgr);
+ CheckLLVMConventions(TU, BR);
+}
+
static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
@@ -489,8 +471,29 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
}
static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
- Decl *D) {
- // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup.
+ TranslationUnitDecl &TU) {
+
+ // Find the entry function definition (if any).
+ FunctionDecl *D = 0;
+
+ // Must specify an entry function.
+ if (!C.Opts.AnalyzeSpecificFunction.empty()) {
+ for (DeclContext::decl_iterator I=TU.decls_begin(), E=TU.decls_end();
+ I != E; ++I) {
+ if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I))
+ if (fd->isThisDeclarationADefinition() &&
+ fd->getNameAsString() == C.Opts.AnalyzeSpecificFunction) {
+ D = fd;
+ break;
+ }
+ }
+ }
+
+ if (!D)
+ return;
+
+
+ // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup.
// Display progress.
C.DisplayFunction(D);
@@ -500,9 +503,9 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
-
+
RegisterAppleChecks(Eng, *D);
-
+
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index 9be6786b5f75..f5291a9525e7 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -17,7 +17,6 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Module.h"
-#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/PrintModulePass.h"
@@ -56,7 +55,6 @@ namespace {
llvm::Module *TheModule;
llvm::TargetData *TheTargetData;
- mutable llvm::ModuleProvider *ModuleProvider;
mutable FunctionPassManager *CodeGenPasses;
mutable PassManager *PerModulePasses;
mutable FunctionPassManager *PerFunctionPasses;
@@ -89,7 +87,7 @@ namespace {
LLVMIRGeneration("LLVM IR Generation Time"),
CodeGenerationTime("Code Generation Time"),
Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
- TheModule(0), TheTargetData(0), ModuleProvider(0),
+ TheModule(0), TheTargetData(0),
CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {
if (AsmOutStream)
@@ -101,7 +99,7 @@ namespace {
~BackendConsumer() {
delete TheTargetData;
- delete ModuleProvider;
+ delete TheModule;
delete CodeGenPasses;
delete PerModulePasses;
delete PerFunctionPasses;
@@ -116,7 +114,6 @@ namespace {
Gen->Initialize(Ctx);
TheModule = Gen->GetModule();
- ModuleProvider = new ExistingModuleProvider(TheModule);
TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
if (llvm::TimePassesIsEnabled)
@@ -172,7 +169,7 @@ namespace {
FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
if (!CodeGenPasses) {
- CodeGenPasses = new FunctionPassManager(ModuleProvider);
+ CodeGenPasses = new FunctionPassManager(TheModule);
CodeGenPasses->add(new TargetData(*TheTargetData));
}
@@ -190,7 +187,7 @@ PassManager *BackendConsumer::getPerModulePasses() const {
FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
if (!PerFunctionPasses) {
- PerFunctionPasses = new FunctionPassManager(ModuleProvider);
+ PerFunctionPasses = new FunctionPassManager(TheModule);
PerFunctionPasses->add(new TargetData(*TheTargetData));
}
@@ -306,20 +303,12 @@ bool BackendConsumer::AddEmitPasses() {
case 3: OptLevel = CodeGenOpt::Aggressive; break;
}
- // Normal mode, emit a .s file by running the code generator.
- // Note, this also adds codegenerator level optimization passes.
- switch (TM->addPassesToEmitFile(*PM, FormattedOutStream,
- TargetMachine::AssemblyFile, OptLevel)) {
- default:
- case FileModel::Error:
- Diags.Report(diag::err_fe_unable_to_interface_with_target);
- return false;
- case FileModel::AsmFile:
- break;
- }
-
- if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
- OptLevel)) {
+ // Normal mode, emit a .s or .o file by running the code generator. Note,
+ // this also adds codegenerator level optimization passes.
+ TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
+ if (Action == Backend_EmitObj)
+ CGFT = TargetMachine::CGFT_ObjectFile;
+ if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel)) {
Diags.Report(diag::err_fe_unable_to_interface_with_target);
return false;
}
@@ -354,11 +343,11 @@ void BackendConsumer::CreatePasses() {
// Set the inline threshold following llvm-gcc.
//
// FIXME: Derive these constants in a principled fashion.
- unsigned Threshold = 200;
+ unsigned Threshold = 225;
if (CodeGenOpts.OptimizeSize)
- Threshold = 50;
+ Threshold = 75;
else if (OptLevel > 2)
- Threshold = 250;
+ Threshold = 275;
InliningPass = createFunctionInliningPass(Threshold);
break;
}
@@ -392,7 +381,6 @@ void BackendConsumer::EmitAssembly() {
if (!M) {
// The module has been released by IR gen on failures, do not
// double free.
- ModuleProvider->releaseModule();
TheModule = 0;
return;
}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 58aaa43aab8f..1d0b5c12041a 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangFrontend
ASTConsumers.cpp
+ ASTMerge.cpp
ASTUnit.cpp
AnalysisConsumer.cpp
Backend.cpp
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 19c740d17a83..917cbd711ad3 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -35,15 +35,19 @@
#include "llvm/System/Program.h"
using namespace clang;
-CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
- bool _OwnsLLVMContext)
- : LLVMContext(_LLVMContext),
- OwnsLLVMContext(_OwnsLLVMContext) {
- }
+CompilerInstance::CompilerInstance()
+ : Invocation(new CompilerInvocation()) {
+}
CompilerInstance::~CompilerInstance() {
- if (OwnsLLVMContext)
- delete LLVMContext;
+}
+
+void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) {
+ LLVMContext.reset(Value);
+}
+
+void CompilerInstance::setInvocation(CompilerInvocation *Value) {
+ Invocation.reset(Value);
}
void CompilerInstance::setDiagnostics(Diagnostic *Value) {
@@ -83,6 +87,23 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
}
// Diagnostics
+namespace {
+ class BinaryDiagnosticSerializer : public DiagnosticClient {
+ llvm::raw_ostream &OS;
+ SourceManager *SourceMgr;
+ public:
+ explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS)
+ : OS(OS), SourceMgr(0) { }
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+ };
+}
+
+void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ Info.Serialize(DiagLevel, OS);
+}
static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
unsigned argc, char **argv,
@@ -122,8 +143,23 @@ Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
// Create the diagnostic client for reporting errors or for
// implementing -verify.
- llvm::OwningPtr<DiagnosticClient> DiagClient(
- new TextDiagnosticPrinter(llvm::errs(), Opts));
+ llvm::OwningPtr<DiagnosticClient> DiagClient;
+ if (Opts.BinaryOutput) {
+ if (llvm::sys::Program::ChangeStderrToBinary()) {
+ // We weren't able to set standard error to binary, which is a
+ // bit of a problem. So, just create a text diagnostic printer
+ // to complain about this problem, and pretend that the user
+ // didn't try to use binary output.
+ DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+ Diags->setClient(DiagClient.take());
+ Diags->Report(diag::err_fe_stderr_binary);
+ return Diags.take();
+ } else {
+ DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs()));
+ }
+ } else {
+ DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+ }
// Chain in -verify checker, if requested.
if (Opts.VerifyDiagnostics)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 0bca4754ec11..a193ac870307 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -170,6 +170,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
}
if (Opts.NoZeroInitializedInBSS)
Res.push_back("-mno-zero-initialized-bss");
+ if (Opts.ObjCLegacyDispatch)
+ Res.push_back("-fobjc-legacy-dispatch");
if (Opts.SoftFloat)
Res.push_back("-msoft-float");
if (Opts.UnwindTables)
@@ -178,6 +180,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-mrelocation-model");
Res.push_back(Opts.RelocationModel);
}
+ if (!Opts.VerifyModule)
+ Res.push_back("-disable-llvm-verifier");
}
static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
@@ -220,6 +224,8 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fcolor-diagnostics");
if (Opts.VerifyDiagnostics)
Res.push_back("-verify");
+ if (Opts.BinaryOutput)
+ Res.push_back("-fdiagnostics-binary");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
@@ -276,6 +282,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::EmitHTML: return "-emit-html";
case frontend::EmitLLVM: return "-emit-llvm";
case frontend::EmitLLVMOnly: return "-emit-llvm-only";
+ case frontend::EmitObj: return "-emit-obj";
case frontend::FixIt: return "-fixit";
case frontend::GeneratePCH: return "-emit-pch";
case frontend::GeneratePTH: return "-emit-pth";
@@ -362,6 +369,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-load");
Res.push_back(Opts.Plugins[i]);
}
+ for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) {
+ Res.push_back("-ast-merge");
+ Res.push_back(Opts.ASTMergeFiles[i]);
+ }
}
static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
@@ -450,6 +461,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fms-extensions");
if (Opts.ObjCNonFragileABI)
Res.push_back("-fobjc-nonfragile-abi");
+ if (Opts.ObjCNonFragileABI2)
+ Res.push_back("-fobjc-nonfragile-abi2");
// NoInline is implicit.
if (!Opts.CXXOperatorNames)
Res.push_back("-fno-operator-names");
@@ -465,6 +478,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-faltivec");
if (Opts.Exceptions)
Res.push_back("-fexceptions");
+ if (Opts.SjLjExceptions)
+ Res.push_back("-fsjlj-exceptions");
if (!Opts.RTTI)
Res.push_back("-fno-rtti");
if (!Opts.NeXTRuntime)
@@ -475,8 +490,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fno-builtin");
if (!Opts.AssumeSaneOperatorNew)
Res.push_back("-fno-assume-sane-operator-new");
- if (Opts.ThreadsafeStatics)
- llvm::llvm_report_error("FIXME: Not yet implemented!");
+ if (!Opts.ThreadsafeStatics)
+ Res.push_back("-fno-threadsafe-statics");
if (Opts.POSIXThreads)
Res.push_back("-pthread");
if (Opts.Blocks)
@@ -770,18 +785,13 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi);
Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision);
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
+ Opts.ObjCLegacyDispatch = Args.hasArg(OPT_fobjc_legacy_dispatch);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic");
Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
-
- // FIXME: Put elsewhere?
-#ifdef NDEBUG
- Opts.VerifyModule = 0;
-#else
- Opts.VerifyModule = 1;
-#endif
+ Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
}
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
@@ -808,6 +818,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+ Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -852,6 +863,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::EmitLLVM; break;
case OPT_emit_llvm_only:
Opts.ProgramAction = frontend::EmitLLVMOnly; break;
+ case OPT_emit_obj:
+ Opts.ProgramAction = frontend::EmitObj; break;
case OPT_fixit:
Opts.ProgramAction = frontend::FixIt; break;
case OPT_emit_pch:
@@ -920,6 +933,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
+ Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge);
FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
@@ -1146,7 +1160,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
if (Args.hasArg(OPT_fno_lax_vector_conversions))
- Opts.LaxVectorConversions = 0;
+ Opts.LaxVectorConversions = 0;
+ if (Args.hasArg(OPT_fno_threadsafe_statics))
+ Opts.ThreadsafeStatics = 0;
Opts.Exceptions = Args.hasArg(OPT_fexceptions);
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
@@ -1165,10 +1181,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.ObjCConstantStringClass = getLastArgValue(Args,
OPT_fconstant_string_class);
Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
+ Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2);
+ if (Opts.ObjCNonFragileABI2)
+ Opts.ObjCNonFragileABI = true;
Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
+ Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions);
Opts.Static = Args.hasArg(OPT_static_define);
+ Opts.DumpVtableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
Opts.OptimizeSize = 0;
// FIXME: Eliminate this dependency.
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 0baba3f4673a..1c958a7087a9 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -177,6 +177,9 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
break;
case Backend_EmitNothing:
break;
+ case Backend_EmitObj:
+ OS.reset(CI.createDefaultOutputFile(true, InFile, "o"));
+ break;
}
if (BA != Backend_EmitNothing && !OS)
return 0;
@@ -196,6 +199,8 @@ EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {}
EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {}
+EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {}
+
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index b163e267b049..f695254cb466 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PathDiagnosticClients.h"
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 6102760aef53..2e0b4bdbfce3 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -483,10 +483,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddPath("/usr/include/c++/4.1", System, true, false, false);
break;
case llvm::Triple::Linux:
- // Exherbo (2009-10-26)
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ // Exherbo (2010-01-25)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
"x86_64-pc-linux-gnu", "32", "", triple);
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
"i686-pc-linux-gnu", "", "", triple);
// Debian sid
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
@@ -522,6 +522,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
"i686-redhat-linux","", "", triple);
+ // Fedora 12 (February-2010+)
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "i686-redhat-linux","", "", triple);
+
// openSUSE 11.1 32 bit
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
"i586-suse-linux", "", "", triple);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 9aaf1320346f..b7ab3d8cd452 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -279,6 +279,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.Exceptions)
Builder.defineMacro("__EXCEPTIONS");
+ if (LangOpts.SjLjExceptions)
+ Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
if (LangOpts.CPlusPlus) {
Builder.defineMacro("__DEPRECATED");
diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile
index 8d708475783f..a630b0133632 100644
--- a/lib/Frontend/Makefile
+++ b/lib/Frontend/Makefile
@@ -10,7 +10,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangFrontend
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 259355145aa3..a878df784005 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -72,12 +72,14 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c);
PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2);
PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi);
+ PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2);
PARSE_LANGOPT_BENIGN(PascalStrings);
PARSE_LANGOPT_BENIGN(WritableStrings);
PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
diag::warn_pch_lax_vector_conversions);
PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec);
PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions);
+ PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions);
PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime);
PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding);
PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins);
@@ -434,7 +436,9 @@ public:
continue;
}
- Prev->Next = new ObjCMethodList(Method, 0);
+ ObjCMethodList *Mem =
+ Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
+ Prev->Next = new (Mem) ObjCMethodList(Method, 0);
Prev = Prev->Next;
}
@@ -450,7 +454,9 @@ public:
continue;
}
- Prev->Next = new ObjCMethodList(Method, 0);
+ ObjCMethodList *Mem =
+ Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
+ Prev->Next = new (Mem) ObjCMethodList(Method, 0);
Prev = Prev->Next;
}
@@ -1326,6 +1332,14 @@ PCHReader::ReadPCHBlock() {
TentativeDefinitions.swap(Record);
break;
+ case pch::UNUSED_STATIC_FUNCS:
+ if (!UnusedStaticFuncs.empty()) {
+ Error("duplicate UNUSED_STATIC_FUNCS record in PCH file");
+ return Failure;
+ }
+ UnusedStaticFuncs.swap(Record);
+ break;
+
case pch::LOCALLY_SCOPED_EXTERNAL_DECLS:
if (!LocallyScopedExternalDecls.empty()) {
Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file");
@@ -1400,9 +1414,9 @@ PCHReader::ReadPCHBlock() {
break;
case pch::VERSION_CONTROL_BRANCH_REVISION: {
- llvm::StringRef CurBranch = getClangFullRepositoryVersion();
+ const std::string &CurBranch = getClangFullRepositoryVersion();
llvm::StringRef PCHBranch(BlobStart, BlobLen);
- if (CurBranch != PCHBranch) {
+ if (llvm::StringRef(CurBranch) != PCHBranch) {
Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch;
return IgnorePCH;
}
@@ -1740,11 +1754,13 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(ObjC1);
PARSE_LANGOPT(ObjC2);
PARSE_LANGOPT(ObjCNonFragileABI);
+ PARSE_LANGOPT(ObjCNonFragileABI2);
PARSE_LANGOPT(PascalStrings);
PARSE_LANGOPT(WritableStrings);
PARSE_LANGOPT(LaxVectorConversions);
PARSE_LANGOPT(AltiVec);
PARSE_LANGOPT(Exceptions);
+ PARSE_LANGOPT(SjLjExceptions);
PARSE_LANGOPT(NeXTRuntime);
PARSE_LANGOPT(Freestanding);
PARSE_LANGOPT(NoBuiltin);
@@ -1880,18 +1896,20 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
}
case pch::TYPE_VECTOR: {
- if (Record.size() != 2) {
+ if (Record.size() != 4) {
Error("incorrect encoding of vector type in PCH file");
return QualType();
}
QualType ElementType = GetType(Record[0]);
unsigned NumElements = Record[1];
- return Context->getVectorType(ElementType, NumElements);
+ bool AltiVec = Record[2];
+ bool Pixel = Record[3];
+ return Context->getVectorType(ElementType, NumElements, AltiVec, Pixel);
}
case pch::TYPE_EXT_VECTOR: {
- if (Record.size() != 2) {
+ if (Record.size() != 4) {
Error("incorrect encoding of extended vector type in PCH file");
return QualType();
}
@@ -2464,11 +2482,17 @@ void PCHReader::InitializeSema(Sema &S) {
PreloadedDecls.clear();
// If there were any tentative definitions, deserialize them and add
- // them to Sema's table of tentative definitions.
+ // them to Sema's list of tentative definitions.
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
- SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
- SemaObj->TentativeDefinitionList.push_back(Var->getDeclName());
+ SemaObj->TentativeDefinitions.push_back(Var);
+ }
+
+ // If there were any unused static functions, deserialize them and add to
+ // Sema's list of unused static functions.
+ for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) {
+ FunctionDecl *FD = cast<FunctionDecl>(GetDecl(UnusedStaticFuncs[I]));
+ SemaObj->UnusedStaticFuncs.push_back(FD);
}
// If there were any locally-scoped external declarations,
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 4dc1318a3ee8..625997cac232 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -117,6 +117,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++])));
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
TD->setDefinition(Record[Idx++]);
+ TD->setEmbeddedInDeclarator(Record[Idx++]);
TD->setTypedefForAnonDecl(
cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -179,7 +180,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- FD->setParams(*Reader.getContext(), Params.data(), NumParams);
+ FD->setParams(Params.data(), NumParams);
}
void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
@@ -387,7 +388,7 @@ void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
VD->setPreviousDeclaration(
cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
if (Record[Idx++])
- VD->setInit(*Reader.getContext(), Reader.ReadDeclExpr());
+ VD->setInit(Reader.ReadDeclExpr());
}
void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
@@ -412,7 +413,7 @@ void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) {
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- BD->setParams(*Reader.getContext(), Params.data(), NumParams);
+ BD->setParams(Params.data(), NumParams);
}
std::pair<uint64_t, uint64_t>
@@ -445,7 +446,7 @@ Attr *PCHReader::ReadAttributes() {
#define STRING_ATTR(Name) \
case Attr::Name: \
- New = ::new (*Context) Name##Attr(ReadString(Record, Idx)); \
+ New = ::new (*Context) Name##Attr(*Context, ReadString(Record, Idx)); \
break
#define UNSIGNED_ATTR(Name) \
@@ -496,7 +497,7 @@ Attr *PCHReader::ReadAttributes() {
std::string Type = ReadString(Record, Idx);
unsigned FormatIdx = Record[Idx++];
unsigned FirstArg = Record[Idx++];
- New = ::new (*Context) FormatAttr(Type, FormatIdx, FirstArg);
+ New = ::new (*Context) FormatAttr(*Context, Type, FormatIdx, FirstArg);
break;
}
@@ -531,7 +532,7 @@ Attr *PCHReader::ReadAttributes() {
llvm::SmallVector<unsigned, 16> ArgNums;
ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size);
Idx += Size;
- New = ::new (*Context) NonNullAttr(ArgNums.data(), Size);
+ New = ::new (*Context) NonNullAttr(*Context, ArgNums.data(), Size);
break;
}
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 21c9cbf17cd7..d123694d699d 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -123,6 +123,8 @@ namespace {
unsigned VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
unsigned VisitCXXConstCastExpr(CXXConstCastExpr *E);
unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
+ unsigned VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+ unsigned VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
};
}
@@ -317,22 +319,24 @@ unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setAsmString(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
// Outputs and inputs
- llvm::SmallVector<std::string, 16> Names;
+ llvm::SmallVector<IdentifierInfo *, 16> Names;
llvm::SmallVector<StringLiteral*, 16> Constraints;
llvm::SmallVector<Stmt*, 16> Exprs;
for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) {
- Names.push_back(Reader.ReadString(Record, Idx));
+ Names.push_back(Reader.GetIdentifierInfo(Record, Idx));
Constraints.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
Exprs.push_back(StmtStack[StackIdx++]);
}
- S->setOutputsAndInputs(NumOutputs, NumInputs,
- Names.data(), Constraints.data(), Exprs.data());
// Constraints
llvm::SmallVector<StringLiteral*, 16> Clobbers;
for (unsigned I = 0; I != NumClobbers; ++I)
Clobbers.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
- S->setClobbers(Clobbers.data(), NumClobbers);
+
+ S->setOutputsAndInputsAndClobbers(*Reader.getContext(),
+ Names.data(), Constraints.data(),
+ Exprs.data(), NumOutputs, NumInputs,
+ Clobbers.data(), NumClobbers);
assert(StackIdx == StmtStack.size() && "Error deserializing AsmStmt");
return NumOutputs*2 + NumInputs*2 + NumClobbers + 1;
@@ -904,6 +908,19 @@ unsigned PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
return num;
}
+unsigned PCHStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
+unsigned PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 0;
+}
+
// Within the bitstream, expressions are stored in Reverse Polish
// Notation, with each of the subexpressions preceding the
// expression they are stored in. To evaluate expressions, we
@@ -1233,7 +1250,13 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) CXXFunctionalCastExpr(Empty);
break;
+ case pch::EXPR_CXX_BOOL_LITERAL:
+ S = new (Context) CXXBoolLiteralExpr(Empty);
+ break;
+ case pch::EXPR_CXX_NULL_PTR_LITERAL:
+ S = new (Context) CXXNullPtrLiteralExpr(Empty);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 9909c95847ee..4c99dbe24504 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -128,6 +128,8 @@ void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
void PCHTypeWriter::VisitVectorType(const VectorType *T) {
Writer.AddTypeRef(T->getElementType(), Record);
Record.push_back(T->getNumElements());
+ Record.push_back(T->isAltiVec());
+ Record.push_back(T->isPixel());
Code = pch::TYPE_VECTOR;
}
@@ -511,6 +513,15 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(STMT_OBJC_AT_TRY);
RECORD(STMT_OBJC_AT_SYNCHRONIZED);
RECORD(STMT_OBJC_AT_THROW);
+ RECORD(EXPR_CXX_OPERATOR_CALL);
+ RECORD(EXPR_CXX_CONSTRUCT);
+ RECORD(EXPR_CXX_STATIC_CAST);
+ RECORD(EXPR_CXX_DYNAMIC_CAST);
+ RECORD(EXPR_CXX_REINTERPRET_CAST);
+ RECORD(EXPR_CXX_CONST_CAST);
+ RECORD(EXPR_CXX_FUNCTIONAL_CAST);
+ RECORD(EXPR_CXX_BOOL_LITERAL);
+ RECORD(EXPR_CXX_NULL_PTR_LITERAL);
#undef RECORD
}
@@ -534,6 +545,7 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(SPECIAL_TYPES);
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
+ RECORD(UNUSED_STATIC_FUNCS);
RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
RECORD(SELECTOR_OFFSETS);
RECORD(METHOD_POOL);
@@ -737,13 +749,17 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled.
Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled.
- Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C modern abi enabled
+ Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C
+ // modern abi enabled.
+ Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
+ // modern abi enabled.
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
Record.push_back(LangOpts.LaxVectorConversions);
Record.push_back(LangOpts.AltiVec);
Record.push_back(LangOpts.Exceptions); // Support exception handling.
+ Record.push_back(LangOpts.SjLjExceptions);
Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime.
Record.push_back(LangOpts.Freestanding); // Freestanding implementation
@@ -1960,15 +1976,18 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
}
// Build a record containing all of the tentative definitions in this file, in
- // TentativeDefinitionList order. Generally, this record will be empty for
+ // TentativeDefinitions order. Generally, this record will be empty for
// headers.
RecordData TentativeDefinitions;
- for (unsigned i = 0, e = SemaRef.TentativeDefinitionList.size(); i != e; ++i){
- VarDecl *VD =
- SemaRef.TentativeDefinitions.lookup(SemaRef.TentativeDefinitionList[i]);
- if (VD) AddDeclRef(VD, TentativeDefinitions);
+ for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) {
+ AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions);
}
+ // Build a record containing all of the static unused functions in this file.
+ RecordData UnusedStaticFuncs;
+ for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i)
+ AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs);
+
// Build a record containing all of the locally-scoped external
// declarations in this header file. Generally, this record will be
// empty.
@@ -2070,6 +2089,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
if (!TentativeDefinitions.empty())
Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions);
+ // Write the record containing unused static functions.
+ if (!UnusedStaticFuncs.empty())
+ Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs);
+
// Write the record containing locally-scoped external definitions.
if (!LocallyScopedExternalDecls.empty())
Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS,
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 020f69b3e669..d105382b4354 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -115,6 +115,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
Record.push_back(D->isDefinition());
+ Record.push_back(D->isEmbeddedInDeclarator());
Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
Writer.AddSourceLocation(D->getTagKeywordLoc(), Record);
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index fdfdfefe08ef..a8cc9d6f4591 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -118,6 +118,8 @@ namespace {
void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
void VisitCXXConstCastExpr(CXXConstCastExpr *E);
void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E);
+ void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
};
}
@@ -287,15 +289,15 @@ void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) {
Writer.WriteSubStmt(S->getAsmString());
// Outputs
- for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
- Writer.AddString(S->getOutputName(I), Record);
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ Writer.AddIdentifierRef(S->getOutputIdentifier(I), Record);
Writer.WriteSubStmt(S->getOutputConstraintLiteral(I));
Writer.WriteSubStmt(S->getOutputExpr(I));
}
// Inputs
for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
- Writer.AddString(S->getInputName(I), Record);
+ Writer.AddIdentifierRef(S->getInputIdentifier(I), Record);
Writer.WriteSubStmt(S->getInputConstraintLiteral(I));
Writer.WriteSubStmt(S->getInputExpr(I));
}
@@ -834,6 +836,19 @@ void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
Code = pch::EXPR_CXX_FUNCTIONAL_CAST;
}
+void PCHStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_CXX_BOOL_LITERAL;
+}
+
+void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = pch::EXPR_CXX_NULL_PTR_LITERAL;
+}
+
//===----------------------------------------------------------------------===//
// PCHWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
index 98be869d2646..5706a07e5a0f 100644
--- a/lib/Frontend/PlistDiagnostics.cpp
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/PathDiagnosticClients.h"
-#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/Preprocessor.h"
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index a91dd8d55e92..8d64a6413304 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -391,7 +391,7 @@ namespace {
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
- std::string *Names,
+ IdentifierInfo **Names,
MultiExprArg Constraints,
MultiExprArg Exprs,
ExprArg AsmString,
@@ -684,7 +684,8 @@ namespace {
virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
IdentifierInfo *Ident,
- SourceLocation LBrace) {
+ SourceLocation LBrace,
+ AttributeList *AttrList) {
Out << __FUNCTION__ << "\n";
return DeclPtrTy();
}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 35d8dde8eaab..9dade66d4ab4 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -124,8 +124,10 @@ namespace {
llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
// Block related declarations.
- llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
- llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallVector<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
+ llvm::SmallVector<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet;
llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
@@ -212,11 +214,10 @@ namespace {
<< Old->getSourceRange();
}
- void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen,
+ void InsertText(SourceLocation Loc, llvm::StringRef Str,
bool InsertAfter = true) {
// If insertion succeeded or warning disabled return with no warning.
- if (!Rewrite.InsertText(Loc, llvm::StringRef(StrData, StrLen),
- InsertAfter) ||
+ if (!Rewrite.InsertText(Loc, Str, InsertAfter) ||
SilenceRewriteMacroWarning)
return;
@@ -232,10 +233,9 @@ namespace {
}
void ReplaceText(SourceLocation Start, unsigned OrigLength,
- const char *NewStr, unsigned NewLength) {
+ llvm::StringRef Str) {
// If removal succeeded or warning disabled return with no warning.
- if (!Rewrite.ReplaceText(Start, OrigLength,
- llvm::StringRef(NewStr, NewLength)) ||
+ if (!Rewrite.ReplaceText(Start, OrigLength, Str) ||
SilenceRewriteMacroWarning)
return;
@@ -263,6 +263,7 @@ namespace {
void RewriteFunctionDecl(FunctionDecl *FD);
void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD);
void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
+ void RewriteTypeOfDecl(VarDecl *VD);
void RewriteObjCQualifiedInterfaceTypes(Expr *E);
bool needToScanForQualifiers(QualType T);
ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
@@ -278,7 +279,9 @@ namespace {
ParentMap *PropParentMap; // created lazily.
Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
- Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart);
+ Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart,
+ bool &replaced);
+ Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced);
Stmt *RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr);
Stmt *RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
SourceRange SrcRange);
@@ -632,6 +635,9 @@ void RewriteObjC::Initialize(ASTContext &context) {
//===----------------------------------------------------------------------===//
void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
+ if (Diags.hasErrorOccurred())
+ return;
+
// Two cases: either the decl could be in the main file, or it could be in a
// #included file. If the former, rewrite it now. If the later, check to see
// if we rewrote the #include/#import.
@@ -681,7 +687,6 @@ void RewriteObjC::RewriteInclude() {
const char *MainBufStart = MainBuf.first;
const char *MainBufEnd = MainBuf.second;
size_t ImportLen = strlen("import");
- size_t IncludeLen = strlen("include");
// Loop over the whole file, looking for includes.
for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
@@ -695,7 +700,7 @@ void RewriteObjC::RewriteInclude() {
// replace import with include
SourceLocation ImportLoc =
LocStart.getFileLocWithOffset(BufPtr-MainBufStart);
- ReplaceText(ImportLoc, ImportLen, "include", IncludeLen);
+ ReplaceText(ImportLoc, ImportLen, "include");
BufPtr += ImportLen;
}
}
@@ -728,7 +733,7 @@ void RewriteObjC::RewriteTabs() {
TabLoc = TabLoc.getFileLocWithOffset(BufPtr-MainBufStart);
// Rewrite the single tab character into a sequence of spaces.
- ReplaceText(TabLoc, 1, " ", Spaces);
+ ReplaceText(TabLoc, 1, llvm::StringRef(" ", Spaces));
}
}
@@ -746,7 +751,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
ObjCImplementationDecl *IMD,
ObjCCategoryImplDecl *CID) {
SourceLocation startLoc = PID->getLocStart();
- InsertText(startLoc, "// ", 3);
+ InsertText(startLoc, "// ");
const char *startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @synthesize location");
const char *semiBuf = strchr(startBuf, ';');
@@ -774,7 +779,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// See objc-act.c:objc_synthesize_new_getter() for details.
Getr += "return " + getIvarAccessString(ClassDecl, OID);
Getr += "; }";
- InsertText(onePastSemiLoc, Getr.c_str(), Getr.size());
+ InsertText(onePastSemiLoc, Getr);
if (PD->isReadOnly())
return;
@@ -789,7 +794,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
Setr += getIvarAccessString(ClassDecl, OID) + " = ";
Setr += PD->getNameAsCString();
Setr += "; }";
- InsertText(onePastSemiLoc, Setr.c_str(), Setr.size());
+ InsertText(onePastSemiLoc, Setr);
}
void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
@@ -828,8 +833,7 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
}
// Replace the @class with typedefs corresponding to the classes.
- ReplaceText(startLoc, semiPtr-startBuf+1,
- typedefString.c_str(), typedefString.size());
+ ReplaceText(startLoc, semiPtr-startBuf+1, typedefString);
}
void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
@@ -842,17 +846,17 @@ void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
if (SM->getInstantiationLineNumber(LocEnd) >
SM->getInstantiationLineNumber(LocStart)) {
- InsertText(LocStart, "#if 0\n", 6);
- ReplaceText(LocEnd, 1, ";\n#endif\n", 9);
+ InsertText(LocStart, "#if 0\n");
+ ReplaceText(LocEnd, 1, ";\n#endif\n");
} else {
- InsertText(LocStart, "// ", 3);
+ InsertText(LocStart, "// ");
}
}
void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) {
SourceLocation Loc = prop->getAtLoc();
- ReplaceText(Loc, 0, "// ", 3);
+ ReplaceText(Loc, 0, "// ");
// FIXME: handle properties that are declared across multiple lines.
}
@@ -860,8 +864,12 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
SourceLocation LocStart = CatDecl->getLocStart();
// FIXME: handle category headers that are declared across multiple lines.
- ReplaceText(LocStart, 0, "// ", 3);
+ ReplaceText(LocStart, 0, "// ");
+ for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(),
+ E = CatDecl->prop_end(); I != E; ++I)
+ RewriteProperty(*I);
+
for (ObjCCategoryDecl::instmeth_iterator
I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
I != E; ++I)
@@ -872,7 +880,7 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ", 3);
+ ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ");
}
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
@@ -881,7 +889,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
SourceLocation LocStart = PDecl->getLocStart();
// FIXME: handle protocol headers that are declared across multiple lines.
- ReplaceText(LocStart, 0, "// ", 3);
+ ReplaceText(LocStart, 0, "// ");
for (ObjCProtocolDecl::instmeth_iterator
I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
@@ -894,24 +902,20 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
// Lastly, comment out the @end.
SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
- ReplaceText(LocEnd, 0, "// ", 3);
+ ReplaceText(LocEnd, 0, "// ");
// Must comment out @optional/@required
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
for (const char *p = startBuf; p < endBuf; p++) {
if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
- std::string CommentedOptional = "/* @optional */";
SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
- ReplaceText(OptionalLoc, strlen("@optional"),
- CommentedOptional.c_str(), CommentedOptional.size());
+ ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */");
}
else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
- std::string CommentedRequired = "/* @required */";
SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
- ReplaceText(OptionalLoc, strlen("@required"),
- CommentedRequired.c_str(), CommentedRequired.size());
+ ReplaceText(OptionalLoc, strlen("@required"), "/* @required */");
}
}
@@ -922,7 +926,7 @@ void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
if (LocStart.isInvalid())
assert(false && "Invalid SourceLocation");
// FIXME: handle forward protocol that are declared across multiple lines.
- ReplaceText(LocStart, 0, "// ", 3);
+ ReplaceText(LocStart, 0, "// ");
}
void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
@@ -1050,10 +1054,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
- if (IMD)
- InsertText(IMD->getLocStart(), "// ", 3);
- else
- InsertText(CID->getLocStart(), "// ", 3);
+ InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// ");
for (ObjCCategoryImplDecl::instmeth_iterator
I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
@@ -1067,8 +1068,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
- ReplaceText(LocStart, endBuf-startBuf,
- ResultStr.c_str(), ResultStr.size());
+ ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
for (ObjCCategoryImplDecl::classmeth_iterator
@@ -1083,8 +1083,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
- ReplaceText(LocStart, endBuf-startBuf,
- ResultStr.c_str(), ResultStr.size());
+ ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
for (ObjCCategoryImplDecl::propimpl_iterator
I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(),
@@ -1093,10 +1092,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
RewritePropertyImplDecl(*I, IMD, CID);
}
- if (IMD)
- InsertText(IMD->getLocEnd(), "// ", 3);
- else
- InsertText(CID->getLocEnd(), "// ", 3);
+ InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// ");
}
void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
@@ -1130,7 +1126,7 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ", 3);
+ ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ");
}
Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
@@ -1149,7 +1145,7 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
PDecl->getSetterName(), PDecl->getType(),
PDecl->getSetterMethodDecl(),
SourceLocation(), SourceLocation(),
@@ -1178,7 +1174,7 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
PDecl->getGetterName(), PDecl->getType(),
PDecl->getGetterMethodDecl(),
SourceLocation(), SourceLocation(),
@@ -1209,14 +1205,15 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
}
Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
- SourceLocation OrigStart) {
+ SourceLocation OrigStart,
+ bool &replaced) {
ObjCIvarDecl *D = IV->getDecl();
const Expr *BaseExpr = IV->getBase();
if (CurMethodDef) {
- if (BaseExpr->getType()->isObjCObjectPointerType() &&
- isa<DeclRefExpr>(BaseExpr)) {
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
ObjCInterfaceType *iFaceDecl =
dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
+ assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
@@ -1226,7 +1223,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Synthesize an explicit cast to gain access to the ivar.
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName.c_str());
+ IdentifierInfo *II = &Context->Idents.get(RecName);
RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
@@ -1238,17 +1235,16 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
IV->getBase()->getLocEnd(),
castExpr);
+ replaced = true;
if (IV->isFreeIvar() &&
CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
IV->getLocation(),
D->getType());
- ReplaceStmt(IV, ME);
// delete IV; leak for now, see RewritePropertySetter() usage for more info.
return ME;
}
-
- ReplaceStmt(IV->getBase(), PE);
+ // Get the new text
// Cannot delete IV->getBase(), since PE points to it.
// Replace the old base with the cast. This is important when doing
// embedded rewrites. For example, [newInv->_container addObject:0].
@@ -1272,7 +1268,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Synthesize an explicit cast to gain access to the ivar.
std::string RecName = clsDeclared->getIdentifier()->getName();
RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName.c_str());
+ IdentifierInfo *II = &Context->Idents.get(RecName);
RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
@@ -1283,7 +1279,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
IV->getBase()->getLocEnd(), castExpr);
- ReplaceStmt(IV->getBase(), PE);
+ replaced = true;
// Cannot delete IV->getBase(), since PE points to it.
// Replace the old base with the cast. This is important when doing
// embedded rewrites. For example, [newInv->_container addObject:0].
@@ -1294,6 +1290,28 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
return IV;
}
+Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) {
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI) {
+ if (*CI) {
+ Stmt *newStmt = RewriteObjCNestedIvarRefExpr(*CI, replaced);
+ if (newStmt)
+ *CI = newStmt;
+ }
+ }
+ if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ SourceRange OrigStmtRange = S->getSourceRange();
+ Stmt *newStmt = RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin(),
+ replaced);
+ return newStmt;
+ }
+ if (ObjCMessageExpr *MsgRefExpr = dyn_cast<ObjCMessageExpr>(S)) {
+ Stmt *newStmt = SynthMessageExpr(MsgRefExpr);
+ return newStmt;
+ }
+ return S;
+}
+
/// SynthCountByEnumWithState - To print:
/// ((unsigned int (*)
/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
@@ -1326,7 +1344,7 @@ Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) {
SourceLocation startLoc = S->getLocStart();
buf = "goto __break_label_";
buf += utostr(ObjCBcLabelNo.back());
- ReplaceText(startLoc, strlen("break"), buf.c_str(), buf.size());
+ ReplaceText(startLoc, strlen("break"), buf);
return 0;
}
@@ -1343,7 +1361,7 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
SourceLocation startLoc = S->getLocStart();
buf = "goto __continue_label_";
buf += utostr(ObjCBcLabelNo.back());
- ReplaceText(startLoc, strlen("continue"), buf.c_str(), buf.size());
+ ReplaceText(startLoc, strlen("continue"), buf);
return 0;
}
@@ -1442,8 +1460,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
startCollectionBuf += 3;
// Replace: "for (type element in" with string constructed thus far.
- ReplaceText(startLoc, startCollectionBuf - startBuf,
- buf.c_str(), buf.size());
+ ReplaceText(startLoc, startCollectionBuf - startBuf, buf);
// Replace ')' in for '(' type elem in collection ')' with ';'
SourceLocation rightParenLoc = S->getRParenLoc();
const char *rparenBuf = SM->getCharacterData(rightParenLoc);
@@ -1484,7 +1501,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
buf += elementTypeAsString;
buf += ")enumState.itemsPtr[counter++];";
// Replace ')' in for '(' type elem in collection ')' with all of these.
- ReplaceText(lparenLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lparenLoc, 1, buf);
/// __continue_label: ;
/// } while (counter < limit);
@@ -1525,7 +1542,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// FIXME: If this should support Obj-C++, support CXXTryStmt
if (isa<CompoundStmt>(S->getBody())) {
SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1);
- InsertText(endBodyLoc, buf.c_str(), buf.size());
+ InsertText(endBodyLoc, buf);
} else {
/* Need to treat single statements specially. For example:
*
@@ -1538,7 +1555,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
const char *semiBuf = strchr(stmtBuf, ';');
assert(semiBuf && "Can't find ';'");
SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(semiBuf-stmtBuf+1);
- InsertText(endBodyLoc, buf.c_str(), buf.size());
+ InsertText(endBodyLoc, buf);
}
Stmts.pop_back();
ObjCBcLabelNo.pop_back();
@@ -1562,7 +1579,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
buf = "objc_sync_enter((id)";
const char *lparenBuf = startBuf;
while (*lparenBuf != '(') lparenBuf++;
- ReplaceText(startLoc, lparenBuf-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, lparenBuf-startBuf+1, buf);
// We can't use S->getSynchExpr()->getLocEnd() to find the end location, since
// the sync expression is typically a message expression that's already
// been rewritten! (which implies the SourceLocation's are invalid).
@@ -1578,7 +1595,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
buf += "id volatile _rethrow = 0;\n";
buf += "objc_exception_try_enter(&_stack);\n";
buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
- ReplaceText(rparenLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(rparenLoc, 1, buf);
startLoc = S->getSynchBody()->getLocEnd();
startBuf = SM->getCharacterData(startLoc);
@@ -1607,7 +1624,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
buf += "}\n";
buf += "}";
- ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lastCurlyLoc, 1, buf);
bool hasReturns = false;
HasReturnStmts(S->getSynchBody(), hasReturns);
@@ -1663,8 +1680,8 @@ void RewriteObjC::RewriteTryReturnStmts(Stmt *S) {
std::string buf;
buf = "{ objc_exception_try_exit(&_stack); return";
- ReplaceText(startLoc, 6, buf.c_str(), buf.size());
- InsertText(onePastSemiLoc, "}", 1);
+ ReplaceText(startLoc, 6, buf);
+ InsertText(onePastSemiLoc, "}");
}
return;
}
@@ -1689,8 +1706,8 @@ void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) {
buf += syncExitBuf;
buf += " return";
- ReplaceText(startLoc, 6, buf.c_str(), buf.size());
- InsertText(onePastSemiLoc, "}", 1);
+ ReplaceText(startLoc, 6, buf);
+ InsertText(onePastSemiLoc, "}");
}
return;
}
@@ -1711,7 +1728,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "objc_exception_try_enter(&_stack);\n";
buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
- ReplaceText(startLoc, 4, buf.c_str(), buf.size());
+ ReplaceText(startLoc, 4, buf);
startLoc = S->getTryBody()->getLocEnd();
startBuf = SM->getCharacterData(startLoc);
@@ -1729,12 +1746,12 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += " _rethrow = objc_exception_extract(&_stack);\n";
buf += " else { /* @catch continue */";
- InsertText(startLoc, buf.c_str(), buf.size());
+ InsertText(startLoc, buf);
} else { /* no catch list */
buf = "}\nelse {\n";
buf += " _rethrow = objc_exception_extract(&_stack);\n";
buf += "}";
- ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lastCurlyLoc, 1, buf);
}
bool sawIdTypedCatch = false;
Stmt *lastCatchBody = 0;
@@ -1767,7 +1784,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
QualType t = catchDecl->getType();
if (t == Context->getObjCIdType()) {
buf += "1) { ";
- ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf);
sawIdTypedCatch = true;
} else if (t->isObjCObjectPointerType()) {
QualType InterfaceTy = t->getPointeeType();
@@ -1777,7 +1794,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
buf += cls->getDecl()->getNameAsString();
buf += "\"), (struct objc_object *)_caught)) { ";
- ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf);
}
}
// Now rewrite the body...
@@ -1789,10 +1806,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
assert((*rParenBuf == ')') && "bogus @catch paren location");
assert((*bodyBuf == '{') && "bogus @catch body location");
- buf = " = _caught;";
// Here we replace ") {" with "= _caught;" (which initializes and
// declares the @catch parameter).
- ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size());
+ ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;");
} else {
assert(false && "@catch rewrite bug");
}
@@ -1814,7 +1830,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "} } /* @catch end */\n";
if (!S->getFinallyStmt())
buf += "}\n";
- InsertText(bodyLoc, buf.c_str(), buf.size());
+ InsertText(bodyLoc, buf);
// Set lastCurlyLoc
lastCurlyLoc = lastCatchBody->getLocEnd();
@@ -1824,8 +1840,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @finally start");
- buf = "/* @finally */";
- ReplaceText(startLoc, 8, buf.c_str(), buf.size());
+ ReplaceText(startLoc, 8, "/* @finally */");
Stmt *body = finalStmt->getFinallyBody();
SourceLocation startLoc = body->getLocStart();
@@ -1836,11 +1851,9 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
"bogus @finally body location");
startLoc = startLoc.getFileLocWithOffset(1);
- buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
- InsertText(startLoc, buf.c_str(), buf.size());
+ InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n");
endLoc = endLoc.getFileLocWithOffset(-1);
- buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
- InsertText(endLoc, buf.c_str(), buf.size());
+ InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n");
// Set lastCurlyLoc
lastCurlyLoc = body->getLocEnd();
@@ -1852,7 +1865,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
buf += "}";
- ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(lastCurlyLoc, 1, buf);
// Now check for any return/continue/go statements within the @try.
// The implicit finally clause won't called if the @try contains any
@@ -1864,8 +1877,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
// Now emit the final closing curly brace...
lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
- buf = " } /* @try scope end */\n";
- InsertText(lastCurlyLoc, buf.c_str(), buf.size());
+ InsertText(lastCurlyLoc, " } /* @try scope end */\n");
return 0;
}
@@ -1897,13 +1909,12 @@ Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
// handle "@ throw" correctly.
const char *wBuf = strchr(startBuf, 'w');
assert((*wBuf == 'w') && "@throw: can't find 'w'");
- ReplaceText(startLoc, wBuf-startBuf+1, buf.c_str(), buf.size());
+ ReplaceText(startLoc, wBuf-startBuf+1, buf);
const char *semiBuf = strchr(startBuf, ';');
assert((*semiBuf == ';') && "@throw: can't find ';'");
SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
- buf = ");";
- ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
+ ReplaceText(semiLoc, 1, ");");
return 0;
}
@@ -1991,7 +2002,17 @@ static void scanToNextArgument(const char *&argRef) {
}
bool RewriteObjC::needToScanForQualifiers(QualType T) {
- return T->isObjCQualifiedIdType() || T->isObjCQualifiedInterfaceType();
+ if (T->isObjCQualifiedIdType())
+ return true;
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ if (PT->getPointeeType()->isObjCQualifiedIdType())
+ return true;
+ }
+ if (T->isObjCObjectPointerType()) {
+ T = T->getPointeeType();
+ return T->isObjCQualifiedInterfaceType();
+ }
+ return false;
}
void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
@@ -2018,8 +2039,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf);
SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1);
// Comment out the protocol references.
- InsertText(LessLoc, "/*", 2);
- InsertText(GreaterLoc, "*/", 2);
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
}
}
}
@@ -2063,8 +2084,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf);
SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1);
// Comment out the protocol references.
- InsertText(LessLoc, "/*", 2);
- InsertText(GreaterLoc, "*/", 2);
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
}
}
if (!proto)
@@ -2087,8 +2108,8 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
SourceLocation GreaterLoc =
Loc.getFileLocWithOffset(endRef-startFuncBuf+1);
// Comment out the protocol references.
- InsertText(LessLoc, "/*", 2);
- InsertText(GreaterLoc, "*/", 2);
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
}
startBuf = ++endBuf;
}
@@ -2102,6 +2123,42 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
}
}
+void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) {
+ QualType QT = ND->getType();
+ const Type* TypePtr = QT->getAs<Type>();
+ if (!isa<TypeOfExprType>(TypePtr))
+ return;
+ while (isa<TypeOfExprType>(TypePtr)) {
+ const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);
+ QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();
+ TypePtr = QT->getAs<Type>();
+ }
+ // FIXME. This will not work for multiple declarators; as in:
+ // __typeof__(a) b,c,d;
+ std::string TypeAsString(QT.getAsString());
+ SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ if (ND->getInit()) {
+ std::string Name(ND->getNameAsString());
+ TypeAsString += " " + Name + " = ";
+ Expr *E = ND->getInit();
+ SourceLocation startLoc;
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))
+ startLoc = ECE->getLParenLoc();
+ else
+ startLoc = E->getLocStart();
+ startLoc = SM->getInstantiationLoc(startLoc);
+ const char *endBuf = SM->getCharacterData(startLoc);
+ ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
+ }
+ else {
+ SourceLocation X = ND->getLocEnd();
+ X = SM->getInstantiationLoc(X);
+ const char *endBuf = SM->getCharacterData(X);
+ ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
+ }
+}
+
// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
void RewriteObjC::SynthSelGetUidFunctionDecl() {
IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
@@ -2126,6 +2183,19 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
RewriteObjCQualifiedInterfaceTypes(FD);
}
+static void RewriteBlockPointerType(std::string& Str, QualType Type) {
+ std::string TypeString(Type.getAsString());
+ const char *argPtr = TypeString.c_str();
+ if (!strchr(argPtr, '^')) {
+ Str += TypeString;
+ return;
+ }
+ while (*argPtr) {
+ Str += (*argPtr == '^' ? '*' : *argPtr);
+ argPtr++;
+ }
+}
+
void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
@@ -2140,13 +2210,12 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
unsigned numArgs = proto->getNumArgs();
for (unsigned i = 0; i < numArgs; i++) {
QualType ArgType = proto->getArgType(i);
- FdStr += ArgType.getAsString();
-
+ RewriteBlockPointerType(FdStr, ArgType);
if (i+1 < numArgs)
FdStr += ", ";
}
FdStr += ");\n";
- InsertText(FunLocStart, FdStr.c_str(), FdStr.size());
+ InsertText(FunLocStart, FdStr);
CurFunctionDeclToDeclareForBlock = 0;
}
@@ -2330,7 +2399,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- &Context->Idents.get(S.c_str()), strType, 0,
+ &Context->Idents.get(S), strType, 0,
VarDecl::Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
@@ -2380,7 +2449,7 @@ QualType RewriteObjC::getSuperStructType() {
/*Mutable=*/false));
}
- SuperStructDecl->completeDefinition(*Context);
+ SuperStructDecl->completeDefinition();
}
return Context->getTagDeclType(SuperStructDecl);
}
@@ -2411,7 +2480,7 @@ QualType RewriteObjC::getConstantStringStructType() {
/*Mutable=*/true));
}
- ConstantStringDecl->completeDefinition(*Context);
+ ConstantStringDecl->completeDefinition();
}
return Context->getTagDeclType(ConstantStringDecl);
}
@@ -2871,7 +2940,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
if ((CDecl->isForwardDecl() || NumIvars == 0) &&
(!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
- ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, endBuf-startBuf, Result);
return;
}
@@ -2913,10 +2982,10 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
endHeader++;
}
// rewrite the original header
- ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, endHeader-startBuf, Result);
} else {
// rewrite the original header *without* disturbing the '{'
- ReplaceText(LocStart, cursor-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, cursor-startBuf, Result);
}
if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
Result = "\n struct ";
@@ -2928,7 +2997,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// insert the super class structure definition.
SourceLocation OnePastCurly =
LocStart.getFileLocWithOffset(cursor-startBuf+1);
- InsertText(OnePastCurly, Result.c_str(), Result.size());
+ InsertText(OnePastCurly, Result);
}
cursor++; // past '{'
@@ -2946,26 +3015,26 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
!strncmp(cursor, "private", strlen("private")) ||
!strncmp(cursor, "package", strlen("package")) ||
!strncmp(cursor, "protected", strlen("protected")))
- InsertText(atLoc, "// ", 3);
+ InsertText(atLoc, "// ");
}
// FIXME: If there are cases where '<' is used in ivar declaration part
// of user code, then scan the ivar list and use needToScanForQualifiers
// for type checking.
else if (*cursor == '<') {
SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
- InsertText(atLoc, "/* ", 3);
+ InsertText(atLoc, "/* ");
cursor = strchr(cursor, '>');
cursor++;
atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
- InsertText(atLoc, " */", 3);
+ InsertText(atLoc, " */");
} else if (*cursor == '^') { // rewrite block specifier.
SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
- ReplaceText(caretLoc, 1, "*", 1);
+ ReplaceText(caretLoc, 1, "*");
}
cursor++;
}
// Don't forget to add a ';'!!
- InsertText(LocEnd.getFileLocWithOffset(1), ";", 1);
+ InsertText(LocEnd.getFileLocWithOffset(1), ";");
} else { // we don't have any instance variables - insert super struct.
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
Result += " {\n struct ";
@@ -2973,7 +3042,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Result += "_IMPL ";
Result += RCDecl->getNameAsString();
Result += "_IVARS;\n};\n";
- ReplaceText(LocStart, endBuf-startBuf, Result.c_str(), Result.size());
+ ReplaceText(LocStart, endBuf-startBuf, Result);
}
// Mark this struct as having been generated.
if (!ObjCSynthesizedStructs.insert(CDecl))
@@ -3805,7 +3874,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
// Create local declarations to avoid rewriting all closure decl ref exprs.
// First, emit a declaration for all "by ref" decls.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -3816,7 +3885,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
// Next, emit a declaration for all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
@@ -3861,7 +3930,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += (*I)->getNameAsString();
S += ", (void*)src->";
S += (*I)->getNameAsString();
- if (BlockByRefDecls.count((*I)))
+ if (BlockByRefDeclsPtrSet.count((*I)))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else
S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
@@ -3877,7 +3946,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
E = ImportedBlockDecls.end(); I != E; ++I) {
S += "_Block_object_dispose((void*)src->";
S += (*I)->getNameAsString();
- if (BlockByRefDecls.count((*I)))
+ if (BlockByRefDeclsPtrSet.count((*I)))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else
S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
@@ -3901,7 +3970,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3927,7 +3996,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
@@ -3966,7 +4035,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += " Desc = desc;\n";
// Initialize all "by copy" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -3977,7 +4046,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + ";\n";
}
// Initialize all "by ref" arguments.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
std::string Name = (*I)->getNameAsString();
Constructor += " ";
@@ -4047,23 +4116,25 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag);
- InsertText(FunLocStart, CI.c_str(), CI.size());
+ InsertText(FunLocStart, CI);
std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag);
- InsertText(FunLocStart, CF.c_str(), CF.size());
+ InsertText(FunLocStart, CF);
if (ImportedBlockDecls.size()) {
std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag);
- InsertText(FunLocStart, HF.c_str(), HF.size());
+ InsertText(FunLocStart, HF);
}
std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName,
ImportedBlockDecls.size() > 0);
- InsertText(FunLocStart, BD.c_str(), BD.size());
+ InsertText(FunLocStart, BD);
BlockDeclRefs.clear();
BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
BlockCallExprs.clear();
ImportedBlockDecls.clear();
}
@@ -4078,17 +4149,23 @@ void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
SynthesizeBlockLiterals(FunLocStart, FuncName);
}
-void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
- //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
- //SourceLocation FunLocStart = MD->getLocStart();
- // FIXME: This hack works around a bug in Rewrite.InsertText().
- SourceLocation FunLocStart = MD->getLocStart().getFileLocWithOffset(-1);
- std::string FuncName = MD->getSelector().getAsString();
+static void BuildUniqueMethodName(std::string &Name,
+ ObjCMethodDecl *MD) {
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ Name = IFace->getNameAsCString();
+ Name += "__" + MD->getSelector().getAsString();
// Convert colons to underscores.
std::string::size_type loc = 0;
- while ((loc = FuncName.find(":", loc)) != std::string::npos)
- FuncName.replace(loc, 1, "_");
+ while ((loc = Name.find(":", loc)) != std::string::npos)
+ Name.replace(loc, 1, "_");
+}
+void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
+ //SourceLocation FunLocStart = MD->getLocStart();
+ SourceLocation FunLocStart = MD->getLocStart();
+ std::string FuncName;
+ BuildUniqueMethodName(FuncName, MD);
SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
}
@@ -4304,11 +4381,9 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
std::string TypeAsString = "(";
TypeAsString += QT.getAsString();
TypeAsString += ")";
- ReplaceText(LocStart, endBuf-startBuf+1,
- TypeAsString.c_str(), TypeAsString.size());
+ ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString);
return;
}
-
// advance the location to startArgList.
const char *argPtr = startBuf;
@@ -4317,7 +4392,7 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
case '^':
// Replace the '^' with '*'.
LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
- ReplaceText(LocStart, 1, "*", 1);
+ ReplaceText(LocStart, 1, "*");
break;
}
}
@@ -4346,7 +4421,7 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
case '^':
// Replace the '^' with '*'.
DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
- ReplaceText(DeclLoc, 1, "*", 1);
+ ReplaceText(DeclLoc, 1, "*");
break;
case '(':
parenCount++;
@@ -4427,7 +4502,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
if (*startBuf == '^') {
// Replace the '^' with '*', computing a negative offset.
DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf);
- ReplaceText(DeclLoc, 1, "*", 1);
+ ReplaceText(DeclLoc, 1, "*");
}
if (PointerTypeTakesAnyBlockArguments(DeclT)) {
// Replace the '^' with '*' for arguments.
@@ -4438,7 +4513,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
while (argListBegin < argListEnd) {
if (*argListBegin == '^') {
SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf);
- ReplaceText(CaretLoc, 1, "*", 1);
+ ReplaceText(CaretLoc, 1, "*");
}
argListBegin++;
}
@@ -4563,7 +4638,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null");
FunLocStart = CurMethodDef->getLocStart();
}
- InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size());
+ InsertText(FunLocStart, ByrefType);
if (Ty.isObjCGCWeak()) {
flag |= BLOCK_FIELD_IS_WEAK;
isa = 1;
@@ -4579,7 +4654,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
flag |= BLOCK_FIELD_IS_OBJECT;
std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
if (!HF.empty())
- InsertText(FunLocStart, HF.c_str(), HF.size());
+ InsertText(FunLocStart, HF);
}
// struct __Block_byref_ND ND =
@@ -4592,10 +4667,12 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
Name = ND->getNameAsString();
ByrefType.clear();
RewriteByRefString(ByrefType, Name, ND);
+ std::string ForwardingCastType("(");
+ ForwardingCastType += ByrefType + " *)";
if (!hasInit) {
ByrefType += " " + Name + " = {(void*)";
ByrefType += utostr(isa);
- ByrefType += ", &" + Name + ", ";
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
ByrefType += utostr(flags);
ByrefType += ", ";
ByrefType += "sizeof(";
@@ -4608,8 +4685,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += utostr(flag);
}
ByrefType += "};\n";
- ReplaceText(DeclLoc, endBuf-startBuf+Name.size(),
- ByrefType.c_str(), ByrefType.size());
+ ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), ByrefType);
}
else {
SourceLocation startLoc;
@@ -4624,7 +4700,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += " " + Name;
ByrefType += " = {(void*)";
ByrefType += utostr(isa);
- ByrefType += ", &" + Name + ", ";
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
ByrefType += utostr(flags);
ByrefType += ", ";
ByrefType += "sizeof(";
@@ -4637,8 +4713,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += utostr(flag);
ByrefType += ", ";
}
- ReplaceText(DeclLoc, endBuf-startBuf,
- ByrefType.c_str(), ByrefType.size());
+ ReplaceText(DeclLoc, endBuf-startBuf, ByrefType);
// Complete the newly synthesized compound expression by inserting a right
// curly brace before the end of the declaration.
@@ -4654,7 +4729,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
SourceLocation semiLoc =
startLoc.getFileLocWithOffset(semiBuf-startBuf);
- InsertText(semiLoc, "}", 1);
+ InsertText(semiLoc, "}");
}
return;
}
@@ -4665,12 +4740,19 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
if (BlockDeclRefs.size()) {
// Unique all "by copy" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (!BlockDeclRefs[i]->isByRef())
- BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
+ if (!BlockDeclRefs[i]->isByRef()) {
+ if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
+ }
// Unique all "by ref" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
if (BlockDeclRefs[i]->isByRef()) {
- BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
+ if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
}
// Find any imported blocks...they will need special attention.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
@@ -4699,13 +4781,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
if (CurFunctionDef)
FuncName = CurFunctionDef->getNameAsString();
- else if (CurMethodDef) {
- FuncName = CurMethodDef->getSelector().getAsString();
- // Convert colons to underscores.
- std::string::size_type loc = 0;
- while ((loc = FuncName.find(":", loc)) != std::string::npos)
- FuncName.replace(loc, 1, "_");
- } else if (GlobalVarDecl)
+ else if (CurMethodDef)
+ BuildUniqueMethodName(FuncName, CurMethodDef);
+ else if (GlobalVarDecl)
FuncName = std::string(GlobalVarDecl->getNameAsString());
std::string BlockNumber = utostr(Blocks.size()-1);
@@ -4752,7 +4830,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
if (BlockDeclRefs.size()) {
Expr *Exp;
// Output all "by copy" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
if (isObjCType((*I)->getType())) {
// FIXME: Conform to ABI ([[obj retain] autorelease]).
@@ -4770,13 +4848,25 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
InitExprs.push_back(Exp);
}
// Output all "by ref" declarations.
- for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
+ ValueDecl *ND = (*I);
+ std::string Name(ND->getNameAsString());
+ std::string RecName;
+ RewriteByRefString(RecName, Name, ND);
+ IdentifierInfo *II = &Context->Idents.get(RecName.c_str()
+ + sizeof("struct"));
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(), II);
+ assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf,
Context->getPointerType(Exp->getType()),
SourceLocation());
+ Exp = NoTypeInfoCStyleCastExpr(Context, castT, CastExpr::CK_Unknown, Exp);
InitExprs.push_back(Exp);
}
}
@@ -4798,7 +4888,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
NewRep);
BlockDeclRefs.clear();
BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
ImportedBlockDecls.clear();
return NewRep;
}
@@ -4843,7 +4935,21 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
CI != E; ++CI)
if (*CI) {
- Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
+ Stmt *newStmt;
+ Stmt *S = (*CI);
+ if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ Expr *OldBase = IvarRefExpr->getBase();
+ bool replaced = false;
+ newStmt = RewriteObjCNestedIvarRefExpr(S, replaced);
+ if (replaced) {
+ if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt))
+ ReplaceStmt(OldBase, IRE->getBase());
+ else
+ ReplaceStmt(S, newStmt);
+ }
+ }
+ else
+ newStmt = RewriteFunctionBodyOrGlobalInitializer(S);
if (newStmt)
*CI = newStmt;
}
@@ -4865,9 +4971,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
return RewriteAtEncode(AtEncode);
- if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
- return RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin());
-
if (ObjCPropertyRefExpr *PropRefExpr = dyn_cast<ObjCPropertyRefExpr>(S)) {
BinaryOperator *BinOp = PropSetters[PropRefExpr];
if (BinOp) {
@@ -4995,7 +5098,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteBlockPointerDecl(ND);
else if (ND->getType()->isFunctionPointerType())
CheckFunctionPointerDecl(ND->getType(), ND);
- if (VarDecl *VD = dyn_cast<VarDecl>(SD))
+ if (VarDecl *VD = dyn_cast<VarDecl>(SD)) {
if (VD->hasAttr<BlocksAttr>()) {
static unsigned uniqueByrefDeclCount = 0;
assert(!BlockByRefDeclNo.count(ND) &&
@@ -5003,6 +5106,9 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;
RewriteByRefVar(VD);
}
+ else
+ RewriteTypeOfDecl(VD);
+ }
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
@@ -5191,11 +5297,6 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
}
void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
- // Get the top-level buffer that this corresponds to.
-
- // Rewrite tabs if we care.
- //RewriteTabs();
-
if (Diags.hasErrorOccurred())
return;
@@ -5207,8 +5308,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
E = ProtocolExprDecls.end(); I != E; ++I)
RewriteObjCProtocolMetaData(*I, "", "", Preamble);
- InsertText(SM->getLocForStartOfFile(MainFileID),
- Preamble.c_str(), Preamble.size(), false);
+ InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
if (ClassImplementation.size() || CategoryImplementation.size())
RewriteImplementations();
@@ -5219,7 +5319,7 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
//printf("Changed:\n");
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
} else {
- fprintf(stderr, "No changes\n");
+ llvm::errs() << "No changes\n";
}
if (ClassImplementation.size() || CategoryImplementation.size() ||
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 83b4542caa25..9ec5ffe1c353 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -104,11 +104,6 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
if (StartColNo) --StartColNo; // Zero base the col #.
}
- // Pick the first non-whitespace column.
- while (StartColNo < SourceLine.size() &&
- (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
- ++StartColNo;
-
// Compute the column number of the end.
unsigned EndColNo = CaretLine.size();
if (EndLineNo == LineNo) {
@@ -123,16 +118,25 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
}
}
+ assert(StartColNo <= EndColNo && "Invalid range!");
+
+ // Pick the first non-whitespace column.
+ while (StartColNo < SourceLine.size() &&
+ (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
+ ++StartColNo;
+
// Pick the last non-whitespace column.
- if (EndColNo <= SourceLine.size())
- while (EndColNo-1 &&
- (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
- --EndColNo;
- else
+ if (EndColNo > SourceLine.size())
EndColNo = SourceLine.size();
+ while (EndColNo-1 &&
+ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+ --EndColNo;
+
+ // If the start/end passed each other, then we are trying to highlight a range
+ // that just exists in whitespace, which must be some sort of other bug.
+ assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
// Fill the range with ~'s.
- assert(StartColNo <= EndColNo && "Invalid range!");
for (unsigned i = StartColNo; i < EndColNo; ++i)
CaretLine[i] = '~';
}
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index e27060295a81..b59c7e824bf1 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -462,7 +462,7 @@ _mm_cvtss_f32(__m128 a)
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadh_pi(__m128 a, __m64 const *p)
+_mm_loadh_pi(__m128 a, const __m64 *p)
{
__m128 b;
b[0] = *(float*)p;
@@ -471,7 +471,7 @@ _mm_loadh_pi(__m128 a, __m64 const *p)
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_pi(__m128 a, __m64 const *p)
+_mm_loadl_pi(__m128 a, const __m64 *p)
{
__m128 b;
b[0] = *(float*)p;
@@ -480,13 +480,13 @@ _mm_loadl_pi(__m128 a, __m64 const *p)
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ss(float *p)
+_mm_load_ss(const float *p)
{
return (__m128){ *p, 0, 0, 0 };
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load1_ps(float *p)
+_mm_load1_ps(const float *p)
{
return (__m128){ *p, *p, *p, *p };
}
@@ -494,19 +494,19 @@ _mm_load1_ps(float *p)
#define _mm_load_ps1(p) _mm_load1_ps(p)
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ps(float *p)
+_mm_load_ps(const float *p)
{
return *(__m128*)p;
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_ps(float *p)
+_mm_loadu_ps(const float *p)
{
return __builtin_ia32_loadups(p);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadr_ps(float *p)
+_mm_loadr_ps(const float *p)
{
__m128 a = _mm_load_ps(p);
return __builtin_shufflevector(a, a, 3, 2, 1, 0);
@@ -895,7 +895,7 @@ do { \
(row0) = _mm_movelh_ps(tmp0, tmp2); \
(row1) = _mm_movehl_ps(tmp2, tmp0); \
(row2) = _mm_movelh_ps(tmp1, tmp3); \
- (row3) = _mm_movelh_ps(tmp3, tmp1); \
+ (row3) = _mm_movehl_ps(tmp3, tmp1); \
} while (0)
/* Ugly hack for backwards-compatibility (compatible with gcc) */
diff --git a/lib/Index/Makefile b/lib/Index/Makefile
index 7dee87f3b6bb..9d33a2d175e3 100644
--- a/lib/Index/Makefile
+++ b/lib/Index/Makefile
@@ -16,7 +16,6 @@ include $(LEVEL)/Makefile.config
LIBRARYNAME := clangIndex
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
ifeq ($(ARCH),PowerPC)
CXXFLAGS += -maltivec
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index afd1ba885167..3207062ccadd 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -985,10 +985,11 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
if (CurPtr == BufferEnd+1) { --CurPtr; break; }
} while (C != '\n' && C != '\r');
- // Found but did not consume the newline.
- if (PP && PP->HandleComment(Result,
- SourceRange(getSourceLocation(BufferPtr),
- getSourceLocation(CurPtr)))) {
+ // Found but did not consume the newline. Notify comment handlers about the
+ // comment unless we're in a #if 0 block.
+ if (PP && !isLexingRawMode() &&
+ PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
+ getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; // A token has to be returned.
}
@@ -1235,9 +1236,10 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
C = *CurPtr++;
}
- if (PP && PP->HandleComment(Result,
- SourceRange(getSourceLocation(BufferPtr),
- getSourceLocation(CurPtr)))) {
+ // Notify comment handlers about the comment unless we're in a #if 0 block.
+ if (PP && !isLexingRawMode() &&
+ PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
+ getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; // A token has to be returned.
}
diff --git a/lib/Lex/Makefile b/lib/Lex/Makefile
index a2437da812bd..509077017c2d 100644
--- a/lib/Lex/Makefile
+++ b/lib/Lex/Makefile
@@ -16,7 +16,6 @@ include $(LEVEL)/Makefile.config
LIBRARYNAME := clangLex
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
ifeq ($(ARCH),PowerPC)
CXXFLAGS += -maltivec
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index 7c3780ffc0ac..6aeb6fa3a2f7 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -91,7 +91,7 @@ const Token &Preprocessor::PeekAhead(unsigned N) {
void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {
assert(Tok.isAnnotation() && "Expected annotation token");
assert(CachedLexPos != 0 && "Expected to have some cached tokens");
- assert(CachedTokens[CachedLexPos-1].getLocation() == Tok.getAnnotationEndLoc()
+ assert(CachedTokens[CachedLexPos-1].getLastLoc() == Tok.getAnnotationEndLoc()
&& "The annotation should be until the most recent cached token");
// Start from the end of the cached tokens list and look for the token
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index b0e784bcd96a..4803c5ab85d5 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1514,18 +1514,21 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
// Check to see if this is the last token on the #if[n]def line.
CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
+ IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
+ MacroInfo *MI = getMacroInfo(MII);
+
if (CurPPLexer->getConditionalStackDepth() == 0) {
- // If the start of a top-level #ifdef, inform MIOpt.
- if (!ReadAnyTokensBeforeDirective) {
+ // If the start of a top-level #ifdef and if the macro is not defined,
+ // inform MIOpt that this might be the start of a proper include guard.
+ // Otherwise it is some other form of unknown conditional which we can't
+ // handle.
+ if (!ReadAnyTokensBeforeDirective && MI == 0) {
assert(isIfndef && "#ifdef shouldn't reach here");
- CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MacroNameTok.getIdentifierInfo());
+ CurPPLexer->MIOpt.EnterTopLevelIFNDEF(MII);
} else
CurPPLexer->MIOpt.EnterTopLevelConditional();
}
- IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
- MacroInfo *MI = getMacroInfo(MII);
-
// If there is a macro, process it.
if (MI) // Mark it used.
MI->setIsUsed(true);
@@ -1558,7 +1561,7 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
// If this condition is equivalent to #ifndef X, and if this is the first
// directive seen, handle it for the multiple-include optimization.
if (CurPPLexer->getConditionalStackDepth() == 0) {
- if (!ReadAnyTokensBeforeDirective && IfNDefMacro)
+ if (!ReadAnyTokensBeforeDirective && IfNDefMacro && ConditionalTrue)
CurPPLexer->MIOpt.EnterTopLevelIFNDEF(IfNDefMacro);
else
CurPPLexer->MIOpt.EnterTopLevelConditional();
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 13aeb88b1db0..b97ab2485d3d 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Lex/LexDiagnostic.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <ctime>
using namespace clang;
@@ -152,7 +153,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
MacroInfo *MI) {
if (Callbacks) Callbacks->MacroExpands(Identifier, MI);
- // If this is a macro exapnsion in the "#if !defined(x)" line for the file,
+ // 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.
if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro();
@@ -627,7 +628,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
++NumBuiltinMacroExpanded;
- char TmpBuffer[100];
+ llvm::SmallString<128> TmpBuffer;
+ llvm::raw_svector_ostream OS(TmpBuffer);
// Set up the return result.
Tok.setIdentifierInfo(0);
@@ -652,9 +654,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc);
// __LINE__ expands to a simple numeric value.
- sprintf(TmpBuffer, "%u", PLoc.getLine());
+ OS << PLoc.getLine();
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) {
// C99 6.10.8: "__FILE__: The presumed name of the current source file (a
// character string literal)". This can be affected by #line.
@@ -671,10 +672,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
}
// Escape this filename. Turn '\' -> '\\' '"' -> '\"'
- std::string FN = PLoc.getFilename();
- FN = '"' + Lexer::Stringify(FN) + '"';
+ llvm::SmallString<128> FN;
+ FN += PLoc.getFilename();
+ Lexer::Stringify(FN);
+ OS << '"' << FN.str() << '"';
Tok.setKind(tok::string_literal);
- CreateString(&FN[0], FN.size(), Tok, Tok.getLocation());
} else if (II == Ident__DATE__) {
if (!DATELoc.isValid())
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
@@ -683,6 +685,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.setLocation(SourceMgr.createInstantiationLoc(DATELoc, Tok.getLocation(),
Tok.getLocation(),
Tok.getLength()));
+ return;
} else if (II == Ident__TIME__) {
if (!TIMELoc.isValid())
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
@@ -691,6 +694,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.setLocation(SourceMgr.createInstantiationLoc(TIMELoc, Tok.getLocation(),
Tok.getLocation(),
Tok.getLength()));
+ return;
} else if (II == Ident__INCLUDE_LEVEL__) {
// Compute the presumed include depth of this token. This can be affected
// by GNU line markers.
@@ -702,9 +706,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc());
// __INCLUDE_LEVEL__ expands to a simple numeric value.
- sprintf(TmpBuffer, "%u", Depth);
+ OS << Depth;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__TIMESTAMP__) {
// MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be
// of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime.
@@ -725,17 +728,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
} else {
Result = "??? ??? ?? ??:??:?? ????\n";
}
- TmpBuffer[0] = '"';
- unsigned Len = strlen(Result);
- memcpy(TmpBuffer+1, Result, Len-1); // Copy string without the newline.
- TmpBuffer[Len] = '"';
+ // Surround the string with " and strip the trailing newline.
+ OS << '"' << llvm::StringRef(Result, strlen(Result)-1) << '"';
Tok.setKind(tok::string_literal);
- CreateString(TmpBuffer, Len+1, Tok, Tok.getLocation());
} else if (II == Ident__COUNTER__) {
// __COUNTER__ expands to a simple numeric value.
- sprintf(TmpBuffer, "%u", CounterValue++);
+ OS << CounterValue++;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__has_feature ||
II == Ident__has_builtin) {
// The argument to these two builtins should be a parenthesized identifier.
@@ -770,9 +769,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Value = HasFeature(*this, FeatureII);
}
- sprintf(TmpBuffer, "%d", (int)Value);
+ OS << (int)Value;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else if (II == Ident__has_include ||
II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
@@ -784,10 +782,10 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
IsValid = EvaluateHasInclude(Value, Tok, II, *this);
else
IsValid = EvaluateHasIncludeNext(Value, Tok, II, *this);
- sprintf(TmpBuffer, "%d", (int)Value);
+ OS << (int)Value;
Tok.setKind(tok::numeric_constant);
- CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
} else {
assert(0 && "Unknown identifier!");
}
+ CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation());
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 5689baaac652..df0e702ab447 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -424,7 +424,7 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
// advanced by 3 should return the location of b, not of \\. One compounding
// detail of this is that the escape may be made by a trigraph.
if (!Lexer::isObviouslySimpleCharacter(*TokPtr))
- PhysOffset = Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
+ PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
return TokStart.getFileLocWithOffset(PhysOffset);
}
diff --git a/lib/Makefile b/lib/Makefile
index d499ee555a38..538bf4394071 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,7 +9,7 @@
LEVEL = ../../..
PARALLEL_DIRS = Headers Runtime Basic Lex Parse AST Sema CodeGen Analysis \
- Rewrite Frontend Index Driver
+ Checker Rewrite Frontend Index Driver
include $(LEVEL)/Makefile.common
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 9e5f5a2ac098..4a699e7ad5e5 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -253,6 +253,11 @@ bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID);
TypeSpecWidth = W;
TSWLoc = Loc;
+ if (TypeAltiVecVector && ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::warn_vector_long_decl_spec_combination;
+ return true;
+ }
return false;
}
@@ -289,6 +294,38 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
TypeRep = Rep;
TSTLoc = Loc;
TypeSpecOwned = Owned;
+ if (TypeAltiVecVector && (TypeSpecType == TST_double)) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_vector_double_decl_spec_combination;
+ return true;
+ }
+ return false;
+}
+
+bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID) {
+ if (TypeSpecType != TST_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_vector_decl_spec_combination;
+ return true;
+ }
+ TypeAltiVecVector = isAltiVecVector;
+ AltiVecLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID) {
+ if (!TypeAltiVecVector || (TypeSpecType != TST_unspecified)) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ DiagID = diag::err_invalid_pixel_decl_spec_combination;
+ return true;
+ }
+ TypeSpecType = TST_int;
+ TypeSpecSign = TSS_unsigned;
+ TypeSpecWidth = TSW_short;
+ TypeAltiVecPixel = isAltiVecPixel;
+ TSTLoc = Loc;
return false;
}
diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile
index 5d69029edc1a..de16e3ea665a 100644
--- a/lib/Parse/Makefile
+++ b/lib/Parse/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangParse
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b5ba8acafc8d..8aa69363beee 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -733,7 +733,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
if (TagName) {
Diag(Loc, diag::err_use_of_tag_name_without_tag)
- << Tok.getIdentifierInfo() << TagName
+ << Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus
<< CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName);
// Parse this as a tag as if the missing tag were present.
@@ -1029,6 +1029,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier())
goto DoneWithDeclSpec;
+ // Check for need to substitute AltiVec keyword tokens.
+ if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
+ break;
+
// It has to be available as a typedef too!
TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), CurScope);
@@ -1270,6 +1274,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
DiagID);
break;
+ case tok::kw___vector:
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw___pixel:
+ isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
+ break;
// class-specifier:
case tok::kw_class:
@@ -1395,20 +1405,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
/// [C++0x] 'decltype' ( expression )
+/// [AltiVec] '__vector'
bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
const char *&PrevSpec,
unsigned &DiagID,
- const ParsedTemplateInfo &TemplateInfo) {
+ const ParsedTemplateInfo &TemplateInfo,
+ bool SuppressDeclarations) {
SourceLocation Loc = Tok.getLocation();
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
+ // Check for need to substitute AltiVec keyword tokens.
+ if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
+ break;
+ // Fall through.
case tok::kw_typename: // typename foo::bar
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- TemplateInfo);
+ TemplateInfo, SuppressDeclarations);
// Otherwise, not a type specifier.
return false;
case tok::coloncolon: // ::foo::bar
@@ -1420,7 +1436,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- TemplateInfo);
+ TemplateInfo, SuppressDeclarations);
// Otherwise, not a type specifier.
return false;
@@ -1519,14 +1535,21 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
DiagID);
break;
-
+ case tok::kw___vector:
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ break;
+ case tok::kw___pixel:
+ isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
+ break;
+
// class-specifier:
case tok::kw_class:
case tok::kw_struct:
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
- ParseClassSpecifier(Kind, Loc, DS, TemplateInfo);
+ ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none,
+ SuppressDeclarations);
return true;
}
@@ -1750,14 +1773,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ConsumeToken();
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
Diag(Tok, diag::err_unexpected_at);
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, true);
continue;
}
ConsumeToken();
ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
if (!Tok.is(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::semi, true, true);
+ SkipUntil(tok::semi, true);
continue;
}
llvm::SmallVector<DeclPtrTy, 16> Fields;
@@ -1771,26 +1794,28 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
if (Tok.is(tok::semi)) {
ConsumeToken();
} else if (Tok.is(tok::r_brace)) {
- Diag(Tok, diag::ext_expected_semi_decl_list);
+ ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list);
break;
} else {
- Diag(Tok, diag::err_expected_semi_decl_list);
- // Skip to end of block or statement
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement to avoid ext-warning on extra ';'.
SkipUntil(tok::r_brace, true, true);
+ // If we stopped at a ';', eat it.
+ if (Tok.is(tok::semi)) ConsumeToken();
}
}
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- AttributeList *AttrList = 0;
+ llvm::OwningPtr<AttributeList> AttrList;
// If attributes exist after struct contents, parse them.
if (Tok.is(tok::kw___attribute))
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
Actions.ActOnFields(CurScope,
RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
LBraceLoc, RBraceLoc,
- AttrList);
+ AttrList.get());
StructScope.Exit();
Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
}
@@ -1817,10 +1842,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
ConsumeToken();
}
- AttributeList *Attr = 0;
+ llvm::OwningPtr<AttributeList> Attr;
// If attributes exist after tag, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseGNUAttributes();
+ Attr.reset(ParseGNUAttributes());
CXXScopeSpec SS;
if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
@@ -1870,7 +1895,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool Owned = false;
bool IsDependent = false;
DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
- StartLoc, SS, Name, NameLoc, Attr, AS,
+ StartLoc, SS, Name, NameLoc, Attr.get(),
+ AS,
Action::MultiTemplateParamsArg(Actions),
Owned, IsDependent);
assert(!IsDependent && "didn't expect dependent enum");
@@ -1878,10 +1904,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Tok.is(tok::l_brace))
ParseEnumBody(StartLoc, TagDecl);
- // TODO: semantic analysis on the declspec for enums.
+ // 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;
- if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, DiagID,
+ if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID,
TagDecl.getAs<void>(), Owned))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -1948,14 +1976,14 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
// Eat the }.
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- AttributeList *Attr = 0;
+ llvm::OwningPtr<AttributeList> Attr;
// If attributes exist after the identifier list, parse them.
if (Tok.is(tok::kw___attribute))
- Attr = ParseGNUAttributes(); // FIXME: where do they do?
+ Attr.reset(ParseGNUAttributes()); // FIXME: where do they do?
Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
EnumConstantDecls.data(), EnumConstantDecls.size(),
- CurScope, Attr);
+ CurScope, Attr.get());
EnumScope.Exit();
Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc);
@@ -1981,6 +2009,9 @@ bool Parser::isTypeSpecifierQualifier() {
default: return false;
case tok::identifier: // foo::bar
+ if (TryAltiVecVectorToken())
+ return true;
+ // Fall through.
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -2026,6 +2057,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw__Decimal32:
case tok::kw__Decimal64:
case tok::kw__Decimal128:
+ case tok::kw___vector:
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
@@ -2066,7 +2098,9 @@ bool Parser::isDeclarationSpecifier() {
// Unfortunate hack to support "Class.factoryMethod" notation.
if (getLang().ObjC1 && NextToken().is(tok::period))
return false;
- // Fall through
+ if (TryAltiVecVectorToken())
+ return true;
+ // Fall through.
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
@@ -2117,6 +2151,7 @@ bool Parser::isDeclarationSpecifier() {
case tok::kw__Decimal32:
case tok::kw__Decimal64:
case tok::kw__Decimal128:
+ case tok::kw___vector:
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
@@ -2608,10 +2643,10 @@ 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.
//
- AttributeList *AttrList = 0;
+ llvm::OwningPtr<AttributeList> AttrList;
bool RequiresArg = false;
if (Tok.is(tok::kw___attribute)) {
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
// We require that the argument list (if this is a non-grouping paren) be
// present even if the attribute list was empty.
@@ -2621,7 +2656,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___w64) ||
Tok.is(tok::kw___ptr64)) {
- AttrList = ParseMicrosoftTypeAttributes(AttrList);
+ AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take()));
}
// If we haven't past the identifier yet (or where the identifier would be
@@ -2652,7 +2687,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
bool hadGroupingParens = D.hasGroupingParens();
D.setGroupingParens(true);
if (AttrList)
- D.AddAttributes(AttrList, SourceLocation());
+ D.AddAttributes(AttrList.take(), SourceLocation());
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
// Match the ')'.
@@ -2669,7 +2704,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// ParseFunctionDeclarator to handle of argument list.
D.SetIdentifier(0, Tok.getLocation());
- ParseFunctionDeclarator(StartLoc, D, AttrList, RequiresArg);
+ ParseFunctionDeclarator(StartLoc, D, AttrList.take(), RequiresArg);
}
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
@@ -2762,7 +2797,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Alternatively, this parameter list may be an identifier list form for a
// K&R-style function: void foo(a,b,c)
- if (!getLang().CPlusPlus && Tok.is(tok::identifier)) {
+ if (!getLang().CPlusPlus && Tok.is(tok::identifier)
+ && !TryAltiVecVectorToken()) {
if (!TryAnnotateTypeOrScopeToken()) {
// K&R identifier lists can't have typedefs as identifiers, per
// C99 6.7.5.3p11.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index efaf8ee3270e..51ee6a443488 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -64,12 +64,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
}
// Read label attributes, if present.
- Action::AttrTy *AttrList = 0;
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute)) {
attrTok = Tok;
// FIXME: save these somewhere.
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
}
if (Tok.is(tok::equal)) {
@@ -91,7 +91,8 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
ParseScope NamespaceScope(this, Scope::DeclScope);
DeclPtrTy NamespcDecl =
- Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace);
+ Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace,
+ AttrList.get());
PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions,
PP.getSourceManager(),
@@ -191,6 +192,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
SourceLocation());
}
+ DS.abort();
+
if (Attr.HasAttr)
Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
<< Attr.Range;
@@ -325,8 +328,6 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
// Parse nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
- AttributeList *AttrList = 0;
-
// Check nested-name specifier.
if (SS.isInvalid()) {
SkipUntil(tok::semi);
@@ -348,8 +349,9 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
}
// Parse (optional) attributes (most likely GNU strong-using extension).
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
// Eat ';'.
DeclEnd = Tok.getLocation();
@@ -358,7 +360,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
tok::semi);
return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name,
- AttrList, IsTypeName, TypenameLoc);
+ AttrList.get(), IsTypeName, TypenameLoc);
}
/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
@@ -547,7 +549,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
/// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
/// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
/// until we reach the start of a definition or see a token that
-/// cannot start a definition.
+/// cannot start a definition. If SuppressDeclarations is true, we do know.
///
/// class-specifier: [C++ class]
/// class-head '{' member-specification[opt] '}'
@@ -587,7 +589,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS) {
+ AccessSpecifier AS, bool SuppressDeclarations){
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@@ -733,8 +735,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// have to be treated differently. If we have 'struct foo {...' or
// 'struct foo :...' 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.
+ // new struct s;
+ // or
+ // &T::operator struct s;
+ // For these, SuppressDeclarations is true.
Action::TagUseKind TUK;
- if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))) {
+ if (SuppressDeclarations)
+ TUK = Action::TUK_Reference;
+ else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
// A class shall not be defined in a friend declaration.
@@ -917,9 +927,62 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
const char *PrevSpec = 0;
unsigned DiagID;
- if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID,
+ // FIXME: The DeclSpec should keep the locations of both the keyword and the
+ // name (if there is one).
+ SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
+
+ if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID,
Result, Owned))
Diag(StartLoc, DiagID) << PrevSpec;
+
+ // At this point, we've successfully parsed a class-specifier in 'definition'
+ // form (e.g. "struct foo { int x; }". While we could just return here, we're
+ // going to look at what comes after it to improve error recovery. If an
+ // impossible token occurs next, we assume that the programmer forgot a ; at
+ // the end of the declaration and recover that way.
+ //
+ // This switch enumerates the valid "follow" set for definition.
+ if (TUK == Action::TUK_Definition) {
+ switch (Tok.getKind()) {
+ case tok::semi: // struct foo {...} ;
+ case tok::star: // struct foo {...} * P;
+ case tok::amp: // struct foo {...} & R = ...
+ case tok::identifier: // struct foo {...} V ;
+ case tok::r_paren: //(struct foo {...} ) {4}
+ case tok::annot_cxxscope: // struct foo {...} a:: b;
+ case tok::annot_typename: // struct foo {...} a ::b;
+ case tok::annot_template_id: // struct foo {...} a<int> ::b;
+ case tok::l_paren: // struct foo {...} ( x);
+ case tok::comma: // __builtin_offsetof(struct foo{...} ,
+ // Storage-class specifiers
+ case tok::kw_static: // struct foo {...} static x;
+ case tok::kw_extern: // struct foo {...} extern x;
+ case tok::kw_typedef: // struct foo {...} typedef x;
+ case tok::kw_register: // struct foo {...} register x;
+ case tok::kw_auto: // struct foo {...} auto x;
+ // Type qualifiers
+ case tok::kw_const: // struct foo {...} const x;
+ case tok::kw_volatile: // struct foo {...} volatile x;
+ case tok::kw_restrict: // struct foo {...} restrict x;
+ case tok::kw_inline: // struct foo {...} inline foo() {};
+ break;
+
+ case tok::r_brace: // struct bar { struct foo {...} }
+ // Missing ';' at end of struct is accepted as an extension in C mode.
+ if (!getLang().CPlusPlus) break;
+ // FALL THROUGH.
+ default:
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
+ TagType == DeclSpec::TST_class ? "class"
+ : TagType == DeclSpec::TST_struct? "struct" : "union");
+ // Push this token back into the preprocessor and change our current token
+ // to ';' so that the rest of the code recovers as though there were an
+ // ';' after the definition.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::semi);
+ break;
+ }
+ }
}
/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
@@ -1164,7 +1227,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
}
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
+ // is a bitfield.
ColonProtectionRAIIObject X(*this);
CXX0XAttributeList AttrList;
@@ -1185,8 +1249,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::kw_namespace)) {
Diag(UsingLoc, diag::err_using_namespace_in_class);
SkipUntil(tok::semi, true, true);
- }
- else {
+ } else {
SourceLocation DeclEnd;
// Otherwise, it must be using-declaration.
ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS);
@@ -1367,19 +1430,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseDeclarator(DeclaratorInfo);
}
- if (Tok.is(tok::semi)) {
- ConsumeToken();
- Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(),
- DeclsInGroup.size());
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
+ // Skip to end of block or statement.
+ SkipUntil(tok::r_brace, true, true);
+ // If we stopped at a ';', eat it.
+ if (Tok.is(tok::semi)) ConsumeToken();
return;
}
- Diag(Tok, diag::err_expected_semi_decl_list);
- // Skip to end of block or statement
- SkipUntil(tok::r_brace, true, true);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return;
+ Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(),
+ DeclsInGroup.size());
}
/// ParseCXXMemberSpecification - Parse the class definition.
@@ -1489,10 +1549,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
- AttributeList *AttrList = 0;
// If attributes exist after class contents, parse them.
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
- AttrList = ParseGNUAttributes(); // FIXME: where should I put them?
+ AttrList.reset(ParseGNUAttributes()); // FIXME: where should I put them?
Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
LBraceLoc, RBraceLoc);
@@ -1546,12 +1606,15 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
SourceLocation ColonLoc = ConsumeToken();
llvm::SmallVector<MemInitTy*, 4> MemInitializers;
-
+ bool AnyErrors = false;
+
do {
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
if (!MemInit.isInvalid())
MemInitializers.push_back(MemInit.get());
-
+ else
+ AnyErrors = true;
+
if (Tok.is(tok::comma))
ConsumeToken();
else if (Tok.is(tok::l_brace))
@@ -1565,7 +1628,8 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
} while (true);
Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
- MemInitializers.data(), MemInitializers.size());
+ MemInitializers.data(), MemInitializers.size(),
+ AnyErrors);
}
/// ParseMemInitializer - Parse a C++ member initializer, which is
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 669575c4f030..c763c2c6f65f 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -22,6 +22,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
+#include "clang/Parse/Template.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallVector.h"
@@ -780,6 +781,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
+ case tok::kw___vector:
case tok::annot_typename: {
if (!getLang().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
@@ -805,9 +807,44 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ParsePostfixExpressionSuffix(move(Res));
}
- case tok::annot_cxxscope: // [C++] id-expression: qualified-id
+ case tok::annot_cxxscope: { // [C++] id-expression: qualified-id
+ Token Next = NextToken();
+ if (Next.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ // We have a qualified template-id that we know refers to a
+ // type, translate it into a type and continue parsing as a
+ // cast expression.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
+ AnnotateTemplateIdTokenAsType(&SS);
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
+ }
+ }
+
+ // Parse as an id-expression.
+ Res = ParseCXXIdExpression(isAddressOfOperand);
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+
+ case tok::annot_template_id: { // [C++] template-id
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ // We have a template-id that we know refers to a type,
+ // translate it into a type and continue parsing as a cast
+ // expression.
+ AnnotateTemplateIdTokenAsType();
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
+ }
+
+ // Fall through to treat the template-id as an id-expression.
+ }
+
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
- case tok::annot_template_id: // [C++] template-id
Res = ParseCXXIdExpression(isAddressOfOperand);
return ParsePostfixExpressionSuffix(move(Res));
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index ca50ef400092..0dbe1ea83890 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -763,12 +763,15 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
bool isInvalid = 0;
// Parse one or more of the type specifiers.
- if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) {
+ if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
+ ParsedTemplateInfo(), /*SuppressDeclarations*/true)) {
Diag(Tok, diag::err_operator_missing_type_specifier);
return true;
}
- while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) ;
+ while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
+ ParsedTemplateInfo(), /*SuppressDeclarations*/true))
+ {}
return false;
}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index ae85aa3a8aef..d1c9be233fe0 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -515,7 +515,8 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
DS.setSetterName(Tok.getIdentifierInfo());
ConsumeToken(); // consume method name
- if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "",
+ if (ExpectAndConsume(tok::colon,
+ diag::err_expected_colon_after_setter_name, "",
tok::r_paren))
return;
} else {
@@ -786,15 +787,15 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
llvm::SmallVector<Declarator, 8> CargNames;
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
- AttributeList *MethodAttrs = 0;
+ llvm::OwningPtr<AttributeList> MethodAttrs;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseGNUAttributes();
+ MethodAttrs.reset(ParseGNUAttributes());
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- 0, CargNames, MethodAttrs,
+ 0, CargNames, MethodAttrs.get(),
MethodImplKind);
PD.complete(Result);
return Result;
@@ -862,9 +863,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// FIXME: Add support for optional parmameter list...
// If attributes exist after the method, parse them.
- AttributeList *MethodAttrs = 0;
+ llvm::OwningPtr<AttributeList> MethodAttrs;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
- MethodAttrs = ParseGNUAttributes();
+ MethodAttrs.reset(ParseGNUAttributes());
if (KeyIdents.size() == 0)
return DeclPtrTy();
@@ -873,9 +874,16 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- &ArgInfos[0], CargNames, MethodAttrs,
+ &ArgInfos[0], CargNames,
+ MethodAttrs.get(),
MethodImplKind, isVariadic);
PD.complete(Result);
+
+ // Delete referenced AttributeList objects.
+ for (llvm::SmallVectorImpl<Action::ObjCArgInfo>::iterator
+ I = ArgInfos.begin(), E = ArgInfos.end(); I != E; ++I)
+ delete I->ArgAttrs;
+
return Result;
}
@@ -1481,7 +1489,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
// Inform the actions module about the parameter declarator, so it
// gets added to the current scope.
+ // FIXME. Probably can build a VarDecl and avoid setting DeclContext.
FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+ Actions.ActOnObjCCatchParam(FirstPart);
} else
ConsumeToken(); // consume '...'
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 21e960aa8173..9fd145dc2676 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -81,6 +81,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
CXX0XAttributeList Attr;
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
Attr = ParseCXX0XAttributes();
+ llvm::OwningPtr<AttributeList> AttrList(Attr.AttrList);
// 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),
@@ -102,13 +103,14 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
case tok::identifier:
if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
// identifier ':' statement
- return ParseLabeledStatement(Attr.AttrList);
+ return ParseLabeledStatement(AttrList.take());
}
// PASS THROUGH.
default: {
if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ AttrList.take(); //Passing 'Attr' to ParseDeclaration transfers ownership.
DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd,
Attr);
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
@@ -135,43 +137,43 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_case: // C99 6.8.1: labeled-statement
- return ParseCaseStatement(Attr.AttrList);
+ return ParseCaseStatement(AttrList.take());
case tok::kw_default: // C99 6.8.1: labeled-statement
- return ParseDefaultStatement(Attr.AttrList);
+ return ParseDefaultStatement(AttrList.take());
case tok::l_brace: // C99 6.8.2: compound-statement
- return ParseCompoundStatement(Attr.AttrList);
+ return ParseCompoundStatement(AttrList.take());
case tok::semi: // C99 6.8.3p3: expression[opt] ';'
return Actions.ActOnNullStmt(ConsumeToken());
case tok::kw_if: // C99 6.8.4.1: if-statement
- return ParseIfStatement(Attr.AttrList);
+ return ParseIfStatement(AttrList.take());
case tok::kw_switch: // C99 6.8.4.2: switch-statement
- return ParseSwitchStatement(Attr.AttrList);
+ return ParseSwitchStatement(AttrList.take());
case tok::kw_while: // C99 6.8.5.1: while-statement
- return ParseWhileStatement(Attr.AttrList);
+ return ParseWhileStatement(AttrList.take());
case tok::kw_do: // C99 6.8.5.2: do-statement
- Res = ParseDoStatement(Attr.AttrList);
+ Res = ParseDoStatement(AttrList.take());
SemiError = "do/while";
break;
case tok::kw_for: // C99 6.8.5.3: for-statement
- return ParseForStatement(Attr.AttrList);
+ return ParseForStatement(AttrList.take());
case tok::kw_goto: // C99 6.8.6.1: goto-statement
- Res = ParseGotoStatement(Attr.AttrList);
+ Res = ParseGotoStatement(AttrList.take());
SemiError = "goto";
break;
case tok::kw_continue: // C99 6.8.6.2: continue-statement
- Res = ParseContinueStatement(Attr.AttrList);
+ Res = ParseContinueStatement(AttrList.take());
SemiError = "continue";
break;
case tok::kw_break: // C99 6.8.6.3: break-statement
- Res = ParseBreakStatement(Attr.AttrList);
+ Res = ParseBreakStatement(AttrList.take());
SemiError = "break";
break;
case tok::kw_return: // C99 6.8.6.4: return-statement
- Res = ParseReturnStatement(Attr.AttrList);
+ Res = ParseReturnStatement(AttrList.take());
SemiError = "return";
break;
@@ -187,7 +189,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::kw_try: // C++ 15: try-block
- return ParseCXXTryBlock(Attr.AttrList);
+ return ParseCXXTryBlock(AttrList.take());
}
// If we reached this code, the statement must end in a semicolon.
@@ -215,6 +217,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
"Not an identifier!");
+ llvm::OwningPtr<AttributeList> AttrList(Attr);
Token IdentTok = Tok; // Save the whole token.
ConsumeToken(); // eat the identifier.
@@ -225,7 +228,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
// Read label attributes, if present.
if (Tok.is(tok::kw___attribute))
- Attr = addAttributeLists(Attr, ParseGNUAttributes());
+ AttrList.reset(addAttributeLists(AttrList.take(), ParseGNUAttributes()));
OwningStmtResult SubStmt(ParseStatement());
@@ -233,6 +236,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
if (SubStmt.isInvalid())
SubStmt = Actions.ActOnNullStmt(ColonLoc);
+ // FIXME: use attributes?
return Actions.ActOnLabelStmt(IdentTok.getLocation(),
IdentTok.getIdentifierInfo(),
ColonLoc, move(SubStmt));
@@ -246,6 +250,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
assert(Tok.is(tok::kw_case) && "Not a case stmt!");
// FIXME: Use attributes?
+ delete Attr;
// It is very very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
@@ -371,6 +376,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
//FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
@@ -427,6 +434,8 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr,
bool isStmtExpr) {
//FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
// Enter a scope to hold everything within the compound stmt. Compound
@@ -562,6 +571,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult,
///
Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
@@ -686,6 +697,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
/// [C++] 'switch' '(' condition ')' statement
Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
@@ -741,19 +754,19 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
// Read the body statement.
OwningStmtResult Body(ParseStatement());
- // Pop the body scope if needed.
+ // Pop the scopes.
InnerScope.Exit();
-
- if (Body.isInvalid()) {
- Body = Actions.ActOnNullStmt(Tok.getLocation());
- // FIXME: Remove the case statement list from the Switch statement.
- }
-
SwitchScope.Exit();
- if (Cond.isInvalid() && !CondVar.get())
+ if (Cond.isInvalid() && !CondVar.get()) {
+ Actions.ActOnSwitchBodyError(SwitchLoc, move(Switch), move(Body));
return StmtError();
+ }
+ if (Body.isInvalid())
+ // FIXME: Remove the case statement list from the Switch statement.
+ Body = Actions.ActOnNullStmt(Tok.getLocation());
+
return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body));
}
@@ -763,6 +776,8 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
/// [C++] 'while' '(' condition ')' statement
Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
SourceLocation WhileLoc = Tok.getLocation();
ConsumeToken(); // eat the 'while'.
@@ -836,6 +851,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
/// Note: this lets the caller parse the end ';'.
Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_do) && "Not a do stmt!");
SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
@@ -911,6 +928,8 @@ Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
@@ -1081,6 +1100,8 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
@@ -1115,6 +1136,8 @@ Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
}
@@ -1127,6 +1150,8 @@ Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
///
Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
return Actions.ActOnBreakStmt(BreakLoc, CurScope);
}
@@ -1136,6 +1161,8 @@ Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
/// 'return' expression[opt] ';'
Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) {
// FIXME: Use attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_return) && "Not a return stmt!");
SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
@@ -1171,7 +1198,6 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
Tok.isNot(tok::eof));
}
- llvm::SmallVector<std::string, 4> Names;
Token t;
t.setKind(tok::string_literal);
t.setLiteralData("\"FIXME: not done\"");
@@ -1181,7 +1207,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
- return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(),
+ return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, 0,
move_arg(Constraints), move_arg(Exprs),
move(AsmString), move_arg(Clobbers),
Tok.getLocation(), true);
@@ -1245,7 +1271,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
if (AsmString.isInvalid())
return StmtError();
- llvm::SmallVector<std::string, 4> Names;
+ llvm::SmallVector<IdentifierInfo *, 4> Names;
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
@@ -1336,9 +1362,9 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
///
//
// FIXME: Avoid unnecessary std::string trashing.
-bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
- llvm::SmallVectorImpl<ExprTy*> &Constraints,
- llvm::SmallVectorImpl<ExprTy*> &Exprs) {
+bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
+ llvm::SmallVectorImpl<ExprTy *> &Constraints,
+ llvm::SmallVectorImpl<ExprTy *> &Exprs) {
// 'asm-operands' isn't present?
if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
return false;
@@ -1357,10 +1383,10 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
IdentifierInfo *II = Tok.getIdentifierInfo();
ConsumeToken();
- Names.push_back(II->getName());
+ Names.push_back(II);
MatchRHSPunctuation(tok::r_square, Loc);
} else
- Names.push_back(std::string());
+ Names.push_back(0);
OwningExprResult Constraint(ParseAsmStringLiteral());
if (Constraint.isInvalid()) {
@@ -1448,6 +1474,8 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
///
Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) {
// FIXME: Add attributes?
+ delete Attr;
+
assert(Tok.is(tok::kw_try) && "Expected 'try'");
SourceLocation TryLoc = ConsumeToken();
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 797c1dfe3e6a..12f26bfcb94e 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -836,7 +836,7 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
Tok.setAnnotationValue(Type.isInvalid()? 0 : Type.get());
if (SS && SS->isNotEmpty()) // it was a C++ qualified type name.
Tok.setLocation(SS->getBeginLoc());
- Tok.setAnnotationEndLoc(TemplateId->TemplateNameLoc);
+ // End location stays the same
// Replace the template-id annotation token, and possible the scope-specifier
// that precedes it, with the typename annotation token.
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 51c56706bb59..6251a2f36754 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -672,6 +672,11 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
Parser::TPResult Parser::isCXXDeclarationSpecifier() {
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
+ // Check for need to substitute AltiVec __vector keyword
+ // for "vector" identifier.
+ if (TryAltiVecVectorToken())
+ return TPResult::True();
+ // Fall through.
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -750,6 +755,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___ptr64:
case tok::kw___forceinline:
return TPResult::True();
+
+ // AltiVec
+ case tok::kw___vector:
+ return TPResult::True();
case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
// We've already annotated a scope; try to annotate a type.
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index f2bc303acd69..30899c5dddb5 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -346,6 +346,11 @@ void Parser::Initialize() {
}
Ident_super = &PP.getIdentifierTable().get("super");
+
+ if (getLang().AltiVec) {
+ Ident_vector = &PP.getIdentifierTable().get("vector");
+ Ident_pixel = &PP.getIdentifierTable().get("pixel");
+ }
}
/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
@@ -588,7 +593,6 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
if (Tok.is(tok::string_literal) && getLang().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
- DS.abort();
DeclPtrTy TheDecl = ParseLinkage(DS, Declarator::FileContext);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
@@ -738,11 +742,11 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Handle the full declarator list.
while (1) {
- Action::AttrTy *AttrList;
// If attributes are present, parse them.
+ llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
// FIXME: attach attributes too.
- AttrList = ParseGNUAttributes();
+ AttrList.reset(ParseGNUAttributes());
// Ask the actions module to compute the type for this declarator.
Action::DeclPtrTy Param =
@@ -835,6 +839,16 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
assert(Tok.is(tok::kw_asm) && "Not an asm!");
SourceLocation Loc = ConsumeToken();
+ if (Tok.is(tok::kw_volatile)) {
+ // Remove from the end of 'asm' to the end of 'volatile'.
+ SourceRange RemovalRange(PP.getLocForEndOfToken(Loc),
+ PP.getLocForEndOfToken(Tok.getLocation()));
+
+ Diag(Tok, diag::warn_file_asm_volatile)
+ << CodeModificationHint::CreateRemoval(RemovalRange);
+ ConsumeToken();
+ }
+
if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "asm";
return ExprError();
@@ -930,9 +944,10 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
return false;
}
+ SourceLocation EndLoc = Tok.getLastLoc();
Tok.setKind(tok::annot_typename);
Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get());
- Tok.setAnnotationEndLoc(Tok.getLocation());
+ Tok.setAnnotationEndLoc(EndLoc);
Tok.setLocation(TypenameLoc);
PP.AnnotateCachedTokens(Tok);
return true;
diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile
index 61fdf4006f86..a6d3f7725689 100644
--- a/lib/Rewrite/Makefile
+++ b/lib/Rewrite/Makefile
@@ -14,7 +14,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangRewrite
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index bff47519a743..b09526e097b6 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -14,8 +14,6 @@
#include "IdentifierResolver.h"
#include "clang/Basic/LangOptions.h"
-#include <list>
-#include <vector>
using namespace clang;
@@ -27,14 +25,31 @@ using namespace clang;
/// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each
/// individual IdDeclInfo to heap.
class IdentifierResolver::IdDeclInfoMap {
- static const unsigned int VECTOR_SIZE = 512;
- // Holds vectors of IdDeclInfos that serve as 'pools'.
- // New vectors are added when the current one is full.
- std::list< std::vector<IdDeclInfo> > IDIVecs;
+ static const unsigned int POOL_SIZE = 512;
+
+ /// We use our own linked-list implementation because it is sadly
+ /// impossible to add something to a pre-C++0x STL container without
+ /// a completely unnecessary copy.
+ struct IdDeclInfoPool {
+ IdDeclInfoPool(IdDeclInfoPool *Next) : Next(Next) {}
+
+ IdDeclInfoPool *Next;
+ IdDeclInfo Pool[POOL_SIZE];
+ };
+
+ IdDeclInfoPool *CurPool;
unsigned int CurIndex;
public:
- IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {}
+ IdDeclInfoMap() : CurPool(0), CurIndex(POOL_SIZE) {}
+
+ ~IdDeclInfoMap() {
+ IdDeclInfoPool *Cur = CurPool;
+ while (IdDeclInfoPool *P = Cur) {
+ Cur = Cur->Next;
+ delete P;
+ }
+ }
/// Returns the IdDeclInfo associated to the DeclarationName.
/// It creates a new IdDeclInfo if one was not created before for this id.
@@ -235,14 +250,11 @@ IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) {
if (Ptr) return *toIdDeclInfo(Ptr);
- if (CurIndex == VECTOR_SIZE) {
- // Add a IdDeclInfo vector 'pool'
- IDIVecs.push_back(std::vector<IdDeclInfo>());
- // Fill the vector
- IDIVecs.back().resize(VECTOR_SIZE);
+ if (CurIndex == POOL_SIZE) {
+ CurPool = new IdDeclInfoPool(CurPool);
CurIndex = 0;
}
- IdDeclInfo *IDI = &IDIVecs.back()[CurIndex];
+ IdDeclInfo *IDI = &CurPool->Pool[CurIndex];
Name.setFETokenInfo(reinterpret_cast<void*>(
reinterpret_cast<uintptr_t>(IDI) | 0x1)
);
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index f4cea2e88a6d..6b2694591f52 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -224,6 +224,10 @@ public:
return Ambiguity;
}
+ const UnresolvedSetImpl &asUnresolvedSet() const {
+ return Decls;
+ }
+
iterator begin() const { return iterator(Decls.begin()); }
iterator end() const { return iterator(Decls.end()); }
@@ -499,7 +503,7 @@ private:
if (isAmbiguous())
SemaRef.DiagnoseAmbiguousLookup(*this);
else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
- SemaRef.CheckAccess(*this);
+ SemaRef.CheckLookupAccess(*this);
}
void setAmbiguous(AmbiguityKind AK) {
@@ -583,6 +587,44 @@ private:
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
bool InBaseClass) = 0;
};
+
+/// \brief A class for storing results from argument-dependent lookup.
+class ADLResult {
+private:
+ /// A map from canonical decls to the 'most recent' decl.
+ llvm::DenseMap<NamedDecl*, NamedDecl*> Decls;
+
+public:
+ /// Adds a new ADL candidate to this map.
+ void insert(NamedDecl *D);
+
+ /// Removes any data associated with a given decl.
+ void erase(NamedDecl *D) {
+ Decls.erase(cast<NamedDecl>(D->getCanonicalDecl()));
+ }
+
+ class iterator {
+ typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator;
+ inner_iterator iter;
+
+ friend class ADLResult;
+ iterator(const inner_iterator &iter) : iter(iter) {}
+ public:
+ iterator() {}
+
+ iterator &operator++() { ++iter; return *this; }
+ iterator operator++(int) { return iterator(iter++); }
+
+ NamedDecl *operator*() const { return iter->second; }
+
+ bool operator==(const iterator &other) const { return iter == other.iter; }
+ bool operator!=(const iterator &other) const { return iter != other.iter; }
+ };
+
+ iterator begin() { return iterator(Decls.begin()); }
+ iterator end() { return iterator(Decls.end()); }
+};
+
}
#endif
diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile
index 0f4c7965dca2..158f1af213d4 100644
--- a/lib/Sema/Makefile
+++ b/lib/Sema/Makefile
@@ -15,7 +15,6 @@
LEVEL = ../../../..
LIBRARYNAME := clangSema
BUILD_ARCHIVE = 1
-CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 171101bb96de..38c842eede57 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -15,260 +15,18 @@
#include "Sema.h"
#include "TargetAttributesSema.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/APFloat.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
-
-/// Determines whether we should have an a.k.a. clause when
-/// pretty-printing a type. There are three main criteria:
-///
-/// 1) Some types provide very minimal sugar that doesn't impede the
-/// user's understanding --- for example, elaborated type
-/// specifiers. If this is all the sugar we see, we don't want an
-/// a.k.a. clause.
-/// 2) Some types are technically sugared but are much more familiar
-/// when seen in their sugared form --- for example, va_list,
-/// vector types, and the magic Objective C types. We don't
-/// want to desugar these, even if we do produce an a.k.a. clause.
-/// 3) Some types may have already been desugared previously in this diagnostic.
-/// if this is the case, doing another "aka" would just be clutter.
-///
-static bool ShouldAKA(ASTContext &Context, QualType QT,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- QualType &DesugaredQT) {
- QualType InputTy = QT;
-
- bool AKA = false;
- QualifierCollector Qc;
-
- while (true) {
- const Type *Ty = Qc.strip(QT);
-
- // Don't aka just because we saw an elaborated type...
- if (isa<ElaboratedType>(Ty)) {
- QT = cast<ElaboratedType>(Ty)->desugar();
- continue;
- }
-
- // ...or a qualified name type...
- if (isa<QualifiedNameType>(Ty)) {
- QT = cast<QualifiedNameType>(Ty)->desugar();
- continue;
- }
-
- // ...or a substituted template type parameter.
- if (isa<SubstTemplateTypeParmType>(Ty)) {
- QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
- continue;
- }
-
- // Don't desugar template specializations.
- if (isa<TemplateSpecializationType>(Ty))
- break;
-
- // Don't desugar magic Objective-C types.
- if (QualType(Ty,0) == Context.getObjCIdType() ||
- QualType(Ty,0) == Context.getObjCClassType() ||
- QualType(Ty,0) == Context.getObjCSelType() ||
- QualType(Ty,0) == Context.getObjCProtoType())
- break;
-
- // Don't desugar va_list.
- if (QualType(Ty,0) == Context.getBuiltinVaListType())
- break;
-
- // Otherwise, do a single-step desugar.
- QualType Underlying;
- bool IsSugar = false;
- switch (Ty->getTypeClass()) {
-#define ABSTRACT_TYPE(Class, Base)
-#define TYPE(Class, Base) \
- case Type::Class: { \
- const Class##Type *CTy = cast<Class##Type>(Ty); \
- if (CTy->isSugared()) { \
- IsSugar = true; \
- Underlying = CTy->desugar(); \
- } \
- break; \
- }
-#include "clang/AST/TypeNodes.def"
- }
-
- // If it wasn't sugared, we're done.
- if (!IsSugar)
- break;
-
- // If the desugared type is a vector type, we don't want to expand
- // it, it will turn into an attribute mess. People want their "vec4".
- if (isa<VectorType>(Underlying))
- break;
-
- // Don't desugar through the primary typedef of an anonymous type.
- if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
- if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
- cast<TypedefType>(QT)->getDecl())
- break;
-
- // Otherwise, we're tearing through something opaque; note that
- // we'll eventually need an a.k.a. clause and keep going.
- AKA = true;
- QT = Underlying;
- continue;
- }
-
- // If we never tore through opaque sugar, don't print aka.
- if (!AKA) return false;
-
- // If we did, check to see if we already desugared this type in this
- // diagnostic. If so, don't do it again.
- for (unsigned i = 0; i != NumPrevArgs; ++i) {
- // TODO: Handle ak_declcontext case.
- if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
- void *Ptr = (void*)PrevArgs[i].second;
- QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
- if (PrevTy == InputTy)
- return false;
- }
- }
-
- DesugaredQT = Qc.apply(QT);
- return true;
-}
-
-/// \brief Convert the given type to a string suitable for printing as part of
-/// a diagnostic.
-///
-/// \param Context the context in which the type was allocated
-/// \param Ty the type to print
-static std::string
-ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs) {
- // FIXME: Playing with std::string is really slow.
- std::string S = Ty.getAsString(Context.PrintingPolicy);
-
- // Consider producing an a.k.a. clause if removing all the direct
- // sugar gives us something "significantly different".
-
- QualType DesugaredTy;
- if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) {
- S = "'"+S+"' (aka '";
- S += DesugaredTy.getAsString(Context.PrintingPolicy);
- S += "')";
- return S;
- }
-
- S = "'" + S + "'";
- return S;
-}
-/// ConvertQualTypeToStringFn - This function is used to pretty print the
-/// specified QualType as a string in diagnostics.
-static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
- const char *Modifier, unsigned ModLen,
- const char *Argument, unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
- void *Cookie) {
- ASTContext &Context = *static_cast<ASTContext*>(Cookie);
-
- std::string S;
- bool NeedQuotes = true;
-
- switch (Kind) {
- default: assert(0 && "unknown ArgumentKind");
- case Diagnostic::ak_qualtype: {
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for QualType argument");
-
- QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
- NeedQuotes = false;
- break;
- }
- case Diagnostic::ak_declarationname: {
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- S = N.getAsString();
-
- if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
- S = '+' + S;
- else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
- S = '-' + S;
- else
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for DeclarationName argument");
- break;
- }
- case Diagnostic::ak_nameddecl: {
- bool Qualified;
- if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
- Qualified = true;
- else {
- assert(ModLen == 0 && ArgLen == 0 &&
- "Invalid modifier for NamedDecl* argument");
- Qualified = false;
- }
- reinterpret_cast<NamedDecl*>(Val)->
- getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
- break;
- }
- case Diagnostic::ak_nestednamespec: {
- llvm::raw_string_ostream OS(S);
- reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
- Context.PrintingPolicy);
- NeedQuotes = false;
- break;
- }
- case Diagnostic::ak_declcontext: {
- DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
- assert(DC && "Should never have a null declaration context");
-
- if (DC->isTranslationUnit()) {
- // FIXME: Get these strings from some localized place
- if (Context.getLangOptions().CPlusPlus)
- S = "the global namespace";
- else
- S = "the global scope";
- } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
- S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs);
- } else {
- // FIXME: Get these strings from some localized place
- NamedDecl *ND = cast<NamedDecl>(DC);
- if (isa<NamespaceDecl>(ND))
- S += "namespace ";
- else if (isa<ObjCMethodDecl>(ND))
- S += "method ";
- else if (isa<FunctionDecl>(ND))
- S += "function ";
-
- S += "'";
- ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
- S += "'";
- }
- NeedQuotes = false;
- break;
- }
- }
-
- if (NeedQuotes)
- Output.push_back('\'');
-
- Output.append(S.begin(), S.end());
-
- if (NeedQuotes)
- Output.push_back('\'');
-}
-
-
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
@@ -363,14 +121,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), NonInstantiationEntries(0),
- CurrentInstantiationScope(0)
+ CurrentInstantiationScope(0), TyposCorrected(0)
{
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
- PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
+ PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ &Context);
ExprEvalContexts.push_back(
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
@@ -426,6 +185,12 @@ void Sema::DeleteStmt(StmtTy *S) {
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
+ // Remove functions that turned out to be used.
+ UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(),
+ UnusedStaticFuncs.end(),
+ std::mem_fun(&FunctionDecl::isUsed)),
+ UnusedStaticFuncs.end());
+
while (1) {
// C++: Perform implicit template instantiations.
//
@@ -472,12 +237,14 @@ void Sema::ActOnEndOfTranslationUnit() {
// translation unit contains a file scope declaration of that
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
- for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
- VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
-
- // If the tentative definition was completed, it will be in the list, but
- // not the map.
- if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
+ llvm::SmallSet<VarDecl *, 32> Seen;
+ for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) {
+ VarDecl *VD = TentativeDefinitions[i]->getActingDefinition();
+
+ // If the tentative definition was completed, getActingDefinition() returns
+ // null. If we've already seen this variable before, insert()'s second
+ // return value is false.
+ if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD))
continue;
if (const IncompleteArrayType *ArrayT
@@ -504,6 +271,15 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteTentativeDefinition(VD);
}
+
+ // Output warning for unused functions.
+ for (std::vector<FunctionDecl*>::iterator
+ F = UnusedStaticFuncs.begin(),
+ FEnd = UnusedStaticFuncs.end();
+ F != FEnd;
+ ++F)
+ Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName();
+
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 06e9e3ae9e64..3c7492af6108 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -60,6 +60,7 @@ namespace clang {
class CallExpr;
class DeclRefExpr;
class UnresolvedLookupExpr;
+ class UnresolvedMemberExpr;
class VarDecl;
class ParmVarDecl;
class TypedefDecl;
@@ -95,6 +96,7 @@ namespace clang {
class ObjCPropertyDecl;
class ObjCContainerDecl;
class FunctionProtoType;
+ class CXXBasePath;
class CXXBasePaths;
class CXXTemporary;
class LookupResult;
@@ -103,6 +105,7 @@ namespace clang {
class InitializationSequence;
class VisibleDeclConsumer;
class TargetAttributesSema;
+ class ADLResult;
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
@@ -150,7 +153,7 @@ class LocInfoType : public Type {
enum {
// The last number that can fit in Type's TC.
// Avoids conflict with an existing Type class.
- LocInfo = (1 << TypeClassBitSize) - 1
+ LocInfo = Type::TypeLast + 1
};
TypeSourceInfo *DeclInfo;
@@ -270,18 +273,124 @@ public:
/// not visible.
llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
- /// \brief The set of tentative declarations seen so far in this
- /// translation unit for which no definition has been seen.
- ///
- /// The tentative declarations are indexed by the name of the
- /// declaration, and only the most recent tentative declaration for
- /// a given variable will be recorded here.
- llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
- std::vector<DeclarationName> TentativeDefinitionList;
+ /// \brief All the tentative definitions encountered in the TU.
+ std::vector<VarDecl *> TentativeDefinitions;
+
+ /// \brief The set of static functions seen so far that have not been used.
+ std::vector<FunctionDecl*> UnusedStaticFuncs;
+
+ /// An enum describing the kind of diagnostics to use when checking
+ /// access.
+ enum AccessDiagnosticsKind {
+ /// Suppress diagnostics.
+ ADK_quiet,
+
+ /// Use the normal diagnostics.
+ ADK_normal,
+
+ /// Use the diagnostics appropriate for checking a covariant
+ /// return type.
+ ADK_covariance
+ };
+
+ class AccessedEntity {
+ public:
+ enum Kind {
+ /// A member declaration found through lookup. The target is the
+ /// member.
+ Member,
+
+ /// A base-to-derived conversion. The target is the base class.
+ BaseToDerivedConversion,
+
+ /// A derived-to-base conversion. The target is the base class.
+ DerivedToBaseConversion
+ };
+
+ bool isMemberAccess() const { return K == Member; }
+
+ static AccessedEntity makeMember(CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ NamedDecl *Target) {
+ AccessedEntity E;
+ E.K = Member;
+ E.Access = Access;
+ E.Target = Target;
+ E.NamingClass = NamingClass;
+ return E;
+ }
+
+ static AccessedEntity makeBaseClass(bool BaseToDerived,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access) {
+ AccessedEntity E;
+ E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion;
+ E.Access = Access;
+ E.Target = BaseClass;
+ E.NamingClass = DerivedClass;
+ return E;
+ }
+
+ Kind getKind() const { return Kind(K); }
+ AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
+
+ // These apply to member decls...
+ NamedDecl *getTargetDecl() const { return Target; }
+ CXXRecordDecl *getNamingClass() const { return NamingClass; }
+
+ // ...and these apply to hierarchy conversions.
+ CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
+ CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+
+ private:
+ unsigned K : 2;
+ unsigned Access : 2;
+ NamedDecl *Target;
+ CXXRecordDecl *NamingClass;
+ };
- /// \brief The collection of delayed deprecation warnings.
- llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8>
- DelayedDeprecationWarnings;
+ struct DelayedDiagnostic {
+ enum DDKind { Deprecation, Access };
+
+ unsigned char Kind; // actually a DDKind
+ bool Triggered;
+
+ SourceLocation Loc;
+
+ union {
+ /// Deprecation.
+ struct { NamedDecl *Decl; } DeprecationData;
+
+ /// Access control.
+ AccessedEntity AccessData;
+ };
+
+ static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
+ NamedDecl *D) {
+ DelayedDiagnostic DD;
+ DD.Kind = Deprecation;
+ DD.Triggered = false;
+ DD.Loc = Loc;
+ DD.DeprecationData.Decl = D;
+ return DD;
+ }
+
+ static DelayedDiagnostic makeAccess(SourceLocation Loc,
+ const AccessedEntity &Entity) {
+ DelayedDiagnostic DD;
+ DD.Kind = Access;
+ DD.Triggered = false;
+ DD.Loc = Loc;
+ DD.AccessData = Entity;
+ return DD;
+ }
+
+ };
+
+ /// \brief The stack of diagnostics that were delayed due to being
+ /// produced during the parsing of a declaration.
+ llvm::SmallVector<DelayedDiagnostic, 8> DelayedDiagnostics;
/// \brief The depth of the current ParsingDeclaration stack.
/// If nonzero, we are currently parsing a declaration (and
@@ -517,8 +626,8 @@ public:
//===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp.
//
+
QualType adjustParameterType(QualType T);
- void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
QualType BuildPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
@@ -548,13 +657,15 @@ public:
static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0);
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
+ bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
bool CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc);
bool CheckEquivalentExceptionSpec(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc);
+ const FunctionProtoType *New, SourceLocation NewLoc,
+ bool *MissingEmptyExceptionSpecification = 0);
bool CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Superset, SourceLocation SuperLoc,
@@ -634,6 +745,7 @@ public:
bool &OverloadableAttrRequired);
void CheckMain(FunctionDecl *FD);
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
+ virtual void ActOnObjCCatchParam(DeclPtrTy D);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
ExprArg defarg);
@@ -950,31 +1062,38 @@ public:
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
// TODO: make this is a typesafe union.
typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet;
-
- typedef llvm::SmallPtrSet<AnyFunctionDecl, 16> FunctionSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
+ void AddOverloadCandidate(NamedDecl *Function,
+ AccessSpecifier Access,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet);
+
void AddOverloadCandidate(FunctionDecl *Function,
+ AccessSpecifier Access,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false,
bool PartialOverloading = false);
- void AddFunctionCandidates(const FunctionSet &Functions,
+ void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
- void AddMethodCandidate(NamedDecl *Decl,
- QualType ObjectType, Expr **Args, unsigned NumArgs,
+ void AddMethodCandidate(NamedDecl *Decl, AccessSpecifier Access,
+ QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversion = false,
bool ForceRValue = false);
- void AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
- QualType ObjectType, Expr **Args, unsigned NumArgs,
+ void AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
+ CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
@@ -983,20 +1102,24 @@ public:
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
QualType ObjectTy, Expr **Args, unsigned NumArgs,
@@ -1021,12 +1144,14 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
+ bool Operator,
Expr **Args, unsigned NumArgs,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false);
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
- const OverloadCandidate& Cand2);
+ const OverloadCandidate& Cand2,
+ SourceLocation Loc);
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
@@ -1072,12 +1197,12 @@ public:
OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned Opc,
- FunctionSet &Functions,
+ const UnresolvedSetImpl &Fns,
ExprArg input);
OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned Opc,
- FunctionSet &Functions,
+ const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS);
OwningExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
@@ -1217,16 +1342,15 @@ public:
bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
-
ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
- FunctionSet &Functions);
+ UnresolvedSetImpl &Functions);
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- FunctionSet &Functions);
+ ADLResult &Functions);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer);
@@ -1302,6 +1426,14 @@ public:
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap);
+ /// LookupPropertyDecl - Looks up a property in the current class and all
+ /// its protocols.
+ ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ IdentifierInfo *II);
+
+ ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
+ IdentifierInfo *NameII);
+
/// AtomicPropertySetterGetterRules - This routine enforces the rule (via
/// warning) when atomic property has one but not the other user-declared
/// setter or getter.
@@ -1373,6 +1505,8 @@ public:
SourceLocation ElseLoc, StmtArg ElseVal);
virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
DeclPtrTy CondVar);
+ virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
+ StmtArg Body);
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
StmtArg Switch, StmtArg Body);
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
@@ -1416,7 +1550,7 @@ public:
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
- std::string *Names,
+ IdentifierInfo **Names,
MultiExprArg Constraints,
MultiExprArg Exprs,
ExprArg AsmString,
@@ -1466,6 +1600,8 @@ public:
void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D);
void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc);
+ void HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, Decl *Ctx);
+
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
@@ -1770,7 +1906,8 @@ public:
// Act on C++ namespaces
virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
IdentifierInfo *Ident,
- SourceLocation LBrace);
+ SourceLocation LBrace,
+ AttributeList *AttrList);
virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace);
virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
@@ -1847,7 +1984,8 @@ public:
QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg Exprs,
- bool RequiresZeroInit = false);
+ bool RequiresZeroInit = false,
+ bool BaseInitialization = false);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
@@ -1856,13 +1994,8 @@ public:
CXXConstructorDecl *Constructor,
bool Elidable,
MultiExprArg Exprs,
- bool RequiresZeroInit = false);
-
- OwningExprResult BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
- QualType writtenTy,
- SourceLocation tyBeginLoc,
- MultiExprArg Args,
- SourceLocation rParenLoc);
+ bool RequiresZeroInit = false,
+ bool BaseInitialization = false);
OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc,
QualType Ty,
@@ -1878,7 +2011,7 @@ public:
/// FinalizeVarWithDestructor - Prepare for calling destructor on the
/// constructed variable.
- void FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType);
+ void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType);
/// DefineImplicitDefaultConstructor - Checks for feasibility of
/// defining this constructor as the default constructor.
@@ -1917,14 +2050,6 @@ public:
Expr **Args, unsigned NumArgs,
SourceLocation Loc,
InitializationKind Kind);
-
- CXXConstructorDecl *
- PerformInitializationByConstructor(QualType ClassType,
- MultiExprArg ArgsPtr,
- SourceLocation Loc, SourceRange Range,
- DeclarationName InitEntity,
- InitializationKind Kind,
- ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
@@ -2218,9 +2343,10 @@ public:
CXXRecordDecl *ClassDecl);
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor);
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ bool IsImplicitConstructor,
+ bool AnyErrors);
/// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl,
/// mark all its non-trivial member and base destructor declarations
@@ -2252,7 +2378,8 @@ public:
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits);
+ MemInitTy **MemInits, unsigned NumMemInits,
+ bool AnyErrors);
void CheckCompletedCXXClass(CXXRecordDecl *Record);
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2326,7 +2453,7 @@ public:
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
+ AccessDiagnosticsKind ADK,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name);
@@ -2353,22 +2480,43 @@ public:
// C++ Access Control
//
+ enum AccessResult {
+ AR_accessible,
+ AR_inaccessible,
+ AR_dependent,
+ AR_delayed
+ };
+
bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS);
- const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base,
- CXXBasePaths &Paths,
- bool NoPrivileges = false);
-
- void CheckAccess(const LookupResult &R);
- bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
-
- bool CheckBaseClassAccess(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- CXXBasePaths& Paths, SourceLocation AccessLoc,
- DeclarationName Name);
-
+ AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckConstructorAccess(SourceLocation Loc,
+ CXXConstructorDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckDestructorAccess(SourceLocation Loc,
+ const RecordType *Record);
+ AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
+ Expr *ObjectExpr,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
+ bool IsBaseToDerived,
+ QualType Base, QualType Derived,
+ const CXXBasePath &Path,
+ bool ForceCheck = false,
+ bool ForceUnprivileged = false,
+ AccessDiagnosticsKind ADK = ADK_normal);
+
+ void CheckLookupAccess(const LookupResult &R);
+
+ void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx);
enum AbstractDiagSelID {
AbstractNone = -1,
@@ -2758,17 +2906,28 @@ public:
///
TemplateArgumentList *Deduced;
+ /// \brief The source location at which template argument
+ /// deduction is occurring.
+ SourceLocation Loc;
+
// do not implement these
TemplateDeductionInfo(const TemplateDeductionInfo&);
TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
public:
- TemplateDeductionInfo(ASTContext &Context) : Context(Context), Deduced(0) { }
+ TemplateDeductionInfo(ASTContext &Context, SourceLocation Loc)
+ : Context(Context), Deduced(0), Loc(Loc) { }
~TemplateDeductionInfo() {
// FIXME: if (Deduced) Deduced->Destroy(Context);
}
+ /// \brief Returns the location at which template argument is
+ /// occuring.
+ SourceLocation getLocation() const {
+ return Loc;
+ }
+
/// \brief Take ownership of the deduced template argument list.
TemplateArgumentList *take() {
TemplateArgumentList *Result = Deduced;
@@ -2866,20 +3025,21 @@ public:
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
+ SourceLocation Loc,
TemplatePartialOrderingContext TPOC);
- FunctionDecl *getMostSpecialized(FunctionDecl **Specializations,
- unsigned NumSpecializations,
- TemplatePartialOrderingContext TPOC,
- SourceLocation Loc,
- const PartialDiagnostic &NoneDiag,
- const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &CandidateDiag,
- unsigned *Index = 0);
+ UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin,
+ UnresolvedSetIterator SEnd,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag);
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
- ClassTemplatePartialSpecializationDecl *PS2);
+ ClassTemplatePartialSpecializationDecl *PS2,
+ SourceLocation Loc);
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
@@ -2893,7 +3053,8 @@ public:
//
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
- const TemplateArgumentList *Innermost = 0);
+ const TemplateArgumentList *Innermost = 0,
+ bool RelativeToPrimary = false);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
@@ -3243,6 +3404,9 @@ public:
/// variables.
LocalInstantiationScope *CurrentInstantiationScope;
+ /// \brief The number of typos corrected by CorrectTypo.
+ unsigned TyposCorrected;
+
/// \brief An entity for which implicit template instantiation is required.
///
/// The source location associated with the declaration is the first place in
@@ -3550,6 +3714,11 @@ public:
// to their respective pointers (C99 6.3.2.1).
void DefaultFunctionArrayConversion(Expr *&expr);
+ // DefaultFunctionArrayLvalueConversion - converts functions and
+ // arrays to their respective pointers and performs the
+ // lvalue-to-rvalue conversion.
+ void DefaultFunctionArrayLvalueConversion(Expr *&expr);
+
// 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.
@@ -3944,12 +4113,15 @@ public:
//===--------------------------------------------------------------------===//
// Extra semantic analysis beyond the C type system
+
+public:
+ SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
+ unsigned ByteNo) const;
+
private:
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
- SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
- unsigned ByteNo) const;
bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall);
bool CheckObjCString(Expr *Arg);
@@ -3957,7 +4129,7 @@ private:
CallExpr *TheCall);
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
- bool SemaBuiltinUnaryFP(CallExpr *TheCall);
+ bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg=1);
bool SemaBuiltinStackAddress(CallExpr *TheCall);
public:
@@ -3987,7 +4159,6 @@ private:
const PartialDiagnostic &PD,
bool Equality = false);
void CheckImplicitConversion(Expr *E, QualType Target);
-
};
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 51f9e300ef90..eca8bb4c2a9b 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -16,6 +16,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+
using namespace clang;
/// SetMemberAccessSpecifier - Set the access specifier of a member.
@@ -47,192 +49,500 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
return false;
}
-/// Find a class on the derivation path between Derived and Base that is
-/// inaccessible. If @p NoPrivileges is true, special access rights (members
-/// and friends) are not considered.
-const CXXBaseSpecifier *Sema::FindInaccessibleBase(
- QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
- Base = Context.getCanonicalType(Base).getUnqualifiedType();
- assert(!Paths.isAmbiguous(Base) &&
- "Can't check base class access if set of paths is ambiguous");
- assert(Paths.isRecordingPaths() &&
- "Can't check base class access without recorded paths");
-
-
- const CXXBaseSpecifier *InaccessibleBase = 0;
-
- const CXXRecordDecl *CurrentClassDecl = 0;
- if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
- CurrentClassDecl = MD->getParent();
-
- for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
- Path != PathsEnd; ++Path) {
-
- bool FoundInaccessibleBase = false;
-
- for (CXXBasePath::const_iterator Element = Path->begin(),
- ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
- const CXXBaseSpecifier *Base = Element->Base;
-
- switch (Base->getAccessSpecifier()) {
- default:
- assert(0 && "invalid access specifier");
- case AS_public:
- // Nothing to do.
- break;
- case AS_private:
- // FIXME: Check if the current function/class is a friend.
- if (NoPrivileges || CurrentClassDecl != Element->Class)
- FoundInaccessibleBase = true;
- break;
- case AS_protected:
- // FIXME: Implement
- break;
- }
+namespace {
+struct EffectiveContext {
+ EffectiveContext() : Record(0), Function(0) {}
+
+ explicit EffectiveContext(DeclContext *DC) {
+ if (isa<FunctionDecl>(DC)) {
+ Function = cast<FunctionDecl>(DC);
+ DC = Function->getDeclContext();
+ } else
+ Function = 0;
+
+ if (isa<CXXRecordDecl>(DC))
+ Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ else
+ Record = 0;
+ }
+
+ bool isClass(const CXXRecordDecl *R) const {
+ return R->getCanonicalDecl() == Record;
+ }
+
+ CXXRecordDecl *Record;
+ FunctionDecl *Function;
+};
+}
+
+static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ while (DeclaringClass->isAnonymousStructOrUnion())
+ DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
+ return DeclaringClass;
+}
+
+static Sema::AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
+ if (EC.isClass(Class))
+ return Sema::AR_accessible;
+
+ // FIXME: implement
+ return Sema::AR_inaccessible;
+}
- if (FoundInaccessibleBase) {
- InaccessibleBase = Base;
- break;
+/// Finds the best path from the naming class to the declaring class,
+/// taking friend declarations into account.
+///
+/// \return null if friendship is dependent
+static CXXBasePath *FindBestPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *Derived,
+ CXXRecordDecl *Base,
+ CXXBasePaths &Paths) {
+ // Derive the paths to the desired base.
+ bool isDerived = Derived->isDerivedFrom(Base, Paths);
+ assert(isDerived && "derived class not actually derived from base");
+ (void) isDerived;
+
+ CXXBasePath *BestPath = 0;
+
+ // Derive the friend-modified access along each path.
+ for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
+ PI != PE; ++PI) {
+
+ // Walk through the path backwards.
+ AccessSpecifier PathAccess = AS_public;
+ CXXBasePath::iterator I = PI->end(), E = PI->begin();
+ while (I != E) {
+ --I;
+
+ AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
+ if (BaseAccess != AS_public) {
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_accessible: BaseAccess = AS_public; break;
+ case Sema::AR_dependent: return 0;
+ case Sema::AR_delayed:
+ llvm_unreachable("friend resolution is never delayed"); break;
+ }
}
+
+ PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
}
- if (!FoundInaccessibleBase) {
- // We found a path to the base, our work here is done.
- return 0;
+ // Note that we modify the path's Access field to the
+ // friend-modified access.
+ if (BestPath == 0 || PathAccess < BestPath->Access) {
+ BestPath = &*PI;
+ BestPath->Access = PathAccess;
}
}
- assert(InaccessibleBase && "no path found, but no inaccessible base");
- return InaccessibleBase;
+ return BestPath;
}
-/// CheckBaseClassAccess - Check that a derived class can access its base class
-/// and report an error if it can't. [class.access.base]
-bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- CXXBasePaths &Paths, SourceLocation AccessLoc,
- DeclarationName Name) {
+/// Diagnose the path which caused the given declaration or base class
+/// to become inaccessible.
+static void DiagnoseAccessPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ CXXRecordDecl *DeclaringClass,
+ NamedDecl *D, AccessSpecifier Access) {
+ // Easy case: the decl's natural access determined its path access.
+ // We have to check against AS_private here in case Access is AS_none,
+ // indicating a non-public member of a private base class.
+ //
+ // DependentFriend should be impossible here.
+ if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_inaccessible: {
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (Access == AS_protected)
+ << /*FIXME: not implicitly*/ 0;
+ return;
+ }
- if (!getLangOptions().AccessControl)
- return false;
- const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
- Derived, Base, Paths);
+ case Sema::AR_accessible: break;
- if (InaccessibleBase) {
- Diag(AccessLoc, InaccessibleBaseID)
- << Derived << Base << Name;
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent/delayed not allowed");
+ return;
+ }
+ }
- AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
+ CXXBasePaths Paths;
+ CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths);
- // If there's no written access specifier, then the inheritance specifier
- // is implicitly private.
- if (AS == AS_none)
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_implicitly_private_here);
- else
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_specifier_here) << AS;
+ CXXBasePath::iterator I = Path.end(), E = Path.begin();
+ while (I != E) {
+ --I;
- return true;
+ const CXXBaseSpecifier *BS = I->Base;
+ AccessSpecifier BaseAccess = BS->getAccessSpecifier();
+
+ // If this is public inheritance, or the derived class is a friend,
+ // skip this step.
+ if (BaseAccess == AS_public)
+ continue;
+
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_accessible: continue;
+ case Sema::AR_inaccessible: break;
+
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent friendship, should not be diagnosing");
+ }
+
+ // Check whether this base specifier is the tighest point
+ // constraining access. We have to check against AS_private for
+ // the same reasons as above.
+ if (BaseAccess == AS_private || BaseAccess >= Access) {
+
+ // We're constrained by inheritance, but we want to say
+ // "declared private here" if we're diagnosing a hierarchy
+ // conversion and this is the final step.
+ unsigned diagnostic;
+ if (D) diagnostic = diag::note_access_constrained_by_path;
+ else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
+ else diagnostic = diag::note_access_constrained_by_path;
+
+ S.Diag(BS->getSourceRange().getBegin(), diagnostic)
+ << BS->getSourceRange()
+ << (BaseAccess == AS_protected)
+ << (BS->getAccessSpecifierAsWritten() == AS_none);
+ return;
+ }
}
- return false;
+ llvm_unreachable("access not apparently constrained by path");
}
-/// Diagnose the path which caused the given declaration to become
-/// inaccessible.
-static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- // Easy case: the decl's natural access determined its path access.
- if (Access == D->getAccess() || D->getAccess() == AS_private) {
- S.Diag(D->getLocation(), diag::note_access_natural)
- << (unsigned) (Access == AS_protected);
- return;
+/// Diagnose an inaccessible class member.
+static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity) {
+ NamedDecl *D = Entity.getTargetDecl();
+ CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+
+ if (isa<CXXConstructorDecl>(D)) {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
+ : diag::err_access_ctor_private);
+ S.Diag(Loc, DiagID)
+ << S.Context.getTypeDeclType(DeclaringClass);
+ } else {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
+ : diag::err_access_private);
+ S.Diag(Loc, DiagID)
+ << D->getDeclName()
+ << S.Context.getTypeDeclType(DeclaringClass);
}
+ DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
+}
- // TODO: flesh this out
- S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
- << (unsigned) (Access == AS_protected);
+/// Diagnose an inaccessible hierarchy conversion.
+static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (ADK == Sema::ADK_covariance) {
+ S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
+ S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else {
+ S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ }
+ DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
+ Entity.getBaseClass(), 0, Access);
}
-/// Checks access to the given declaration in the current context.
-///
-/// \param R the means via which the access was made; must have a naming
-/// class set
-/// \param D the declaration accessed
-/// \param Access the best access along any inheritance path from the
-/// naming class to the declaration. AS_none means the path is impossible
-bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- assert(R.getNamingClass() && "performing access check without naming class");
+static void DiagnoseBadAccess(Sema &S,
+ SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (Entity.isMemberAccess())
+ DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
+ else
+ DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+}
- // If the access path is public, it's accessible everywhere.
- if (Access == AS_public)
- return false;
- // Otherwise, derive the current class context.
- DeclContext *DC = CurContext;
- while (isa<CXXRecordDecl>(DC) &&
- cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
- DC = DC->getParent();
-
- CXXRecordDecl *CurRecord;
- if (isa<CXXRecordDecl>(DC))
- CurRecord = cast<CXXRecordDecl>(DC);
- else if (isa<CXXMethodDecl>(DC))
- CurRecord = cast<CXXMethodDecl>(DC)->getParent();
- else {
- Diag(R.getNameLoc(), diag::err_access_outside_class)
- << (Access == AS_protected);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+/// Try to elevate access using friend declarations. This is
+/// potentially quite expensive.
+static void TryElevateAccess(Sema &S,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity,
+ AccessSpecifier &Access) {
+ CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
+ } else {
+ DeclaringClass = Entity.getBaseClass();
}
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+
+ // Adjust the declaration of the referred entity.
+ AccessSpecifier DeclAccess = AS_none;
+ if (Entity.isMemberAccess()) {
+ NamedDecl *Target = Entity.getTargetDecl();
+
+ DeclAccess = Target->getAccess();
+ if (DeclAccess != AS_public) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_accessible: DeclAccess = AS_public; break;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
+ case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
+ }
+ }
+
+ if (DeclaringClass == NamingClass) {
+ Access = DeclAccess;
+ return;
+ }
+ }
+
+ assert(DeclaringClass != NamingClass);
- CXXRecordDecl *NamingClass = R.getNamingClass();
+ // Append the declaration's access if applicable.
+ CXXBasePaths Paths;
+ CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
+ DeclaringClass, Paths);
+ if (!Path) {
+ // FIXME: delay dependent friendship
+ return;
+ }
+
+ // Grab the access along the best path.
+ AccessSpecifier NewAccess = Path->Access;
+ if (Entity.isMemberAccess())
+ NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
+
+ assert(NewAccess <= Access && "access along best path worse than direct?");
+ Access = NewAccess;
+}
+
+/// Checks access to an entity from the given effective context.
+static Sema::AccessResult CheckEffectiveAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ Sema::AccessedEntity const &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ AccessSpecifier Access = Entity.getAccess();
+ assert(Access != AS_public);
+
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
while (NamingClass->isAnonymousStructOrUnion())
// This should be guaranteed by the fact that the decl has
// non-public access. If not, we should make it guaranteed!
NamingClass = cast<CXXRecordDecl>(NamingClass);
+ if (!EC.Record) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+ }
+
// White-list accesses from within the declaring class.
- if (Access != AS_none &&
- CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
- return false;
+ if (Access != AS_none && EC.isClass(NamingClass))
+ return Sema::AR_accessible;
+
+ // If the access is worse than 'protected', try to promote to it using
+ // friend declarations.
+ bool TriedElevation = false;
+ if (Access != AS_protected) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ TriedElevation = true;
+ }
// Protected access.
if (Access == AS_protected) {
// FIXME: implement [class.protected]p1
- if (CurRecord->isDerivedFrom(NamingClass))
- return false;
+ if (EC.Record->isDerivedFrom(NamingClass))
+ return Sema::AR_accessible;
- // FIXME: dependent classes
+ // FIXME: delay dependent classes
}
- // FIXME: friends
+ // We're about to reject; one last chance to promote access.
+ if (!TriedElevation) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ }
+
+ // Okay, that's it, reject it.
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+}
- // Okay, it's a bad access, reject it.
+static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK
+ = Sema::ADK_normal) {
+ // If the access path is public, it's accessible everywhere.
+ if (Entity.getAccess() == AS_public)
+ return Sema::AR_accessible;
+
+ // If we're currently parsing a top-level declaration, delay
+ // diagnostics. This is the only case where parsing a declaration
+ // can actually change our effective context for the purposes of
+ // access control.
+ if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
+ assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
+ S.DelayedDiagnostics.push_back(
+ Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
+ return Sema::AR_delayed;
+ }
-
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
+ Loc, Entity, ADK);
+}
- if (Access == AS_protected) {
- Diag(R.getNameLoc(), diag::err_access_protected)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
- }
+void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
+ // Pretend we did this from the context of the newly-parsed
+ // declaration.
+ EffectiveContext EC(Ctx->getDeclContext());
+
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
+ DD.Triggered = true;
+}
+
+Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl || !E->getNamingClass())
+ return AR_accessible;
- assert(Access == AS_private || Access == AS_none);
- Diag(R.getNameLoc(), diag::err_access_private)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+ return CheckAccess(*this, E->getNameLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+/// Perform access-control checking on a previously-unresolved member
+/// access which has now been resolved to a member.
+Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ return CheckAccess(*this, E->getMemberLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
+ const RecordType *RT) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+ CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
+
+ AccessSpecifier Access = Dtor->getAccess();
+ if (Access == AS_public)
+ return AR_accessible;
+
+ return CheckAccess(*this, Loc,
+ AccessedEntity::makeMember(NamingClass, Access, Dtor));
+}
+
+/// Checks access to a constructor.
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
+ CXXConstructorDecl *Constructor,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = Constructor->getParent();
+ return CheckAccess(*this, UseLoc,
+ AccessedEntity::makeMember(NamingClass, Access, Constructor));
+}
+
+/// Checks access to an overloaded member operator, including
+/// conversion operators.
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ NamedDecl *MemberOperator,
+ AccessSpecifier Access) {
+ if (!getLangOptions().AccessControl)
+ return AR_accessible;
+
+ const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
+ assert(RT && "found member operator but object expr not of record type");
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+
+ return CheckAccess(*this, OpLoc,
+ AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+}
+
+/// Checks access for a hierarchy conversion.
+///
+/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
+/// or a derived-to-base conversion (false)
+/// \param ForceCheck true if this check should be performed even if access
+/// control is disabled; some things rely on this for semantics
+/// \param ForceUnprivileged true if this check should proceed as if the
+/// context had no special privileges
+/// \param ADK controls the kind of diagnostics that are used
+Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
+ bool IsBaseToDerived,
+ QualType Base,
+ QualType Derived,
+ const CXXBasePath &Path,
+ bool ForceCheck,
+ bool ForceUnprivileged,
+ AccessDiagnosticsKind ADK) {
+ if (!ForceCheck && !getLangOptions().AccessControl)
+ return AR_accessible;
+
+ if (Path.Access == AS_public)
+ return AR_accessible;
+
+ // TODO: preserve the information about which types exactly were used.
+ CXXRecordDecl *BaseD, *DerivedD;
+ BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
+ DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
+ AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
+ BaseD, DerivedD,
+ Path.Access);
+
+ if (ForceUnprivileged)
+ return CheckEffectiveAccess(*this, EffectiveContext(),
+ AccessLoc, Entity, ADK);
+ return CheckAccess(*this, AccessLoc, Entity, ADK);
}
/// Checks access to all the declarations in the given result set.
-void Sema::CheckAccess(const LookupResult &R) {
+void Sema::CheckLookupAccess(const LookupResult &R) {
+ assert(getLangOptions().AccessControl
+ && "performing access check without access control");
+ assert(R.getNamingClass() && "performing access check without naming class");
+
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- CheckAccess(R, *I, I.getAccess());
+ if (I.getAccess() != AS_public)
+ CheckAccess(*this, R.getNameLoc(),
+ AccessedEntity::makeMember(R.getNamingClass(),
+ I.getAccess(), *I));
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 57c4f9bc2a27..0097cd363c8c 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -204,7 +204,30 @@ bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
T2 = T2PtrType->getPointeeType();
return true;
}
-
+ const ObjCObjectPointerType *T1ObjCPtrType =
+ T1->getAs<ObjCObjectPointerType>(),
+ *T2ObjCPtrType =
+ T2->getAs<ObjCObjectPointerType>();
+ if (T1ObjCPtrType) {
+ if (T2ObjCPtrType) {
+ T1 = T1ObjCPtrType->getPointeeType();
+ T2 = T2ObjCPtrType->getPointeeType();
+ return true;
+ }
+ else if (T2PtrType) {
+ T1 = T1ObjCPtrType->getPointeeType();
+ T2 = T2PtrType->getPointeeType();
+ return true;
+ }
+ }
+ else if (T2ObjCPtrType) {
+ if (T1PtrType) {
+ T2 = T2ObjCPtrType->getPointeeType();
+ T1 = T1PtrType->getPointeeType();
+ return true;
+ }
+ }
+
const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
*T2MPType = T2->getAs<MemberPointerType>();
if (T1MPType && T2MPType) {
@@ -225,9 +248,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
// C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
// the rules are non-trivial. So first we construct Tcv *...cv* as described
// in C++ 5.2.11p8.
- assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) &&
+ assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType()) &&
"Source type is not pointer or pointer to member.");
- assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
+ assert((DestType->isAnyPointerType() || DestType->isMemberPointerType()) &&
"Destination type is not pointer or pointer to member.");
QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
@@ -368,7 +391,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
}
// C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
- const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context);
+ const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition();
assert(SrcDecl && "Definition missing");
if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
@@ -388,7 +411,7 @@ void
CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, const SourceRange &DestRange) {
if (!DestType->isLValueReferenceType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
@@ -407,7 +430,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, const SourceRange &DestRange,
CastExpr::CastKind &Kind) {
if (!DestType->isLValueReferenceType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
@@ -434,7 +457,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
}
if (!DestType->isLValueReferenceType() && !DestType->isRecordType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
@@ -755,9 +778,10 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
return TC_Failed;
}
- if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
- diag::err_downcast_from_inaccessible_base, Paths,
- OpRange.getBegin(), DeclarationName())) {
+ if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+ /*IsBaseToDerived*/ true,
+ SrcType, DestType,
+ Paths.front())) {
msg = 0;
return TC_Failed;
}
@@ -821,9 +845,10 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
return TC_Failed;
}
- if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
- diag::err_downcast_from_inaccessible_base, Paths,
- OpRange.getBegin(), DeclarationName())) {
+ if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+ /*IsBaseToDerived*/ false,
+ DestType, SrcType,
+ Paths.front())) {
msg = 0;
return TC_Failed;
}
@@ -1083,10 +1108,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
return TC_Failed;
}
- bool destIsPtr =
- CStyle? DestType->isAnyPointerType() : DestType->isPointerType();
- bool srcIsPtr =
- CStyle ? SrcType->isAnyPointerType() : SrcType->isPointerType();
+ bool destIsPtr = DestType->isAnyPointerType();
+ bool srcIsPtr = SrcType->isAnyPointerType();
if (!destIsPtr && !srcIsPtr) {
// Except for std::nullptr_t->integer and lvalue->reference, which are
// handled above, at least one of the two arguments must be a pointer.
@@ -1197,7 +1220,7 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
return false;
if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType())
- DefaultFunctionArrayConversion(CastExpr);
+ DefaultFunctionArrayLvalueConversion(CastExpr);
// C++ [expr.cast]p5: The conversions performed by
// - a const_cast,
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 7a0b6252064d..52e9e9bc87ef 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -241,6 +241,10 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
DeclContext *DC = computeDeclContext(SS, true);
if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ // If this is a dependent type, then we consider it complete.
+ if (Tag->isDependentContext())
+ return false;
+
// If we're currently defining this type, then lookup into the
// type is okay: don't complain that it isn't complete yet.
const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>();
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 6ff8b1d75371..b62cd19a0b25 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -14,7 +14,8 @@
#include "Sema.h"
#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Analyses/PrintfFormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
@@ -140,12 +141,16 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinUnorderedCompare(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_fpclassify:
+ if (SemaBuiltinFPClassification(TheCall, 6))
+ return ExprError();
+ break;
case Builtin::BI__builtin_isfinite:
case Builtin::BI__builtin_isinf:
case Builtin::BI__builtin_isinf_sign:
case Builtin::BI__builtin_isnan:
case Builtin::BI__builtin_isnormal:
- if (SemaBuiltinUnaryFP(TheCall))
+ if (SemaBuiltinFPClassification(TheCall))
return ExprError();
break;
case Builtin::BI__builtin_return_address:
@@ -583,20 +588,21 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
return false;
}
-/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isnan and
-/// friends. This is declared to take (...), so we have to check everything.
-bool Sema::SemaBuiltinUnaryFP(CallExpr *TheCall) {
- if (TheCall->getNumArgs() < 1)
+/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like
+/// __builtin_isnan and friends. This is declared to take (...), so we have
+/// to check everything.
+bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg) {
+ if (TheCall->getNumArgs() < LastArg)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
<< 0 /*function call*/;
- if (TheCall->getNumArgs() > 1)
- return Diag(TheCall->getArg(1)->getLocStart(),
+ if (TheCall->getNumArgs() > LastArg)
+ return Diag(TheCall->getArg(LastArg)->getLocStart(),
diag::err_typecheck_call_too_many_args)
<< 0 /*function call*/
- << SourceRange(TheCall->getArg(1)->getLocStart(),
+ << SourceRange(TheCall->getArg(LastArg)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
- Expr *OrigArg = TheCall->getArg(0);
+ Expr *OrigArg = TheCall->getArg(LastArg-1);
if (OrigArg->isTypeDependent())
return false;
@@ -748,7 +754,7 @@ bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) {
if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context))
return Diag(TheCall->getLocStart(), diag::err_expr_not_ice)
<< TheCall->getArg(0)->getSourceRange();
-
+
return false;
}
@@ -845,8 +851,7 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
}
if (isConstant) {
- const VarDecl *Def = 0;
- if (const Expr *Init = VD->getDefinition(Def))
+ if (const Expr *Init = VD->getAnyInitializer())
return SemaCheckStringLiteral(Init, TheCall,
HasVAListArg, format_idx, firstDataArg);
}
@@ -925,7 +930,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end();
i != e; ++i) {
const Expr *ArgExpr = TheCall->getArg(*i);
- if (ArgExpr->isNullPointerConstant(Context,
+ if (ArgExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull))
Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg)
<< ArgExpr->getSourceRange();
@@ -1032,248 +1037,309 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
<< OrigFormatExpr->getSourceRange();
}
-void Sema::CheckPrintfString(const StringLiteral *FExpr,
- const Expr *OrigFormatExpr,
- const CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg) {
-
- const ObjCStringLiteral *ObjCFExpr =
- dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
-
- // CHECK: is the format string a wide literal?
- if (FExpr->isWide()) {
- Diag(FExpr->getLocStart(),
- diag::warn_printf_format_string_is_wide_literal)
- << OrigFormatExpr->getSourceRange();
- return;
- }
+namespace {
+class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
+ Sema &S;
+ const StringLiteral *FExpr;
+ const Expr *OrigFormatExpr;
+ unsigned NumConversions;
+ const unsigned NumDataArgs;
+ const bool IsObjCLiteral;
+ const char *Beg; // Start of format string.
+ const bool HasVAListArg;
+ const CallExpr *TheCall;
+ unsigned FormatIdx;
+public:
+ CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
+ const Expr *origFormatExpr,
+ unsigned numDataArgs, bool isObjCLiteral,
+ const char *beg, bool hasVAListArg,
+ const CallExpr *theCall, unsigned formatIdx)
+ : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
+ NumConversions(0), NumDataArgs(numDataArgs),
+ IsObjCLiteral(isObjCLiteral), Beg(beg),
+ HasVAListArg(hasVAListArg),
+ TheCall(theCall), FormatIdx(formatIdx) {}
+
+ void DoneProcessing();
+
+ void HandleIncompleteFormatSpecifier(const char *startSpecifier,
+ unsigned specifierLen);
+
+ void
+ HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen);
+
+ void HandleNullChar(const char *nullCharacter);
+
+ bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen);
+private:
+ SourceRange getFormatStringRange();
+ SourceRange getFormatSpecifierRange(const char *startSpecifier,
+ unsigned specifierLen);
+ SourceLocation getLocationOfByte(const char *x);
+
+ bool HandleAmount(const analyze_printf::OptionalAmount &Amt,
+ unsigned MissingArgDiag, unsigned BadTypeDiag,
+ const char *startSpecifier, unsigned specifierLen);
+ void HandleFlags(const analyze_printf::FormatSpecifier &FS,
+ llvm::StringRef flag, llvm::StringRef cspec,
+ const char *startSpecifier, unsigned specifierLen);
+
+ const Expr *getDataArg(unsigned i) const;
+};
+}
- // Str - The format string. NOTE: this is NOT null-terminated!
- const char *Str = FExpr->getStrData();
+SourceRange CheckPrintfHandler::getFormatStringRange() {
+ return OrigFormatExpr->getSourceRange();
+}
- // CHECK: empty format string?
- unsigned StrLen = FExpr->getByteLength();
+SourceRange CheckPrintfHandler::
+getFormatSpecifierRange(const char *startSpecifier, unsigned specifierLen) {
+ return SourceRange(getLocationOfByte(startSpecifier),
+ getLocationOfByte(startSpecifier+specifierLen-1));
+}
- if (StrLen == 0) {
- Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
- << OrigFormatExpr->getSourceRange();
- return;
- }
+SourceLocation CheckPrintfHandler::getLocationOfByte(const char *x) {
+ return S.getLocationOfStringLiteralByte(FExpr, x - Beg);
+}
- // We process the format string using a binary state machine. The
- // current state is stored in CurrentState.
- enum {
- state_OrdChr,
- state_Conversion
- } CurrentState = state_OrdChr;
+void CheckPrintfHandler::
+HandleIncompleteFormatSpecifier(const char *startSpecifier,
+ unsigned specifierLen) {
+ SourceLocation Loc = getLocationOfByte(startSpecifier);
+ S.Diag(Loc, diag::warn_printf_incomplete_specifier)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+}
- // numConversions - The number of conversions seen so far. This is
- // incremented as we traverse the format string.
- unsigned numConversions = 0;
+void CheckPrintfHandler::
+HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+
+ ++NumConversions;
+ const analyze_printf::ConversionSpecifier &CS =
+ FS.getConversionSpecifier();
+ SourceLocation Loc = getLocationOfByte(CS.getStart());
+ S.Diag(Loc, diag::warn_printf_invalid_conversion)
+ << llvm::StringRef(CS.getStart(), CS.getLength())
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+}
- // numDataArgs - The number of data arguments after the format
- // string. This can only be determined for non vprintf-like
- // functions. For those functions, this value is 1 (the sole
- // va_arg argument).
- unsigned numDataArgs = TheCall->getNumArgs()-firstDataArg;
+void CheckPrintfHandler::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();
+}
- // Inspect the format string.
- unsigned StrIdx = 0;
+const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
+ return TheCall->getArg(FormatIdx + i);
+}
- // LastConversionIdx - Index within the format string where we last saw
- // a '%' character that starts a new format conversion.
- unsigned LastConversionIdx = 0;
- for (; StrIdx < StrLen; ++StrIdx) {
- // Is the number of detected conversion conversions greater than
- // the number of matching data arguments? If so, stop.
- if (!HasVAListArg && numConversions > numDataArgs) break;
+void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS,
+ llvm::StringRef flag,
+ llvm::StringRef cspec,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier();
+ S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_nonsensical_flag)
+ << flag << cspec << getFormatSpecifierRange(startSpecifier, specifierLen);
+}
- // Handle "\0"
- if (Str[StrIdx] == '\0') {
- // The string returned by getStrData() is not null-terminated,
- // so the presence of a null character is likely an error.
- Diag(getLocationOfStringLiteralByte(FExpr, StrIdx),
- diag::warn_printf_format_string_contains_null_char)
- << OrigFormatExpr->getSourceRange();
- return;
- }
+bool
+CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
+ unsigned MissingArgDiag,
+ unsigned BadTypeDiag,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+
+ if (Amt.hasDataArgument()) {
+ ++NumConversions;
+ if (!HasVAListArg) {
+ if (NumConversions > NumDataArgs) {
+ S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ // Don't do any more checking. We will just emit
+ // spurious errors.
+ return false;
+ }
- // Ordinary characters (not processing a format conversion).
- if (CurrentState == state_OrdChr) {
- if (Str[StrIdx] == '%') {
- CurrentState = state_Conversion;
- LastConversionIdx = StrIdx;
+ // Type check the data argument. It should be an 'int'.
+ // Although not in conformance with C99, we also allow the argument to be
+ // an 'unsigned int' as that is a reasonably safe case. GCC also
+ // doesn't emit a warning for that case.
+ const Expr *Arg = getDataArg(NumConversions);
+ QualType T = Arg->getType();
+
+ const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context);
+ assert(ATR.isValid());
+
+ if (!ATR.matchesType(S.Context, T)) {
+ S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag)
+ << ATR.getRepresentativeType(S.Context) << T
+ << getFormatSpecifierRange(startSpecifier, specifierLen)
+ << Arg->getSourceRange();
+ // Don't do any more checking. We will just emit
+ // spurious errors.
+ return false;
}
- continue;
}
+ }
+ return true;
+}
- // Seen '%'. Now processing a format conversion.
- switch (Str[StrIdx]) {
- // Handle dynamic precision or width specifier.
- case '*': {
- ++numConversions;
-
- if (!HasVAListArg) {
- if (numConversions > numDataArgs) {
- SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
-
- if (Str[StrIdx-1] == '.')
- Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg)
- << OrigFormatExpr->getSourceRange();
- else
- Diag(Loc, diag::warn_printf_asterisk_width_missing_arg)
- << OrigFormatExpr->getSourceRange();
-
- // Don't do any more checking. We'll just emit spurious errors.
- return;
- }
+bool
+CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
+ &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+
+ using namespace analyze_printf;
+ const ConversionSpecifier &CS = FS.getConversionSpecifier();
+
+ // First check if the field width, precision, and conversion specifier
+ // have matching data arguments.
+ if (!HandleAmount(FS.getFieldWidth(),
+ diag::warn_printf_asterisk_width_missing_arg,
+ diag::warn_printf_asterisk_width_wrong_type,
+ startSpecifier, specifierLen)) {
+ return false;
+ }
- // Perform type checking on width/precision specifier.
- const Expr *E = TheCall->getArg(format_idx+numConversions);
- if (const BuiltinType *BT = E->getType()->getAs<BuiltinType>())
- if (BT->getKind() == BuiltinType::Int)
- break;
+ if (!HandleAmount(FS.getPrecision(),
+ diag::warn_printf_asterisk_precision_missing_arg,
+ diag::warn_printf_asterisk_precision_wrong_type,
+ startSpecifier, specifierLen)) {
+ return false;
+ }
- SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx);
+ // Check for using an Objective-C specific conversion specifier
+ // in a non-ObjC literal.
+ if (!IsObjCLiteral && CS.isObjCArg()) {
+ HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen);
- if (Str[StrIdx-1] == '.')
- Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type)
- << E->getType() << E->getSourceRange();
- else
- Diag(Loc, diag::warn_printf_asterisk_width_wrong_type)
- << E->getType() << E->getSourceRange();
+ // Continue checking the other format specifiers.
+ return true;
+ }
- break;
- }
- }
+ if (!CS.consumesDataArgument()) {
+ // FIXME: Technically specifying a precision or field width here
+ // makes no sense. Worth issuing a warning at some point.
+ return true;
+ }
- // Characters which can terminate a format conversion
- // (e.g. "%d"). Characters that specify length modifiers or
- // other flags are handled by the default case below.
- //
- // FIXME: additional checks will go into the following cases.
- case 'i':
- case 'd':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- case 'D':
- case 'O':
- case 'U':
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- case 'a':
- case 'A':
- case 'c':
- case 'C':
- case 'S':
- case 's':
- case 'p':
- ++numConversions;
- CurrentState = state_OrdChr;
- break;
+ ++NumConversions;
- case 'm':
- // FIXME: Warn in situations where this isn't supported!
- CurrentState = state_OrdChr;
- break;
+ // Are we using '%n'? Issue a warning about this being
+ // a possible security issue.
+ if (CS.getKind() == ConversionSpecifier::OutIntPtrArg) {
+ S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_write_back)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ // Continue checking the other format specifiers.
+ return true;
+ }
- // CHECK: Are we using "%n"? Issue a warning.
- case 'n': {
- ++numConversions;
- CurrentState = state_OrdChr;
- SourceLocation Loc = getLocationOfStringLiteralByte(FExpr,
- LastConversionIdx);
+ if (CS.getKind() == ConversionSpecifier::VoidPtrArg) {
+ if (FS.getPrecision().getHowSpecified() != OptionalAmount::NotSpecified)
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_nonsensical_precision)
+ << CS.getCharacters()
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ }
+ if (CS.getKind() == ConversionSpecifier::VoidPtrArg ||
+ CS.getKind() == ConversionSpecifier::CStrArg) {
+ // FIXME: Instead of using "0", "+", etc., eventually get them from
+ // the FormatSpecifier.
+ if (FS.hasLeadingZeros())
+ HandleFlags(FS, "0", CS.getCharacters(), startSpecifier, specifierLen);
+ if (FS.hasPlusPrefix())
+ HandleFlags(FS, "+", CS.getCharacters(), startSpecifier, specifierLen);
+ if (FS.hasSpacePrefix())
+ HandleFlags(FS, " ", CS.getCharacters(), startSpecifier, specifierLen);
+ }
- Diag(Loc, diag::warn_printf_write_back)<<OrigFormatExpr->getSourceRange();
- break;
- }
+ // The remaining checks depend on the data arguments.
+ if (HasVAListArg)
+ return true;
- // Handle "%@"
- case '@':
- // %@ is allowed in ObjC format strings only.
- if (ObjCFExpr != NULL)
- CurrentState = state_OrdChr;
- else {
- // Issue a warning: invalid format conversion.
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
- Diag(Loc, diag::warn_printf_invalid_conversion)
- << std::string(Str+LastConversionIdx,
- Str+std::min(LastConversionIdx+2, StrLen))
- << OrigFormatExpr->getSourceRange();
- }
- ++numConversions;
- break;
+ if (NumConversions > NumDataArgs) {
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_insufficient_data_args)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ // Don't do any more checking.
+ return false;
+ }
- // Handle "%%"
- case '%':
- // Sanity check: Was the first "%" character the previous one?
- // If not, we will assume that we have a malformed format
- // conversion, and that the current "%" character is the start
- // of a new conversion.
- if (StrIdx - LastConversionIdx == 1)
- CurrentState = state_OrdChr;
- else {
- // Issue a warning: invalid format conversion.
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
- Diag(Loc, diag::warn_printf_invalid_conversion)
- << std::string(Str+LastConversionIdx, Str+StrIdx)
- << OrigFormatExpr->getSourceRange();
-
- // This conversion is broken. Advance to the next format
- // conversion.
- LastConversionIdx = StrIdx;
- ++numConversions;
- }
- break;
+ // Now type check the data expression that matches the
+ // format specifier.
+ const Expr *Ex = getDataArg(NumConversions);
+ const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
+ if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
+ // Check if we didn't match because of an implicit cast from a 'char'
+ // or 'short' to an 'int'. This is done because printf is a varargs
+ // function.
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
+ if (ICE->getType() == S.Context.IntTy)
+ if (ATR.matchesType(S.Context, ICE->getSubExpr()->getType()))
+ return true;
- default:
- // This case catches all other characters: flags, widths, etc.
- // We should eventually process those as well.
- break;
- }
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_conversion_argument_type_mismatch)
+ << ATR.getRepresentativeType(S.Context) << Ex->getType()
+ << getFormatSpecifierRange(startSpecifier, specifierLen)
+ << Ex->getSourceRange();
}
- if (CurrentState == state_Conversion) {
- // Issue a warning: invalid format conversion.
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
+ return true;
+}
- Diag(Loc, diag::warn_printf_invalid_conversion)
- << std::string(Str+LastConversionIdx,
- Str+std::min(LastConversionIdx+2, StrLen))
- << OrigFormatExpr->getSourceRange();
+void CheckPrintfHandler::DoneProcessing() {
+ // Does the number of data arguments exceed the number of
+ // format conversions in the format string?
+ if (!HasVAListArg && NumConversions < NumDataArgs)
+ S.Diag(getDataArg(NumConversions+1)->getLocStart(),
+ diag::warn_printf_too_many_data_args)
+ << getFormatStringRange();
+}
+
+void Sema::CheckPrintfString(const StringLiteral *FExpr,
+ const Expr *OrigFormatExpr,
+ const CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg) {
+
+ // CHECK: is the format string a wide literal?
+ if (FExpr->isWide()) {
+ Diag(FExpr->getLocStart(),
+ diag::warn_printf_format_string_is_wide_literal)
+ << OrigFormatExpr->getSourceRange();
return;
}
- if (!HasVAListArg) {
- // CHECK: Does the number of format conversions exceed the number
- // of data arguments?
- if (numConversions > numDataArgs) {
- SourceLocation Loc =
- getLocationOfStringLiteralByte(FExpr, LastConversionIdx);
-
- Diag(Loc, diag::warn_printf_insufficient_data_args)
- << OrigFormatExpr->getSourceRange();
- }
- // CHECK: Does the number of data arguments exceed the number of
- // format conversions in the format string?
- else if (numConversions < numDataArgs)
- Diag(TheCall->getArg(format_idx+numConversions+1)->getLocStart(),
- diag::warn_printf_too_many_data_args)
- << OrigFormatExpr->getSourceRange();
+ // Str - The format string. NOTE: this is NOT null-terminated!
+ const char *Str = FExpr->getStrData();
+
+ // CHECK: empty format string?
+ unsigned StrLen = FExpr->getByteLength();
+
+ if (StrLen == 0) {
+ Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
+ << OrigFormatExpr->getSourceRange();
+ return;
}
+
+ CheckPrintfHandler H(*this, FExpr, OrigFormatExpr,
+ TheCall->getNumArgs() - firstDataArg,
+ isa<ObjCStringLiteral>(OrigFormatExpr), Str,
+ HasVAListArg, TheCall, format_idx);
+
+ if (!analyze_printf::ParseFormatString(H, Str, Str + StrLen))
+ H.DoneProcessing();
}
//===--- CHECK: Return Address of Stack Variable --------------------------===//
@@ -1300,11 +1366,11 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
if (C->hasBlockDeclRefExprs())
Diag(C->getLocStart(), diag::err_ret_local_block)
<< C->getSourceRange();
-
+
if (AddrLabelExpr *ALE = dyn_cast<AddrLabelExpr>(RetValExp))
Diag(ALE->getLocStart(), diag::warn_ret_addr_label)
<< ALE->getSourceRange();
-
+
} else if (lhsType->isReferenceType()) {
// Perform checking for stack values returned by reference.
// Check for a reference to the stack
@@ -1780,7 +1846,7 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
if (BO->getLHS()->getType()->isPointerType())
return IntRange::forType(C, E->getType());
// fallthrough
-
+
default:
break;
}
@@ -2221,7 +2287,7 @@ void Sema::CheckUnreachable(AnalysisContext &AC) {
CFG *cfg = AC.getCFG();
if (cfg == 0)
return;
-
+
llvm::BitVector live(cfg->getNumBlockIDs());
// Mark all live things first.
count = MarkLive(&cfg->getEntry(), live);
@@ -2268,7 +2334,9 @@ void Sema::CheckUnreachable(AnalysisContext &AC) {
CFGBlock &b = **I;
if (!live[b.getBlockID()])
// Avoid excessive errors by marking everything reachable from here
- lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange()));
+ lines.push_back(ErrLoc(MarkLiveTop(&b, live,
+ Context.getSourceManager()),
+ SourceRange(), SourceRange()));
}
}
@@ -2418,17 +2486,19 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
// which this code would then warn about.
if (getDiagnostics().hasErrorOccurred())
return;
-
+
bool ReturnsVoid = false;
bool HasNoReturn = false;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // If the result type of the function is a dependent type, we don't know
- // whether it will be void or not, so don't
- if (FD->getResultType()->isDependentType())
+ // For function templates, class templates and member function templates
+ // we'll do the analysis at instantiation time.
+ if (FD->isDependentContext())
return;
+
if (FD->getResultType()->isVoidType())
ReturnsVoid = true;
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
HasNoReturn = true;
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (MD->getResultType()->isVoidType())
@@ -2552,6 +2622,24 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
!Param->isImplicit() &&
!getLangOptions().CPlusPlus)
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+
+ // C99 6.7.5.3p12:
+ // If the function declarator is not part of a definition of that
+ // function, parameters may have incomplete type and may use the [*]
+ // notation in their sequences of declarator specifiers to specify
+ // variable length array types.
+ QualType PType = Param->getOriginalType();
+ if (const ArrayType *AT = Context.getAsArrayType(PType)) {
+ if (AT->getSizeModifier() == ArrayType::Star) {
+ // FIXME: This diagnosic should point the the '[*]' if source-location
+ // information is added for it.
+ Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
+ }
+ }
+
+ if (getLangOptions().CPlusPlus)
+ if (const RecordType *RT = Param->getType()->getAs<RecordType>())
+ FinalizeVarWithDestructor(Param, RT);
}
return HasInvalidParm;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index fcd419bb10fb..a86294971861 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2196,13 +2196,15 @@ void Sema::CodeCompleteCase(Scope *S) {
namespace {
struct IsBetterOverloadCandidate {
Sema &S;
+ SourceLocation Loc;
public:
- explicit IsBetterOverloadCandidate(Sema &S) : S(S) { }
+ explicit IsBetterOverloadCandidate(Sema &S, SourceLocation Loc)
+ : S(S), Loc(Loc) { }
bool
operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const {
- return S.isBetterOverloadCandidate(X, Y);
+ return S.isBetterOverloadCandidate(X, Y, Loc);
}
};
}
@@ -2228,7 +2230,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
}
// Build an overload candidate set based on the functions we find.
- OverloadCandidateSet CandidateSet;
+ SourceLocation Loc = Fn->getExprLoc();
+ OverloadCandidateSet CandidateSet(Loc);
// FIXME: What if we're calling something that isn't a function declaration?
// FIXME: What if we're calling a pseudo-destructor?
@@ -2247,7 +2250,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
if (!FDecl->getType()->getAs<FunctionProtoType>())
Results.push_back(ResultCandidate(FDecl));
else
- AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet,
+ // FIXME: access?
+ AddOverloadCandidate(FDecl, AS_none, Args, NumArgs, CandidateSet,
false, false, /*PartialOverloading*/ true);
}
}
@@ -2255,7 +2259,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
if (!CandidateSet.empty()) {
// Sort the overload candidate set by placing the best overloads first.
std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
- IsBetterOverloadCandidate(*this));
+ IsBetterOverloadCandidate(*this, Loc));
// Add the remaining viable overload candidates as code-completion reslults.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -2977,7 +2981,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- DefaultFunctionArrayConversion(RecExpr);
+ DefaultFunctionArrayLvalueConversion(RecExpr);
QualType ReceiverType = RecExpr->getType();
if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index fbe02894ace5..1fc08ce03197 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14,7 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -135,6 +135,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
+ Result.suppressDiagnostics();
return 0;
case LookupResult::Ambiguous:
@@ -509,9 +510,18 @@ static void RemoveUsingDecls(LookupResult &R) {
}
static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
+ if (D->isInvalidDecl())
+ return false;
+
if (D->isUsed() || D->hasAttr<UnusedAttr>())
return false;
-
+
+ // White-list anything that isn't a local variable.
+ if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ||
+ !D->getDeclContext()->isFunctionOrMethod())
+ return false;
+
+ // Types of valid local variables should be complete, so this should succeed.
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
@@ -523,9 +533,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
}
}
- return (isa<VarDecl>(D) && !isa<ParmVarDecl>(D) &&
- !isa<ImplicitParamDecl>(D) &&
- D->getDeclContext()->isFunctionOrMethod());
+ return true;
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
@@ -690,7 +698,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
FT->getArgType(i), /*TInfo=*/0,
VarDecl::None, 0));
- New->setParams(Context, Params.data(), Params.size());
+ New->setParams(Params.data(), Params.size());
}
AddKnownFunctionAttributes(New);
@@ -957,6 +965,44 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
return true;
}
+ // If a function is first declared with a calling convention, but is
+ // later declared or defined without one, the second decl assumes the
+ // calling convention of the first.
+ //
+ // For the new decl, we have to look at the NON-canonical type to tell the
+ // difference between a function that really doesn't have a calling
+ // convention and one that is declared cdecl. That's because in
+ // canonicalization (see ASTContext.cpp), cdecl is canonicalized away
+ // because it is the default calling convention.
+ //
+ // Note also that we DO NOT return at this point, because we still have
+ // other tests to run.
+ const FunctionType *OldType = OldQType->getAs<FunctionType>();
+ const FunctionType *NewType = New->getType()->getAs<FunctionType>();
+ if (OldType->getCallConv() != CC_Default &&
+ NewType->getCallConv() == CC_Default) {
+ NewQType = Context.getCallConvType(NewQType, OldType->getCallConv());
+ New->setType(NewQType);
+ NewQType = Context.getCanonicalType(NewQType);
+ } else if (!Context.isSameCallConv(OldType->getCallConv(),
+ NewType->getCallConv())) {
+ // Calling conventions really aren't compatible, so complain.
+ Diag(New->getLocation(), diag::err_cconv_change)
+ << FunctionType::getNameForCallConv(NewType->getCallConv())
+ << (OldType->getCallConv() == CC_Default)
+ << (OldType->getCallConv() == CC_Default ? "" :
+ FunctionType::getNameForCallConv(OldType->getCallConv()));
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
+ // FIXME: diagnose the other way around?
+ if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) {
+ NewQType = Context.getNoReturnType(NewQType);
+ New->setType(NewQType);
+ assert(NewQType.isCanonical());
+ }
+
if (getLangOptions().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
@@ -1061,7 +1107,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
Params.push_back(Param);
}
- New->setParams(Context, Params.data(), Params.size());
+ New->setParams(Params.data(), Params.size());
}
return MergeCompatibleFunctionDecls(New, Old);
@@ -1297,6 +1343,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
Diag(Old->getLocation(), diag::note_previous_definition);
}
+ // C++ doesn't have tentative definitions, so go right ahead and check here.
+ const VarDecl *Def;
+ if (getLangOptions().CPlusPlus &&
+ New->isThisDeclarationADefinition() == VarDecl::Definition &&
+ (Def = Old->getDefinition())) {
+ Diag(New->getLocation(), diag::err_redefinition)
+ << New->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return;
+ }
+
// Keep a chain of previous declarations.
New->setPreviousDeclaration(Old);
@@ -1855,6 +1913,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (!DC->isDependentContext() &&
RequireCompleteDeclContext(D.getCXXScopeSpec()))
return DeclPtrTy();
+
+ if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_member_def_undefined_record)
+ << Name << DC << D.getCXXScopeSpec().getRange();
+ D.setInvalidType();
+ }
LookupQualifiedName(Previous, DC);
@@ -2322,7 +2387,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getString()));
+ NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString()));
}
// Don't consider existing declarations that are in a different
@@ -2359,9 +2424,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// attributes declared post-definition are currently ignored
if (Previous.isSingleResult()) {
- const VarDecl *Def = 0;
- VarDecl *PrevDecl = dyn_cast<VarDecl>(Previous.getFoundDecl());
- if (PrevDecl && PrevDecl->getDefinition(Def) && D.hasAttributes()) {
+ VarDecl *Def = dyn_cast<VarDecl>(Previous.getFoundDecl());
+ if (Def && (Def = Def->getDefinition()) &&
+ Def != NewVD && D.hasAttributes()) {
Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition);
Diag(Def->getLocation(), diag::note_previous_definition);
}
@@ -2675,7 +2740,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// (The parser checks for a return type and makes the declarator a
// constructor if it has no return type).
// must have an invalid constructor that has a return type
- if (Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){
+ if (Name.getAsIdentifierInfo() &&
+ Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){
Diag(D.getIdentifierLoc(), diag::err_constructor_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
@@ -2783,6 +2849,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
+ // C++ [dcl.fct.spec]p6:
+ // The explicit specifier shall be used only in the declaration of a
+ // constructor or conversion function within its class definition; see 12.3.1
+ // and 12.3.2.
+ if (isExplicit && !NewFD->isInvalidDecl()) {
+ if (!CurContext->isRecord()) {
+ // 'explicit' was specified outside of the class.
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ diag::err_explicit_out_of_class)
+ << CodeModificationHint::CreateRemoval(
+ D.getDeclSpec().getExplicitSpecLoc());
+ } else if (!isa<CXXConstructorDecl>(NewFD) &&
+ !isa<CXXConversionDecl>(NewFD)) {
+ // 'explicit' was specified on a function that wasn't a constructor
+ // or conversion function.
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ diag::err_explicit_non_ctor_or_conv_function)
+ << CodeModificationHint::CreateRemoval(
+ D.getDeclSpec().getExplicitSpecLoc());
+ }
+ }
+
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
@@ -2822,7 +2910,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getString()));
+ NewFD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString()));
}
// Copy the parameter declarations from the declarator D to the function
@@ -2882,7 +2970,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
"Should not need args for typedef of non-prototype fn");
}
// Finally, we know we have the right number of parameters, install them.
- NewFD->setParams(Context, Params.data(), Params.size());
+ NewFD->setParams(Params.data(), Params.size());
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
@@ -2950,7 +3038,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
// Fake up an access specifier if it's supposed to be a class member.
- if (isa<CXXRecordDecl>(NewFD->getDeclContext()))
+ if (!Redeclaration && isa<CXXRecordDecl>(NewFD->getDeclContext()))
NewFD->setAccess(AS_public);
// An out-of-line member function declaration must also be a
@@ -3041,6 +3129,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (FunctionTemplate)
return FunctionTemplate;
+
+ // Keep track of static, non-inlined function definitions that
+ // have not been used. We will warn later.
+ // FIXME: Also include static functions declared but not defined.
+ if (!NewFD->isInvalidDecl() && IsFunctionDefinition
+ && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage
+ && !NewFD->isUsed())
+ UnusedStaticFuncs.push_back(NewFD);
+
return NewFD;
}
@@ -3412,8 +3509,8 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
AbstractVariableType))
VDecl->setInvalidDecl();
- const VarDecl *Def = 0;
- if (VDecl->getDefinition(Def)) {
+ const VarDecl *Def;
+ if ((Def = VDecl->getDefinition()) && Def != VDecl) {
Diag(VDecl->getLocation(), diag::err_redefinition)
<< VDecl->getDeclName();
Diag(Def->getLocation(), diag::note_previous_definition);
@@ -3473,7 +3570,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
// };
// Attach the initializer
- VDecl->setInit(Context, Init);
+ VDecl->setInit(Init);
// C++ [class.mem]p4:
// A member-declarator can contain a constant-initializer only
@@ -3545,23 +3642,15 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
Init = MaybeCreateCXXExprWithTemporaries(Init);
// Attach the initializer to the decl.
- VDecl->setInit(Context, Init);
-
- // If the previous declaration of VDecl was a tentative definition,
- // remove it from the set of tentative definitions.
- if (VDecl->getPreviousDeclaration() &&
- VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) {
- bool Deleted = TentativeDefinitions.erase(VDecl->getDeclName());
- assert(Deleted && "Unrecorded tentative definition?"); Deleted=Deleted;
- }
+ VDecl->setInit(Init);
if (getLangOptions().CPlusPlus) {
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
while (const ArrayType *Array = Context.getAsArrayType(InitType))
InitType = Context.getBaseElementType(Array);
- if (InitType->isRecordType())
- FinalizeVarWithDestructor(VDecl, InitType);
+ if (const RecordType *Record = InitType->getAs<RecordType>())
+ FinalizeVarWithDestructor(VDecl, Record);
}
return;
@@ -3578,136 +3667,140 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
QualType Type = Var->getType();
- // Record tentative definitions.
- if (Var->isTentativeDefinition(Context)) {
- std::pair<llvm::DenseMap<DeclarationName, VarDecl *>::iterator, bool>
- InsertPair =
- TentativeDefinitions.insert(std::make_pair(Var->getDeclName(), Var));
+ // C++0x [dcl.spec.auto]p3
+ if (TypeContainsUndeducedAuto) {
+ Diag(Var->getLocation(), diag::err_auto_var_requires_init)
+ << Var->getDeclName() << Type;
+ Var->setInvalidDecl();
+ return;
+ }
+
+ switch (Var->isThisDeclarationADefinition()) {
+ case VarDecl::Definition:
+ if (!Var->isStaticDataMember() || !Var->getAnyInitializer())
+ break;
- // Keep the latest definition in the map. If we see 'int i; int i;' we
- // want the second one in the map.
- InsertPair.first->second = Var;
+ // We have an out-of-line definition of a static data member
+ // that has an in-class initializer, so we type-check this like
+ // a declaration.
+ //
+ // Fall through
+
+ case VarDecl::DeclarationOnly:
+ // It's only a declaration.
+
+ // Block scope. C99 6.7p7: If an identifier for an object is
+ // declared with no linkage (C99 6.2.2p6), the type for the
+ // object shall be complete.
+ if (!Type->isDependentType() && Var->isBlockVarDecl() &&
+ !Var->getLinkage() && !Var->isInvalidDecl() &&
+ RequireCompleteType(Var->getLocation(), Type,
+ diag::err_typecheck_decl_incomplete_type))
+ Var->setInvalidDecl();
- // However, for the list, we don't care about the order, just make sure
- // that there are no dupes for a given declaration name.
- if (InsertPair.second)
- TentativeDefinitionList.push_back(Var->getDeclName());
+ // Make sure that the type is not abstract.
+ if (!Type->isDependentType() && !Var->isInvalidDecl() &&
+ RequireNonAbstractType(Var->getLocation(), Type,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ Var->setInvalidDecl();
+ return;
+
+ case VarDecl::TentativeDefinition:
+ // File scope. C99 6.9.2p2: A declaration of an identifier for an
+ // object that has file scope without an initializer, and without a
+ // storage-class specifier or with the storage-class specifier "static",
+ // constitutes a tentative definition. Note: A tentative definition with
+ // external linkage is valid (C99 6.2.2p5).
+ if (!Var->isInvalidDecl()) {
+ if (const IncompleteArrayType *ArrayT
+ = Context.getAsIncompleteArrayType(Type)) {
+ if (RequireCompleteType(Var->getLocation(),
+ ArrayT->getElementType(),
+ diag::err_illegal_decl_array_incomplete_type))
+ Var->setInvalidDecl();
+ } else if (Var->getStorageClass() == VarDecl::Static) {
+ // C99 6.9.2p3: If the declaration of an identifier for an object is
+ // a tentative definition and has internal linkage (C99 6.2.2p3), the
+ // declared type shall not be an incomplete type.
+ // NOTE: code such as the following
+ // static struct s;
+ // struct s { int a; };
+ // is accepted by gcc. Hence here we issue a warning instead of
+ // an error and we do not invalidate the static declaration.
+ // NOTE: to avoid multiple warnings, only check the first declaration.
+ if (Var->getPreviousDeclaration() == 0)
+ RequireCompleteType(Var->getLocation(), Type,
+ diag::ext_typecheck_decl_incomplete_type);
+ }
+ }
+
+ // Record the tentative definition; we're done.
+ if (!Var->isInvalidDecl())
+ TentativeDefinitions.push_back(Var);
+ return;
}
- // C++ [dcl.init.ref]p3:
- // The initializer can be omitted for a reference only in a
- // parameter declaration (8.3.5), in the declaration of a
- // function return type, in the declaration of a class member
- // within its class declaration (9.2), and where the extern
- // specifier is explicitly used.
- if (Type->isReferenceType() && !Var->hasExternalStorage()) {
- Diag(Var->getLocation(), diag::err_reference_var_requires_init)
- << Var->getDeclName()
- << SourceRange(Var->getLocation(), Var->getLocation());
+ // Provide a specific diagnostic for uninitialized variable
+ // definitions with incomplete array type.
+ if (Type->isIncompleteArrayType()) {
+ Diag(Var->getLocation(),
+ diag::err_typecheck_incomplete_array_needs_initializer);
Var->setInvalidDecl();
return;
}
- // C++0x [dcl.spec.auto]p3
- if (TypeContainsUndeducedAuto) {
- Diag(Var->getLocation(), diag::err_auto_var_requires_init)
- << Var->getDeclName() << Type;
+ // Provide a specific diagnostic for uninitialized variable
+ // definitions with reference type.
+ if (Type->isReferenceType()) {
+ Diag(Var->getLocation(), diag::err_reference_var_requires_init)
+ << Var->getDeclName()
+ << SourceRange(Var->getLocation(), Var->getLocation());
+ Var->setInvalidDecl();
+ return;
+ }
+
+ // Do not attempt to type-check the default initializer for a
+ // variable with dependent type.
+ if (Type->isDependentType())
+ return;
+
+ if (Var->isInvalidDecl())
+ return;
+
+ if (RequireCompleteType(Var->getLocation(),
+ Context.getBaseElementType(Type),
+ diag::err_typecheck_decl_incomplete_type)) {
Var->setInvalidDecl();
return;
}
- // An array without size is an incomplete type, and there are no special
- // rules in C++ to make such a definition acceptable.
- if (getLangOptions().CPlusPlus && Type->isIncompleteArrayType() &&
- !Var->hasExternalStorage()) {
- Diag(Var->getLocation(),
- diag::err_typecheck_incomplete_array_needs_initializer);
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(Var->getLocation(), Type,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType)) {
Var->setInvalidDecl();
return;
}
- // C++ [temp.expl.spec]p15:
- // An explicit specialization of a static data member of a template is a
- // definition if the declaration includes an initializer; otherwise, it
- // is a declaration.
- if (Var->isStaticDataMember() &&
- Var->getInstantiatedFromStaticDataMember() &&
- Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return;
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(Var);
+ InitializationKind Kind
+ = InitializationKind::CreateDefault(Var->getLocation());
- // C++ [dcl.init]p9:
- // If no initializer is specified for an object, and the object
- // is of (possibly cv-qualified) non-POD class type (or array
- // thereof), the object shall be default-initialized; if the
- // object is of const-qualified type, the underlying class type
- // shall have a user-declared default constructor.
- //
- // FIXME: Diagnose the "user-declared default constructor" bit.
- if (getLangOptions().CPlusPlus) {
- QualType InitType = Type;
- if (const ArrayType *Array = Context.getAsArrayType(Type))
- InitType = Context.getBaseElementType(Array);
- if ((!Var->hasExternalStorage() && !Var->isExternC()) &&
- InitType->isRecordType() && !InitType->isDependentType()) {
- if (!RequireCompleteType(Var->getLocation(), InitType,
- diag::err_invalid_incomplete_type_use)) {
- InitializedEntity Entity
- = InitializedEntity::InitializeVariable(Var);
- InitializationKind Kind
- = InitializationKind::CreateDefault(Var->getLocation());
-
- InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
- OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, 0, 0));
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else {
- Var->setInit(Context,
- MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>()));
- FinalizeVarWithDestructor(Var, InitType);
- }
- } else {
- Var->setInvalidDecl();
- }
- }
+ InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
+ OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, 0, 0));
+ if (Init.isInvalid())
+ Var->setInvalidDecl();
+ else {
+ if (Init.get())
+ Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs<Expr>()));
- // The variable can not have an abstract class type.
- if (RequireNonAbstractType(Var->getLocation(), Type,
- diag::err_abstract_type_in_decl,
- AbstractVariableType))
- Var->setInvalidDecl();
+ if (getLangOptions().CPlusPlus)
+ if (const RecordType *Record
+ = Context.getBaseElementType(Type)->getAs<RecordType>())
+ FinalizeVarWithDestructor(Var, Record);
}
-
-#if 0
- // FIXME: Temporarily disabled because we are not properly parsing
- // linkage specifications on declarations, e.g.,
- //
- // extern "C" const CGPoint CGPointerZero;
- //
- // C++ [dcl.init]p9:
- //
- // If no initializer is specified for an object, and the
- // object is of (possibly cv-qualified) non-POD class type (or
- // array thereof), the object shall be default-initialized; if
- // the object is of const-qualified type, the underlying class
- // type shall have a user-declared default
- // constructor. Otherwise, if no initializer is specified for
- // an object, the object and its subobjects, if any, have an
- // indeterminate initial value; if the object or any of its
- // subobjects are of const-qualified type, the program is
- // ill-formed.
- //
- // This isn't technically an error in C, so we don't diagnose it.
- //
- // FIXME: Actually perform the POD/user-defined default
- // constructor check.
- if (getLangOptions().CPlusPlus &&
- Context.getCanonicalType(Type).isConstQualified() &&
- !Var->hasExternalStorage())
- Diag(Var->getLocation(), diag::err_const_var_requires_init)
- << Var->getName()
- << SourceRange(Var->getLocation(), Var->getLocation());
-#endif
}
}
@@ -3723,77 +3816,6 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (Decl *D = Group[i].getAs<Decl>())
Decls.push_back(D);
- // Perform semantic analysis that depends on having fully processed both
- // the declarator and initializer.
- for (unsigned i = 0, e = Decls.size(); i != e; ++i) {
- VarDecl *IDecl = dyn_cast<VarDecl>(Decls[i]);
- if (!IDecl)
- continue;
- QualType T = IDecl->getType();
-
- // Block scope. C99 6.7p7: If an identifier for an object is declared with
- // no linkage (C99 6.2.2p6), the type for the object shall be complete...
- if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) {
- if (T->isDependentType()) {
- // If T is dependent, we should not require a complete type.
- // (RequireCompleteType shouldn't be called with dependent types.)
- // But we still can at least check if we've got an array of unspecified
- // size without an initializer.
- if (!IDecl->isInvalidDecl() && T->isIncompleteArrayType() &&
- !IDecl->getInit()) {
- Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type)
- << T;
- IDecl->setInvalidDecl();
- }
- } else if (!IDecl->isInvalidDecl()) {
- // If T is an incomplete array type with an initializer list that is
- // dependent on something, its size has not been fixed. We could attempt
- // to fix the size for such arrays, but we would still have to check
- // here for initializers containing a C++0x vararg expansion, e.g.
- // template <typename... Args> void f(Args... args) {
- // int vals[] = { args };
- // }
- const IncompleteArrayType *IAT = Context.getAsIncompleteArrayType(T);
- Expr *Init = IDecl->getInit();
- if (IAT && Init &&
- (Init->isTypeDependent() || Init->isValueDependent())) {
- // Check that the member type of the array is complete, at least.
- if (RequireCompleteType(IDecl->getLocation(), IAT->getElementType(),
- diag::err_typecheck_decl_incomplete_type))
- IDecl->setInvalidDecl();
- } else if (RequireCompleteType(IDecl->getLocation(), T,
- diag::err_typecheck_decl_incomplete_type))
- IDecl->setInvalidDecl();
- }
- }
- // File scope. C99 6.9.2p2: A declaration of an identifier for an
- // object that has file scope without an initializer, and without a
- // storage-class specifier or with the storage-class specifier "static",
- // constitutes a tentative definition. Note: A tentative definition with
- // external linkage is valid (C99 6.2.2p5).
- if (IDecl->isTentativeDefinition(Context) && !IDecl->isInvalidDecl()) {
- if (const IncompleteArrayType *ArrayT
- = Context.getAsIncompleteArrayType(T)) {
- if (RequireCompleteType(IDecl->getLocation(),
- ArrayT->getElementType(),
- diag::err_illegal_decl_array_incomplete_type))
- IDecl->setInvalidDecl();
- } else if (IDecl->getStorageClass() == VarDecl::Static) {
- // C99 6.9.2p3: If the declaration of an identifier for an object is
- // a tentative definition and has internal linkage (C99 6.2.2p3), the
- // declared type shall not be an incomplete type.
- // NOTE: code such as the following
- // static struct s;
- // struct s { int a; };
- // is accepted by gcc. Hence here we issue a warning instead of
- // an error and we do not invalidate the static declaration.
- // NOTE: to avoid multiple warnings, only check the first declaration.
- if (IDecl->getPreviousDeclaration() == 0)
- RequireCompleteType(IDecl->getLocation(), T,
- diag::ext_typecheck_decl_incomplete_type);
- }
- }
- }
return DeclGroupPtrTy::make(DeclGroupRef::Create(Context,
Decls.data(), Decls.size()));
}
@@ -3853,6 +3875,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Recover by removing the name
II = 0;
D.SetIdentifier(0, D.getIdentifierLoc());
+ D.setInvalidType(true);
}
}
}
@@ -3919,6 +3942,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy::make(New);
}
+void Sema::ActOnObjCCatchParam(DeclPtrTy D) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>());
+ Param->setDeclContext(CurContext);
+}
+
void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls) {
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
@@ -4297,8 +4325,8 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
bool HasVAListArg;
if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
if (!FD->getAttr<FormatAttr>())
- FD->addAttr(::new (Context) FormatAttr("printf", FormatIdx + 1,
- HasVAListArg ? 0 : FormatIdx + 2));
+ FD->addAttr(::new (Context) FormatAttr(Context, "printf", FormatIdx+1,
+ HasVAListArg ? 0 : FormatIdx+2));
}
// Mark const if we don't care about errno and that is the only
@@ -4311,7 +4339,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
}
if (Context.BuiltinInfo.isNoReturn(BuiltinID))
- FD->addAttr(::new (Context) NoReturnAttr());
+ FD->setType(Context.getNoReturnType(FD->getType()));
if (Context.BuiltinInfo.isNoThrow(BuiltinID))
FD->addAttr(::new (Context) NoThrowAttr());
if (Context.BuiltinInfo.isConst(BuiltinID))
@@ -4335,15 +4363,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// FIXME: NSLog and NSLogv should be target specific
if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
// FIXME: We known better than our headers.
- const_cast<FormatAttr *>(Format)->setType("printf");
+ const_cast<FormatAttr *>(Format)->setType(Context, "printf");
} else
- FD->addAttr(::new (Context) FormatAttr("printf", 1,
+ FD->addAttr(::new (Context) FormatAttr(Context, "printf", 1,
Name->isStr("NSLogv") ? 0 : 2));
} else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
// FIXME: asprintf and vasprintf aren't C99 functions. Should they be
// target-specific builtins, perhaps?
if (!FD->getAttr<FormatAttr>())
- FD->addAttr(::new (Context) FormatAttr("printf", 2,
+ FD->addAttr(::new (Context) FormatAttr(Context, "printf", 2,
Name->isStr("vasprintf") ? 0 : 3));
}
}
@@ -4614,7 +4642,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Diagnose attempts to redefine a tag.
if (TUK == TUK_Definition) {
- if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
+ if (TagDecl *Def = PrevTagDecl->getDefinition()) {
// If we're defining a specialization and the previous definition
// is from an implicit instantiation, don't emit an error
// here; we'll catch this in the general case below.
@@ -4927,9 +4955,17 @@ RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record,
if (Record->isDependentContext() || !Record->isDefinition())
return;
- if (Record->isDynamicClass() && !S.Context.getKeyFunction(Record))
- S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc));
+ if (Record->isDynamicClass()) {
+ const CXXMethodDecl *KeyFunction = S.Context.getKeyFunction(Record);
+ if (!KeyFunction)
+ S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record,
+ Loc));
+
+ if ((!KeyFunction || (KeyFunction->getBody() && KeyFunction->isInlined()))
+ && Record->getLinkage() == ExternalLinkage)
+ S.Diag(Record->getLocation(), diag::warn_weak_vtable) << Record;
+ }
for (DeclContext::decl_iterator D = Record->decls_begin(),
DEnd = Record->decls_end();
D != DEnd; ++D) {
@@ -5156,7 +5192,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
NewFD->setInvalidDecl();
}
- if (getLangOptions().CPlusPlus) {
+ if (!InvalidDecl && getLangOptions().CPlusPlus) {
CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record);
if (!T->isPODType())
@@ -5584,7 +5620,7 @@ void Sema::ActOnFields(Scope* S,
// Okay, we successfully defined 'Record'.
if (Record) {
- Record->completeDefinition(Context);
+ Record->completeDefinition();
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -5628,6 +5664,45 @@ void Sema::ActOnFields(Scope* S,
ProcessDeclAttributeList(S, Record, Attr);
}
+/// \brief Determine whether the given integral value is representable within
+/// the given type T.
+static bool isRepresentableIntegerValue(ASTContext &Context,
+ llvm::APSInt &Value,
+ QualType T) {
+ assert(T->isIntegralType() && "Integral type required!");
+ unsigned BitWidth = Context.getTypeSize(T);
+
+ if (Value.isUnsigned() || Value.isNonNegative())
+ return Value.getActiveBits() < BitWidth;
+
+ return Value.getMinSignedBits() <= BitWidth;
+}
+
+// \brief Given an integral type, return the next larger integral type
+// (or a NULL type of no such type exists).
+static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
+ // FIXME: Int128/UInt128 support, which also needs to be introduced into
+ // enum checking below.
+ assert(T->isIntegralType() && "Integral type required!");
+ const unsigned NumTypes = 4;
+ QualType SignedIntegralTypes[NumTypes] = {
+ Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy
+ };
+ QualType UnsignedIntegralTypes[NumTypes] = {
+ Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy,
+ Context.UnsignedLongLongTy
+ };
+
+ unsigned BitWidth = Context.getTypeSize(T);
+ QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes
+ : UnsignedIntegralTypes;
+ for (unsigned I = 0; I != NumTypes; ++I)
+ if (Context.getTypeSize(Types[I]) > BitWidth)
+ return Types[I];
+
+ return QualType();
+}
+
EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EnumConstantDecl *LastEnumConst,
SourceLocation IdLoc,
@@ -5635,24 +5710,45 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
ExprArg val) {
Expr *Val = (Expr *)val.get();
- llvm::APSInt EnumVal(32);
+ unsigned IntWidth = Context.Target.getIntWidth();
+ llvm::APSInt EnumVal(IntWidth);
QualType EltTy;
if (Val) {
if (Enum->isDependentType())
EltTy = Context.DependentTy;
else {
- // Make sure to promote the operand type to int.
- UsualUnaryConversions(Val);
- if (Val != val.get()) {
- val.release();
- val = Val;
- }
-
// C99 6.7.2.2p2: Make sure we have an integer constant expression.
SourceLocation ExpLoc;
if (VerifyIntegerConstantExpression(Val, &EnumVal)) {
Val = 0;
- } else {
+ } else {
+ if (!getLangOptions().CPlusPlus) {
+ // C99 6.7.2.2p2:
+ // The expression that defines the value of an enumeration constant
+ // shall be an integer constant expression that has a value
+ // representable as an int.
+
+ // Complain if the value is not representable in an int.
+ if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
+ Diag(IdLoc, diag::ext_enum_value_not_int)
+ << EnumVal.toString(10) << Val->getSourceRange()
+ << EnumVal.isNonNegative();
+ else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
+ // Force the type of the expression to 'int'.
+ ImpCastExprToType(Val, Context.IntTy, CastExpr::CK_IntegralCast);
+
+ if (Val != val.get()) {
+ val.release();
+ val = Val;
+ }
+ }
+ }
+
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ // - If an initializer is specified for an enumerator, the
+ // initializing value has the same type as the expression.
EltTy = Val->getType();
}
}
@@ -5661,25 +5757,76 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (!Val) {
if (Enum->isDependentType())
EltTy = Context.DependentTy;
- else if (LastEnumConst) {
+ else if (!LastEnumConst) {
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ // - If no initializer is specified for the first enumerator, the
+ // initializing value has an unspecified integral type.
+ //
+ // GCC uses 'int' for its unspecified integral type, as does
+ // C99 6.7.2.2p3.
+ EltTy = Context.IntTy;
+ } else {
// Assign the last value + 1.
EnumVal = LastEnumConst->getInitVal();
++EnumVal;
+ EltTy = LastEnumConst->getType();
// Check for overflow on increment.
- if (EnumVal < LastEnumConst->getInitVal())
- Diag(IdLoc, diag::warn_enum_value_overflow);
-
- EltTy = LastEnumConst->getType();
- } else {
- // First value, set to zero.
- EltTy = Context.IntTy;
- EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
- EnumVal.setIsSigned(true);
+ if (EnumVal < LastEnumConst->getInitVal()) {
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ //
+ // - Otherwise the type of the initializing value is the same as
+ // the type of the initializing value of the preceding enumerator
+ // unless the incremented value is not representable in that type,
+ // in which case the type is an unspecified integral type
+ // sufficient to contain the incremented value. If no such type
+ // exists, the program is ill-formed.
+ QualType T = getNextLargerIntegralType(Context, EltTy);
+ if (T.isNull()) {
+ // There is no integral type larger enough to represent this
+ // value. Complain, then allow the value to wrap around.
+ EnumVal = LastEnumConst->getInitVal();
+ EnumVal.zext(EnumVal.getBitWidth() * 2);
+ Diag(IdLoc, diag::warn_enumerator_too_large)
+ << EnumVal.toString(10);
+ } else {
+ EltTy = T;
+ }
+
+ // Retrieve the last enumerator's value, extent that type to the
+ // type that is supposed to be large enough to represent the incremented
+ // value, then increment.
+ EnumVal = LastEnumConst->getInitVal();
+ EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ ++EnumVal;
+
+ // If we're not in C++, diagnose the overflow of enumerator values,
+ // which in C99 means that the enumerator value is not representable in
+ // an int (C99 6.7.2.2p2). However, we support GCC's extension that
+ // permits enumerator values that are representable in some larger
+ // integral type.
+ if (!getLangOptions().CPlusPlus && !T.isNull())
+ Diag(IdLoc, diag::warn_enum_value_overflow);
+ } else if (!getLangOptions().CPlusPlus &&
+ !isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
+ // Enforce C99 6.7.2.2p2 even when we compute the next value.
+ Diag(IdLoc, diag::ext_enum_value_not_int)
+ << EnumVal.toString(10) << 1;
+ }
}
}
- assert(!EltTy.isNull() && "Enum constant with NULL type");
+ if (!Enum->isDependentType()) {
+ // Make the enumerator value match the signedness and size of the
+ // enumerator's type.
+ EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ }
val.release();
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
@@ -5759,7 +5906,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(EnumType);
}
- Enum->completeDefinition(Context, Context.DependentTy, Context.DependentTy);
+ Enum->completeDefinition(Context.DependentTy, Context.DependentTy);
return;
}
@@ -5783,18 +5930,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>());
if (!ECD) continue; // Already issued a diagnostic.
- // If the enum value doesn't fit in an int, emit an extension warning.
const llvm::APSInt &InitVal = ECD->getInitVal();
- assert(InitVal.getBitWidth() >= IntWidth &&
- "Should have promoted value to int");
- if (!getLangOptions().CPlusPlus && InitVal.getBitWidth() > IntWidth) {
- llvm::APSInt V(InitVal);
- V.trunc(IntWidth);
- V.extend(InitVal.getBitWidth());
- if (V != InitVal)
- Diag(ECD->getLocation(), diag::ext_enum_value_not_int)
- << InitVal.toString(10);
- }
// Keep track of the size of positive and negative values.
if (InitVal.isUnsigned() || InitVal.isNonNegative())
@@ -5856,8 +5992,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
}
BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType);
} else {
- // If there is no negative value, figure out which of uint, ulong, ulonglong
- // fits.
+ // If there is no negative value, figure out the smallest type that fits
+ // all of the enumerator values.
// If it's packed, check also if it fits a char or a short.
if (Packed && NumPositiveBits <= CharWidth) {
BestType = Context.UnsignedCharTy;
@@ -5870,30 +6006,26 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
} else if (NumPositiveBits <= IntWidth) {
BestType = Context.UnsignedIntTy;
BestWidth = IntWidth;
- BestPromotionType = (NumPositiveBits == BestWidth
- ? Context.UnsignedIntTy : Context.IntTy);
+ BestPromotionType
+ = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ ? Context.UnsignedIntTy : Context.IntTy;
} else if (NumPositiveBits <=
(BestWidth = Context.Target.getLongWidth())) {
BestType = Context.UnsignedLongTy;
- BestPromotionType = (NumPositiveBits == BestWidth
- ? Context.UnsignedLongTy : Context.LongTy);
+ BestPromotionType
+ = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ ? Context.UnsignedLongTy : Context.LongTy;
} else {
BestWidth = Context.Target.getLongLongWidth();
assert(NumPositiveBits <= BestWidth &&
"How could an initializer get larger than ULL?");
BestType = Context.UnsignedLongLongTy;
- BestPromotionType = (NumPositiveBits == BestWidth
- ? Context.UnsignedLongLongTy : Context.LongLongTy);
+ BestPromotionType
+ = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ ? Context.UnsignedLongLongTy : Context.LongLongTy;
}
}
- // If we're in C and the promotion type is larger than an int, just
- // use the underlying type, which is generally the unsigned integer
- // type of the same rank as the promotion type. This is how the gcc
- // extension works.
- if (!getLangOptions().CPlusPlus && BestPromotionType != Context.IntTy)
- BestPromotionType = BestType;
-
// Loop over all of the enumerator constants, changing their types to match
// the type of the enum if needed.
for (unsigned i = 0; i != NumElements; ++i) {
@@ -5906,23 +6038,17 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// enumerator value fits in an int, type it as an int, otherwise type it the
// same as the enumerator decl itself. This means that in "enum { X = 1U }"
// that X has type 'int', not 'unsigned'.
- if (!getLangOptions().CPlusPlus && ECD->getType() == Context.IntTy)
- continue;
// Determine whether the value fits into an int.
llvm::APSInt InitVal = ECD->getInitVal();
- bool FitsInInt;
- if (InitVal.isUnsigned() || !InitVal.isNegative())
- FitsInInt = InitVal.getActiveBits() < IntWidth;
- else
- FitsInInt = InitVal.getMinSignedBits() <= IntWidth;
// If it fits into an integer type, force it. Otherwise force it to match
// the enum decl type.
QualType NewTy;
unsigned NewWidth;
bool NewSign;
- if (FitsInInt && !getLangOptions().CPlusPlus) {
+ if (!getLangOptions().CPlusPlus &&
+ isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) {
NewTy = Context.IntTy;
NewWidth = IntWidth;
NewSign = true;
@@ -5960,7 +6086,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(NewTy);
}
- Enum->completeDefinition(Context, BestType, BestPromotionType);
+ Enum->completeDefinition(BestType, BestPromotionType);
}
Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 1a12208e5a94..cba1e9e1cd50 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -307,7 +307,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned* start = &NonNullArgs[0];
unsigned size = NonNullArgs.size();
std::sort(start, start + size);
- d->addAttr(::new (S.Context) NonNullAttr(start, size));
+ d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size));
}
static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -329,7 +329,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// FIXME: check if target symbol exists in current file
- d->addAttr(::new (S.Context) AliasAttr(Str->getString()));
+ d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString()));
}
static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
@@ -391,6 +391,11 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Don't apply as a decl attribute to ValueDecl.
+ // FIXME: probably ought to diagnose this.
+ if (isa<ValueDecl>(d))
+ return;
+
if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) NoReturnAttr());
}
@@ -404,7 +409,7 @@ static void HandleAnalyzerNoReturnAttr(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() << 8 /*function, method, or parameter*/;
return;
}
// FIXME: Actually store the attribute on the declaration
@@ -542,17 +547,16 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- const char *TypeStr = Str->getStrData();
- unsigned TypeLen = Str->getByteLength();
+ llvm::StringRef TypeStr = Str->getString();
VisibilityAttr::VisibilityTypes type;
- if (TypeLen == 7 && !memcmp(TypeStr, "default", 7))
+ if (TypeStr == "default")
type = VisibilityAttr::DefaultVisibility;
- else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6))
+ else if (TypeStr == "hidden")
type = VisibilityAttr::HiddenVisibility;
- else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8))
+ else if (TypeStr == "internal")
type = VisibilityAttr::HiddenVisibility; // FIXME
- else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9))
+ else if (TypeStr == "protected")
type = VisibilityAttr::ProtectedVisibility;
else {
S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
@@ -938,105 +942,9 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
-}
-
-static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Attribute has no arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- // Attribute can be applied only to functions.
- if (!isa<FunctionDecl>(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
- return;
- }
-
- // cdecl and fastcall attributes are mutually incompatible.
- if (d->getAttr<FastCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "cdecl" << "fastcall";
- return;
- }
-
- // cdecl and stdcall attributes are mutually incompatible.
- if (d->getAttr<StdCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "cdecl" << "stdcall";
- return;
- }
-
- d->addAttr(::new (S.Context) CDeclAttr());
-}
-
-
-static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Attribute has no arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- // Attribute can be applied only to functions.
- if (!isa<FunctionDecl>(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
- return;
- }
-
- // stdcall and fastcall attributes are mutually incompatible.
- if (d->getAttr<FastCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "stdcall" << "fastcall";
- return;
- }
-
- d->addAttr(::new (S.Context) StdCallAttr());
-}
-
-/// Diagnose the use of a non-standard calling convention on the given
-/// function.
-static void DiagnoseCConv(FunctionDecl *D, const char *CConv,
- SourceLocation Loc, Sema &S) {
- if (!D->hasPrototype()) {
- S.Diag(Loc, diag::err_cconv_knr) << CConv;
- return;
- }
-
- const FunctionProtoType *T = D->getType()->getAs<FunctionProtoType>();
- if (T->isVariadic()) {
- S.Diag(Loc, diag::err_cconv_varargs) << CConv;
- return;
- }
+ D->addAttr(::new (S.Context) SectionAttr(S.Context, SE->getString()));
}
-static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Attribute has no arguments.
- if (Attr.getNumArgs() != 0) {
- 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*/;
- return;
- }
-
- DiagnoseCConv(cast<FunctionDecl>(d), "fastcall", Attr.getLoc(), S);
-
- // stdcall and fastcall attributes are mutually incompatible.
- if (d->getAttr<StdCallAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << "fastcall" << "stdcall";
- return;
- }
-
- d->addAttr(::new (S.Context) FastCallAttr());
-}
static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
@@ -1349,7 +1257,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) FormatAttr(Format, Idx.getZExtValue(),
+ d->addAttr(::new (S.Context) FormatAttr(S.Context, Format, Idx.getZExtValue(),
FirstArg.getZExtValue()));
}
@@ -1435,7 +1343,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
- d->addAttr(::new (S.Context) AnnotateAttr(SE->getString()));
+ d->addAttr(::new (S.Context) AnnotateAttr(S.Context, SE->getString()));
}
static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1608,9 +1516,15 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
if (!IntegerMode)
NewTy = S.Context.DoubleTy;
else if (OldTy->isSignedIntegerType())
- NewTy = S.Context.LongLongTy;
+ if (S.Context.Target.getLongWidth() == 64)
+ NewTy = S.Context.LongTy;
+ else
+ NewTy = S.Context.LongLongTy;
else
- NewTy = S.Context.UnsignedLongLongTy;
+ if (S.Context.Target.getLongWidth() == 64)
+ NewTy = S.Context.UnsignedLongTy;
+ else
+ NewTy = S.Context.UnsignedLongLongTy;
break;
case 96:
NewTy = S.Context.LongDoubleTy;
@@ -1903,7 +1817,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break;
case AttributeList::AT_carries_dependency:
HandleDependencyAttr (D, Attr, S); break;
- case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break;
case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
@@ -1912,7 +1825,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_ext_vector_type:
HandleExtVectorTypeAttr(scope, D, Attr, S);
break;
- case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break;
case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
@@ -1935,7 +1847,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break;
case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break;
- case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break;
case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break;
case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break;
@@ -1964,6 +1875,11 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore
break;
+ case AttributeList::AT_stdcall:
+ case AttributeList::AT_cdecl:
+ case AttributeList::AT_fastcall:
+ // These are all treated as type attributes.
+ break;
default:
// Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
@@ -2008,7 +1924,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias());
- NewD->addAttr(::new (Context) AliasAttr(NDId->getName()));
+ NewD->addAttr(::new (Context) AliasAttr(Context, NDId->getName()));
NewD->addAttr(::new (Context) WeakAttr());
WeakTopLevelDecl.push_back(NewD);
// FIXME: "hideous" code from Sema::LazilyCreateBuiltin
@@ -2062,48 +1978,71 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
/// on the warning stack.
Action::ParsingDeclStackState Sema::PushParsingDeclaration() {
ParsingDeclDepth++;
- return (ParsingDeclStackState) DelayedDeprecationWarnings.size();
-}
-
-static bool isDeclDeprecated(Decl *D) {
- do {
- if (D->hasAttr<DeprecatedAttr>())
- return true;
- } while ((D = cast_or_null<Decl>(D->getDeclContext())));
- return false;
+ return (ParsingDeclStackState) DelayedDiagnostics.size();
}
void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack");
ParsingDeclDepth--;
- if (DelayedDeprecationWarnings.empty())
+ if (DelayedDiagnostics.empty())
return;
unsigned SavedIndex = (unsigned) S;
- assert(SavedIndex <= DelayedDeprecationWarnings.size() &&
+ assert(SavedIndex <= DelayedDiagnostics.size() &&
"saved index is out of bounds");
- if (Ctx && !isDeclDeprecated(Ctx.getAs<Decl>())) {
- for (unsigned I = 0, E = DelayedDeprecationWarnings.size(); I != E; ++I) {
- SourceLocation Loc = DelayedDeprecationWarnings[I].first;
- NamedDecl *&ND = DelayedDeprecationWarnings[I].second;
- if (ND) {
- Diag(Loc, diag::warn_deprecated) << ND->getDeclName();
-
- // Prevent this from triggering multiple times.
- ND = 0;
+ // We only want to actually emit delayed diagnostics when we
+ // successfully parsed a decl.
+ Decl *D = Ctx ? Ctx.getAs<Decl>() : 0;
+ if (D) {
+ // We really do want to start with 0 here. We get one push for a
+ // decl spec and another for each declarator; in a decl group like:
+ // deprecated_typedef foo, *bar, baz();
+ // only the declarator pops will be passed decls. This is correct;
+ // we really do need to consider delayed diagnostics from the decl spec
+ // for each of the different declarations.
+ for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) {
+ if (DelayedDiagnostics[I].Triggered)
+ continue;
+
+ switch (DelayedDiagnostics[I].Kind) {
+ case DelayedDiagnostic::Deprecation:
+ HandleDelayedDeprecationCheck(DelayedDiagnostics[I], D);
+ break;
+
+ case DelayedDiagnostic::Access:
+ HandleDelayedAccessCheck(DelayedDiagnostics[I], D);
+ break;
}
}
}
- DelayedDeprecationWarnings.set_size(SavedIndex);
+ DelayedDiagnostics.set_size(SavedIndex);
+}
+
+static bool isDeclDeprecated(Decl *D) {
+ do {
+ if (D->hasAttr<DeprecatedAttr>())
+ return true;
+ } while ((D = cast_or_null<Decl>(D->getDeclContext())));
+ return false;
+}
+
+void Sema::HandleDelayedDeprecationCheck(Sema::DelayedDiagnostic &DD,
+ Decl *Ctx) {
+ if (isDeclDeprecated(Ctx))
+ return;
+
+ DD.Triggered = true;
+ Diag(DD.Loc, diag::warn_deprecated)
+ << DD.DeprecationData.Decl->getDeclName();
}
void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) {
// Delay if we're currently parsing a declaration.
if (ParsingDeclDepth) {
- DelayedDeprecationWarnings.push_back(std::make_pair(Loc, D));
+ DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D));
return;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9ec95f3d170d..9defcca7e565 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -356,9 +356,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
}
}
- if (CheckEquivalentExceptionSpec(
- Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(), New->getLocation()))
+ if (CheckEquivalentExceptionSpec(Old, New))
Invalid = true;
return Invalid;
@@ -433,7 +431,7 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
} else
CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
- if (CurDecl)
+ if (CurDecl && CurDecl->getIdentifier())
return &II == CurDecl->getIdentifier();
else
return false;
@@ -486,7 +484,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// If the base class is polymorphic or isn't empty, the new one is/isn't, too.
RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl();
assert(BaseDecl && "Record type has no declaration");
- BaseDecl = BaseDecl->getDefinition(Context);
+ BaseDecl = BaseDecl->getDefinition();
assert(BaseDecl && "Base type is not incomplete, but has no definition");
CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
assert(CXXBaseDecl && "Base type is not a C++ type");
@@ -641,7 +639,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
}
// Attach the remaining base class specifiers to the derived class.
- Class->setBases(Context, Bases, NumGoodBases);
+ Class->setBases(Bases, NumGoodBases);
// Delete the remaining (good) base class specifiers, since their
// data has been copied into the CXXRecordDecl.
@@ -680,7 +678,8 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl());
CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl());
- return DerivedRD->isDerivedFrom(BaseRD);
+ // FIXME: instantiate DerivedRD if necessary. We need a PoI for this.
+ return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD);
}
/// \brief Determine whether the type \p Derived is a C++ class that is
@@ -712,7 +711,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
/// if there is an error.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
+ AccessDiagnosticsKind ADK,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name) {
@@ -728,11 +727,20 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (InaccessibleBaseID == 0)
+ if (ADK == ADK_quiet)
return false;
+
// Check that the base class can be accessed.
- return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
- Name);
+ switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false,
+ Base, Derived, Paths.front(),
+ /*force*/ false,
+ /*unprivileged*/ false,
+ ADK)) {
+ case AR_accessible: return false;
+ case AR_inaccessible: return true;
+ case AR_dependent: return false;
+ case AR_delayed: return false;
+ }
}
// We know that the derived-to-base conversion is ambiguous, and
@@ -763,8 +771,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
- IgnoreAccess ? 0 :
- diag::err_conv_to_inaccessible_base,
+ IgnoreAccess ? ADK_quiet : ADK_normal,
diag::err_ambiguous_derived_to_base_conv,
Loc, Range, DeclarationName());
}
@@ -1195,10 +1202,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
unsigned NumArgs, SourceLocation IdLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
-
// Diagnose value-uses of fields to initialize themselves, e.g.
// foo(foo)
// where foo is not also a parameter to the constructor.
@@ -1220,65 +1223,80 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
for (unsigned i = 0; i < NumArgs; i++)
HasDependentArg |= Args[i]->isTypeDependent();
- CXXConstructorDecl *C = 0;
QualType FieldType = Member->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- if (FieldType->isDependentType()) {
- // Can't check init for dependent type.
- } else if (FieldType->isRecordType()) {
- // Member is a record (struct/union/class), so pass the initializer
- // arguments down to the record's constructor.
- if (!HasDependentArg) {
- C = PerformInitializationByConstructor(FieldType,
- MultiExprArg(*this,
- (void**)Args,
- NumArgs),
- IdLoc,
- SourceRange(IdLoc, RParenLoc),
- Member->getDeclName(),
- InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc),
- ConstructorArgs);
-
- if (C) {
- // Take over the constructor arguments as our own.
- NumArgs = ConstructorArgs.size();
- Args = (Expr **)ConstructorArgs.take();
- }
- }
- } else if (NumArgs != 1 && NumArgs != 0) {
- // The member type is not a record type (or an array of record
- // types), so it can be only be default- or copy-initialized.
- return Diag(IdLoc, diag::err_mem_initializer_mismatch)
- << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
- } else if (!HasDependentArg) {
- Expr *NewExp;
- if (NumArgs == 0) {
- if (FieldType->isReferenceType()) {
- Diag(IdLoc, diag::err_null_intialized_reference_member)
- << Member->getDeclName();
- return Diag(Member->getLocation(), diag::note_declared_at);
- }
- NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc);
- NumArgs = 1;
- }
- else
- NewExp = (Expr*)Args[0];
- if (!Member->isInvalidDecl() &&
- PerformCopyInitialization(NewExp, FieldType, AA_Passing))
- return true;
- Args[0] = NewExp;
+ if (FieldType->isDependentType() || HasDependentArg) {
+ // Can't check initialization for a member of dependent type or when
+ // any of the arguments are type-dependent expressions.
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+
+ // Erase any temporaries within this evaluation context; we're not
+ // going to track them in the AST, since we'll be rebuilding the
+ // ASTs during template instantiation.
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+
}
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
+ if (Member->isInvalidDecl())
+ return true;
+
+ // Initialize the member.
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(Member, 0);
+ InitializationKind Kind =
+ InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc);
- // FIXME: Perform direct initialization of the member.
+ InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs);
+
+ OwningExprResult MemberInit =
+ InitSeq.Perform(*this, MemberEntity, Kind,
+ MultiExprArg(*this, (void**)Args, NumArgs), 0);
+ if (MemberInit.isInvalid())
+ return true;
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid())
+ return true;
+
+ // If we are in a dependent context, template instantiation will
+ // perform this type-checking again. Just save the arguments that we
+ // received in a ParenListExpr.
+ // FIXME: This isn't quite ideal, since our ASTs don't capture all
+ // of the information that we have about the member
+ // initializer. However, deconstructing the ASTs is a dicey process,
+ // and this approach is far more likely to get the corner cases right.
+ if (CurContext->isDependentContext()) {
+ // Bump the reference count of all of the arguments.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Retain();
+
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+ return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+ }
+
return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc,
- C, LParenLoc, (Expr **)Args,
- NumArgs, RParenLoc);
+ LParenLoc,
+ MemberInit.takeAs<Expr>(),
+ RParenLoc);
}
Sema::MemInitResult
@@ -1291,76 +1309,118 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
HasDependentArg |= Args[i]->isTypeDependent();
SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin();
- if (!BaseType->isDependentType()) {
- if (!BaseType->isRecordType())
- return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
-
- // C++ [class.base.init]p2:
- // [...] Unless the mem-initializer-id names a nonstatic data
- // member of the constructor’s class or a direct or virtual base
- // of that class, the mem-initializer is ill-formed. A
- // mem-initializer-list can initialize a base class using any
- // name that denotes that base class type.
-
- // Check for direct and virtual base classes.
- const CXXBaseSpecifier *DirectBaseSpec = 0;
- const CXXBaseSpecifier *VirtualBaseSpec = 0;
- FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
- VirtualBaseSpec);
-
- // C++ [base.class.init]p2:
- // If a mem-initializer-id is ambiguous because it designates both
- // a direct non-virtual base class and an inherited virtual base
- // class, the mem-initializer is ill-formed.
- if (DirectBaseSpec && VirtualBaseSpec)
- return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
- << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
- // C++ [base.class.init]p2:
- // Unless the mem-initializer-id names a nonstatic data membeer of the
- // constructor's class ot a direst or virtual base of that class, the
- // mem-initializer is ill-formed.
- if (!DirectBaseSpec && !VirtualBaseSpec)
- return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
- << BaseTInfo->getTypeLoc().getSourceRange();
- }
-
- CXXConstructorDecl *C = 0;
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- if (!BaseType->isDependentType() && !HasDependentArg) {
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(BaseType).getUnqualifiedType());
-
- C = PerformInitializationByConstructor(BaseType,
- MultiExprArg(*this,
- (void**)Args, NumArgs),
- BaseLoc,
- SourceRange(BaseLoc, RParenLoc),
- Name,
- InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc),
- ConstructorArgs);
- if (C) {
- // Take over the constructor arguments as our own.
- NumArgs = ConstructorArgs.size();
- Args = (Expr **)ConstructorArgs.take();
- }
+ if (BaseType->isDependentType() || HasDependentArg) {
+ // Can't check initialization for a base of dependent type or when
+ // any of the arguments are type-dependent expressions.
+ OwningExprResult BaseInit
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+
+ // Erase any temporaries within this evaluation context; we're not
+ // going to track them in the AST, since we'll be rebuilding the
+ // ASTs during template instantiation.
+ ExprTemporaries.erase(
+ ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+ ExprTemporaries.end());
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ BaseInit.takeAs<Expr>(),
+ RParenLoc);
}
+
+ if (!BaseType->isRecordType())
+ return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
+ // C++ [class.base.init]p2:
+ // [...] Unless the mem-initializer-id names a nonstatic data
+ // member of the constructor’s class or a direct or virtual base
+ // of that class, the mem-initializer is ill-formed. A
+ // mem-initializer-list can initialize a base class using any
+ // name that denotes that base class type.
+
+ // Check for direct and virtual base classes.
+ const CXXBaseSpecifier *DirectBaseSpec = 0;
+ const CXXBaseSpecifier *VirtualBaseSpec = 0;
+ FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+ VirtualBaseSpec);
+
+ // C++ [base.class.init]p2:
+ // If a mem-initializer-id is ambiguous because it designates both
+ // a direct non-virtual base class and an inherited virtual base
+ // class, the mem-initializer is ill-formed.
+ if (DirectBaseSpec && VirtualBaseSpec)
+ return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
+ // C++ [base.class.init]p2:
+ // Unless the mem-initializer-id names a nonstatic data membeer of the
+ // constructor's class ot a direst or virtual base of that class, the
+ // mem-initializer is ill-formed.
+ if (!DirectBaseSpec && !VirtualBaseSpec)
+ return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
+ << BaseType << ClassDecl->getNameAsCString()
+ << BaseTInfo->getTypeLoc().getSourceRange();
+
+ CXXBaseSpecifier *BaseSpec
+ = const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
+ if (!BaseSpec)
+ BaseSpec = const_cast<CXXBaseSpecifier *>(VirtualBaseSpec);
+
+ // Initialize the base.
+ InitializedEntity BaseEntity =
+ InitializedEntity::InitializeBase(Context, BaseSpec);
+ InitializationKind Kind =
+ InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc);
+
+ InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs);
+
+ OwningExprResult BaseInit =
+ InitSeq.Perform(*this, BaseEntity, Kind,
+ MultiExprArg(*this, (void**)Args, NumArgs), 0);
+ if (BaseInit.isInvalid())
+ return true;
- return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C,
- LParenLoc, (Expr **)Args,
- NumArgs, RParenLoc);
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.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()) {
+ // Bump the reference count of all of the arguments.
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Retain();
+
+ OwningExprResult Init
+ = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc));
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ Init.takeAs<Expr>(),
+ RParenLoc);
+ }
+
+ return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ LParenLoc,
+ BaseInit.takeAs<Expr>(),
+ RParenLoc);
}
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor) {
+ CXXBaseOrMemberInitializer **Initializers,
+ unsigned NumInitializers,
+ bool IsImplicitConstructor,
+ bool AnyErrors) {
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
@@ -1403,6 +1463,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
AllToInit.push_back(Member);
}
} else {
+ llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
+
// Push virtual bases before others.
for (CXXRecordDecl::base_class_iterator VBase =
ClassDecl->vbases_begin(),
@@ -1412,44 +1474,34 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
if (CXXBaseOrMemberInitializer *Value
= AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
- }
- else {
- CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
- assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null");
- CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 0 << VBase->getType();
- Diag(VBaseDecl->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(VBaseDecl);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, VBase);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
HadError = true;
continue;
}
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+ // Don't attach synthesized base initializers in a dependent
+ // context; they'll be checked again at template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
-
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if
- // necessary.
- // FIXME: Is there any better source-location information we can give?
- ExprTemporaries.clear();
- CXXBaseOrMemberInitializer *Member =
+ CXXBaseOrMemberInitializer *CXXBaseInit =
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialTypeSourceInfo(VBase->getType(),
SourceLocation()),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ BaseInit.takeAs<Expr>(),
SourceLocation());
- AllToInit.push_back(Member);
+ AllToInit.push_back(CXXBaseInit);
}
}
@@ -1466,43 +1518,34 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
}
- else {
- CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null");
- CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 0 << Base->getType();
- Diag(BaseDecl->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(BaseDecl);
+ else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, Base);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
HadError = true;
continue;
}
-
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+
+ // Don't attach synthesized base initializers in a dependent
+ // context; they'll be regenerated at template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
-
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if
- // necessary.
- // FIXME: Is there any better source-location information we can give?
- ExprTemporaries.clear();
- CXXBaseOrMemberInitializer *Member =
+ CXXBaseOrMemberInitializer *CXXBaseInit =
new (Context) CXXBaseOrMemberInitializer(Context,
Context.getTrivialTypeSourceInfo(Base->getType(),
SourceLocation()),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ BaseInit.takeAs<Expr>(),
SourceLocation());
- AllToInit.push_back(Member);
+ AllToInit.push_back(CXXBaseInit);
}
}
}
@@ -1535,66 +1578,49 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
}
- if ((*Field)->getType()->isDependentType())
+ if ((*Field)->getType()->isDependentType() || AnyErrors)
continue;
QualType FT = Context.getBaseElementType((*Field)->getType());
- if (const RecordType* RT = FT->getAs<RecordType>()) {
- CXXConstructorDecl *Ctor =
- cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
- if (!Ctor) {
- Diag(Constructor->getLocation(), diag::err_missing_default_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 1 << (*Field)->getDeclName();
- Diag(Field->getLocation(), diag::note_field_decl);
- Diag(RT->getDecl()->getLocation(), diag::note_previous_decl)
- << Context.getTagDeclType(RT->getDecl());
+ if (FT->getAs<RecordType>()) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeMember(*Field);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid()) {
HadError = true;
continue;
}
-
- if (FT.isConstQualified() && Ctor->isTrivial()) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
- << 1 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- HadError = true;
- }
-
- // Don't create initializers for trivial constructors, since they don't
- // actually need to be run.
- if (Ctor->isTrivial())
- continue;
-
- ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this);
- if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0),
- Constructor->getLocation(), CtorArgs))
+
+ // Don't attach synthesized member initializers in a dependent
+ // context; they'll be regenerated a template instantiation
+ // time.
+ if (CurContext->isDependentContext())
continue;
- // FIXME: CXXBaseOrMemberInitializer should only contain a single
- // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary.
- ExprTemporaries.clear();
CXXBaseOrMemberInitializer *Member =
new (Context) CXXBaseOrMemberInitializer(Context,
*Field, SourceLocation(),
- Ctor,
SourceLocation(),
- CtorArgs.takeAs<Expr>(),
- CtorArgs.size(),
+ MemberInit.takeAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
- MarkDeclarationReferenced(Constructor->getLocation(), Ctor);
}
else if (FT->isReferenceType()) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 0 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
}
else if (FT.isConstQualified()) {
- Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+ Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
<< (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
@@ -1659,7 +1685,8 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits) {
+ MemInitTy **MemInits, unsigned NumMemInits,
+ bool AnyErrors) {
if (!ConstructorDecl)
return;
@@ -1709,7 +1736,7 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SetBaseOrMemberInitializers(Constructor,
reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits, false);
+ NumMemInits, false, AnyErrors);
if (Constructor->isDependentContext())
return;
@@ -1860,7 +1887,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
- SetBaseOrMemberInitializers(Constructor, 0, 0, false);
+ SetBaseOrMemberInitializers(Constructor, 0, 0, false, false);
}
namespace {
@@ -1978,13 +2005,15 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
if (!RT)
return false;
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
- return false;
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (CurrentRD && CurrentRD != RD)
return false;
+ // FIXME: is this reasonable? It matches current behavior, but....
+ if (!RD->getDefinition())
+ return false;
+
if (!RD->isAbstract())
return false;
@@ -2086,6 +2115,11 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->isInvalidDecl())
return;
+ // Set access bits correctly on the directly-declared conversions.
+ UnresolvedSetImpl *Convs = Record->getConversionFunctions();
+ for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I)
+ Convs->setAccess(I, (*I)->getAccess());
+
if (!Record->isAbstract()) {
// Collect all the pure virtual methods and see if this is an abstract
// class after all.
@@ -2227,7 +2261,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
VarDecl::None, 0);
- CopyConstructor->setParams(Context, &FromParam, 1);
+ CopyConstructor->setParams(&FromParam, 1);
ClassDecl->addDecl(CopyConstructor);
}
@@ -2311,7 +2345,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
VarDecl::None, 0);
- CopyAssignment->setParams(Context, &FromParam, 1);
+ CopyAssignment->setParams(&FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
// implicit from an explicit assignment operator.
@@ -2793,13 +2827,16 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
SourceLocation IdentLoc,
IdentifierInfo *II,
- SourceLocation LBrace) {
+ SourceLocation LBrace,
+ AttributeList *AttrList) {
NamespaceDecl *Namespc =
NamespaceDecl::Create(Context, CurContext, IdentLoc, II);
Namespc->setLBracLoc(LBrace);
Scope *DeclRegionScope = NamespcScope->getParent();
+ ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
+
if (II) {
// C++ [namespace.def]p2:
// The identifier in an original-namespace-definition shall not have been
@@ -3654,7 +3691,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
(NestedNameSpecifier *)SS.getScopeRep(),
IdentLoc, R.getFoundDecl());
- CurContext->addDecl(AliasDecl);
+ PushOnScopeChains(AliasDecl, S);
return DeclPtrTy::make(AliasDecl);
}
@@ -3668,13 +3705,16 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(Constructor->getDeclContext());
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) {
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Constructor;
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
}
+ CurContext = PreviousContext;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3683,6 +3723,10 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
+
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Destructor;
+
// C++ [class.dtor] p5
// Before the implicitly-declared default destructor for a class is
// implicitly defined, all the implicitly-declared default destructors
@@ -3729,8 +3773,11 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
Destructor->setInvalidDecl();
+ CurContext = PreviousContext;
+
return;
}
+ CurContext = PreviousContext;
Destructor->setUsed();
}
@@ -3745,6 +3792,9 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+ DeclContext *PreviousContext = CurContext;
+ CurContext = MethodDecl;
+
// C++[class.copy] p12
// Before the implicitly-declared copy assignment operator for a class is
// implicitly defined, all implicitly-declared copy assignment operators
@@ -3788,6 +3838,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
}
if (!err)
MethodDecl->setUsed();
+
+ CurContext = PreviousContext;
}
CXXMethodDecl *
@@ -3808,7 +3860,7 @@ Sema::getAssignOperatorMethod(SourceLocation CurrentLocation,
RHSType,
CurrentLocation));
Expr *Args[2] = { &*LHS, &*RHS };
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(CurrentLocation);
AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
CandidateSet);
OverloadCandidateSet::iterator Best;
@@ -3830,6 +3882,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl
= cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
+
+ DeclContext *PreviousContext = CurContext;
+ CurContext = CopyConstructor;
+
// C++ [class.copy] p209
// Before the implicitly-declared copy constructor for a class is
// implicitly defined, all the implicitly-declared copy constructors
@@ -3858,13 +3914,16 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
}
CopyConstructor->setUsed();
+
+ CurContext = PreviousContext;
}
Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
- bool RequiresZeroInit) {
+ bool RequiresZeroInit,
+ bool BaseInitialization) {
bool Elidable = false;
// C++ [class.copy]p15:
@@ -3897,7 +3956,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
}
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
- Elidable, move(ExprArgs), RequiresZeroInit);
+ Elidable, move(ExprArgs), RequiresZeroInit,
+ BaseInitialization);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3906,32 +3966,17 @@ Sema::OwningExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
- bool RequiresZeroInit) {
+ bool RequiresZeroInit,
+ bool BaseInitialization) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
- RequiresZeroInit));
-}
-
-Sema::OwningExprResult
-Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor,
- QualType Ty,
- SourceLocation TyBeginLoc,
- MultiExprArg Args,
- SourceLocation RParenLoc) {
- unsigned NumExprs = Args.size();
- Expr **Exprs = (Expr **)Args.release();
-
- MarkDeclarationReferenced(TyBeginLoc, Constructor);
- return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty,
- TyBeginLoc, Exprs,
- NumExprs, RParenLoc));
+ RequiresZeroInit, BaseInitialization));
}
-
bool Sema::InitializeVarWithConstructor(VarDecl *VD,
CXXConstructorDecl *Constructor,
MultiExprArg Exprs) {
@@ -3944,18 +3989,18 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
Expr *Temp = TempResult.takeAs<Expr>();
MarkDeclarationReferenced(VD->getLocation(), Constructor);
Temp = MaybeCreateCXXExprWithTemporaries(Temp);
- VD->setInit(Context, Temp);
+ VD->setInit(Temp);
return false;
}
-void Sema::FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType) {
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(
- DeclInitType->getAs<RecordType>()->getDecl());
- if (!ClassDecl->hasTrivialDestructor())
- if (CXXDestructorDecl *Destructor =
- const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context)))
- MarkDeclarationReferenced(VD->getLocation(), Destructor);
+void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
+ if (!ClassDecl->hasTrivialDestructor()) {
+ CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
+ MarkDeclarationReferenced(VD->getLocation(), Destructor);
+ CheckDestructorAccess(VD->getLocation(), Record);
+ }
}
/// AddCXXDirectInitializerToDecl - This action is called immediately after
@@ -3991,24 +4036,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
// exactly form was it (like the CodeGen) can handle both cases without
// special case code.
- // If either the declaration has a dependent type or if any of the expressions
- // is type-dependent, we represent the initialization via a ParenListExpr for
- // later use during template instantiation.
- if (VDecl->getType()->isDependentType() ||
- Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) {
- // Let clients know that initialization was done with a direct initializer.
- VDecl->setCXXDirectInitializer(true);
-
- // Store the initialization expressions as a ParenListExpr.
- unsigned NumExprs = Exprs.size();
- VDecl->setInit(Context,
- new (Context) ParenListExpr(Context, LParenLoc,
- (Expr **)Exprs.release(),
- NumExprs, RParenLoc));
- return;
- }
-
-
// C++ 8.5p11:
// The form of initialization (using parentheses or '=') is generally
// insignificant, but does matter when the entity being initialized has a
@@ -4017,7 +4044,8 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
if (const ArrayType *Array = Context.getAsArrayType(DeclInitType))
DeclInitType = Context.getBaseElementType(Array);
- if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
+ if (!VDecl->getType()->isDependentType() &&
+ RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
diag::err_typecheck_decl_incomplete_type)) {
VDecl->setInvalidDecl();
return;
@@ -4029,14 +4057,30 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
AbstractVariableType))
VDecl->setInvalidDecl();
- const VarDecl *Def = 0;
- if (VDecl->getDefinition(Def)) {
+ const VarDecl *Def;
+ if ((Def = VDecl->getDefinition()) && Def != VDecl) {
Diag(VDecl->getLocation(), diag::err_redefinition)
<< VDecl->getDeclName();
Diag(Def->getLocation(), diag::note_previous_definition);
VDecl->setInvalidDecl();
return;
}
+
+ // If either the declaration has a dependent type or if any of the
+ // expressions is type-dependent, we represent the initialization
+ // via a ParenListExpr for later use during template instantiation.
+ if (VDecl->getType()->isDependentType() ||
+ Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) {
+ // Let clients know that initialization was done with a direct initializer.
+ VDecl->setCXXDirectInitializer(true);
+
+ // Store the initialization expressions as a ParenListExpr.
+ unsigned NumExprs = Exprs.size();
+ VDecl->setInit(new (Context) ParenListExpr(Context, LParenLoc,
+ (Expr **)Exprs.release(),
+ NumExprs, RParenLoc));
+ return;
+ }
// Capture the variable that is being initialized and the style of
// initialization.
@@ -4056,11 +4100,11 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
}
Result = MaybeCreateCXXExprWithTemporaries(move(Result));
- VDecl->setInit(Context, Result.takeAs<Expr>());
+ VDecl->setInit(Result.takeAs<Expr>());
VDecl->setCXXDirectInitializer(true);
- if (VDecl->getType()->getAs<RecordType>())
- FinalizeVarWithDestructor(VDecl, DeclInitType);
+ if (const RecordType *Record = VDecl->getType()->getAs<RecordType>())
+ FinalizeVarWithDestructor(VDecl, Record);
}
/// \brief Add the applicable constructor candidates for an initialization
@@ -4112,10 +4156,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef,
Constructor->isDefaultConstructor())) {
if (ConstructorTmpl)
SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
/*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
- SemaRef.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ SemaRef.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ Args, NumArgs, CandidateSet);
}
}
}
@@ -4145,7 +4191,7 @@ Sema::TryInitializationByConstructor(QualType ClassType,
SourceLocation Loc,
InitializationKind Kind) {
// Build the overload candidate set
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
CandidateSet);
@@ -4167,92 +4213,6 @@ Sema::TryInitializationByConstructor(QualType ClassType,
return 0;
}
-/// \brief Perform initialization by constructor (C++ [dcl.init]p14), which
-/// may occur as part of direct-initialization or copy-initialization.
-///
-/// \param ClassType the type of the object being initialized, which must have
-/// class type.
-///
-/// \param ArgsPtr the arguments provided to initialize the object
-///
-/// \param Loc the source location where the initialization occurs
-///
-/// \param Range the source range that covers the entire initialization
-///
-/// \param InitEntity the name of the entity being initialized, if known
-///
-/// \param Kind the type of initialization being performed
-///
-/// \param ConvertedArgs a vector that will be filled in with the
-/// appropriately-converted arguments to the constructor (if initialization
-/// succeeded).
-///
-/// \returns the constructor used to initialize the object, if successful.
-/// Otherwise, emits a diagnostic and returns NULL.
-CXXConstructorDecl *
-Sema::PerformInitializationByConstructor(QualType ClassType,
- MultiExprArg ArgsPtr,
- SourceLocation Loc, SourceRange Range,
- DeclarationName InitEntity,
- InitializationKind Kind,
- ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) {
-
- // Build the overload candidate set
- Expr **Args = (Expr **)ArgsPtr.get();
- unsigned NumArgs = ArgsPtr.size();
- OverloadCandidateSet CandidateSet;
- AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
- CandidateSet);
-
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Loc, Best)) {
- case OR_Success:
- // We found a constructor. Break out so that we can convert the arguments
- // appropriately.
- break;
-
- case OR_No_Viable_Function:
- if (InitEntity)
- Diag(Loc, diag::err_ovl_no_viable_function_in_init)
- << InitEntity << Range;
- else
- Diag(Loc, diag::err_ovl_no_viable_function_in_init)
- << ClassType << Range;
- PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
- return 0;
-
- case OR_Ambiguous:
- if (InitEntity)
- Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
- else
- Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
- PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
- return 0;
-
- case OR_Deleted:
- if (InitEntity)
- Diag(Loc, diag::err_ovl_deleted_init)
- << Best->Function->isDeleted()
- << InitEntity << Range;
- else {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(ClassType->getAs<RecordType>()->getDecl());
- Diag(Loc, diag::err_ovl_deleted_init)
- << Best->Function->isDeleted()
- << RD->getDeclName() << Range;
- }
- PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
- return 0;
- }
-
- // Convert the arguments, fill in default arguments, etc.
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
- if (CompleteConstructorCall(Constructor, move(ArgsPtr), Loc, ConvertedArgs))
- return 0;
-
- return Constructor;
-}
-
/// \brief Given a constructor and the set of arguments provided for the
/// constructor, convert the arguments and add any required default arguments
/// to form a proper call to this constructor.
@@ -4453,7 +4413,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+ ICS->Standard.setToType(0, T2);
+ ICS->Standard.setToType(1, T1);
+ ICS->Standard.setToType(2, T1);
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = true;
ICS->Standard.RRefBinding = false;
@@ -4486,7 +4448,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(DeclLoc);
const UnresolvedSetImpl *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
@@ -4509,10 +4471,11 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (Conv->getConversionType()->isLValueReferenceType() &&
(AllowExplicit || !Conv->isExplicit())) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, ActingDC,
+ AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), ActingDC,
Init, DeclType, CandidateSet);
else
- AddConversionCandidate(Conv, ActingDC, Init, DeclType, CandidateSet);
+ AddConversionCandidate(Conv, I.getAccess(), ActingDC, Init,
+ DeclType, CandidateSet);
}
}
@@ -4606,6 +4569,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) {
if (!ICS)
Diag(DeclLoc, diag::err_not_reference_to_const_init)
+ << T1.isVolatileQualified()
<< T1 << int(InitLvalue != Expr::LV_Valid)
<< T2 << Init->getSourceRange();
return true;
@@ -4642,7 +4606,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+ ICS->Standard.setToType(0, T2);
+ ICS->Standard.setToType(1, T1);
+ ICS->Standard.setToType(2, T1);
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = false;
ICS->Standard.RRefBinding = isRValRef;
@@ -5611,7 +5577,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType();
- if (Context.hasSameType(NewTy, OldTy))
+ if (Context.hasSameType(NewTy, OldTy) ||
+ NewTy->isDependentType() || OldTy->isDependentType())
return false;
// Check if the return types are covariant
@@ -5665,8 +5632,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}
// Check if we the conversion from derived to base is valid.
- if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
- diag::err_covariant_return_inaccessible_base,
+ if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance,
diag::err_covariant_return_ambiguous_derived_to_base_conv,
// FIXME: Should this point to the return type?
New->getLocation(), SourceRange(), New->getDeclName())) {
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 1b07d19882e0..1e9b56a90ed6 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -446,18 +446,19 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
assert (CatDecl && "MatchOneProtocolPropertiesInClass");
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = (*P);
- ObjCCategoryDecl::prop_iterator CP, CE;
- // Is this property already in category's list of properties?
- for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
- if ((*CP)->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
- }
+ if (!CatDecl->IsClassExtension())
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Pr = (*P);
+ ObjCCategoryDecl::prop_iterator CP, CE;
+ // Is this property already in category's list of properties?
+ for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
+ if ((*CP)->getIdentifier() == Pr->getIdentifier())
+ break;
+ if (CP != CE)
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+ }
return;
}
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
@@ -596,44 +597,59 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc) {
- ObjCCategoryDecl *CDecl =
- ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
- CategoryLoc, CategoryName);
- // FIXME: PushOnScopeChains?
- CurContext->addDecl(CDecl);
-
+ ObjCCategoryDecl *CDecl = 0;
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
- /// Check that class of this category is already completely declared.
- if (!IDecl || IDecl->isForwardDecl()) {
- CDecl->setInvalidDecl();
- Diag(ClassLoc, diag::err_undef_interface) << ClassName;
- return DeclPtrTy::make(CDecl);
- }
+ if (!CategoryName) {
+ // Class extensions require a special treatment. Use an existing one.
+ for (CDecl = IDecl->getCategoryList(); CDecl;
+ CDecl = CDecl->getNextClassCategory())
+ if (CDecl->IsClassExtension())
+ break;
+ }
+ if (!CDecl) {
+ CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
+ CategoryLoc, CategoryName);
+ // FIXME: PushOnScopeChains?
+ CurContext->addDecl(CDecl);
+
+ /// Check that class of this category is already completely declared.
+ if (!IDecl || IDecl->isForwardDecl()) {
+ CDecl->setInvalidDecl();
+ Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+ return DeclPtrTy::make(CDecl);
+ }
- CDecl->setClassInterface(IDecl);
+ CDecl->setClassInterface(IDecl);
+ // Insert first use of class extension to the list of class's categories.
+ if (!CategoryName)
+ CDecl->insertNextClassCategory();
+ }
// If the interface is deprecated, warn about it.
(void)DiagnoseUseOfDecl(IDecl, ClassLoc);
- /// Check for duplicate interface declaration for this category
- ObjCCategoryDecl *CDeclChain;
- for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
- CDeclChain = CDeclChain->getNextClassCategory()) {
- if (CategoryName && CDeclChain->getIdentifier() == CategoryName) {
- Diag(CategoryLoc, diag::warn_dup_category_def)
- << ClassName << CategoryName;
- Diag(CDeclChain->getLocation(), diag::note_previous_definition);
- break;
+ if (CategoryName) {
+ /// Check for duplicate interface declaration for this category
+ ObjCCategoryDecl *CDeclChain;
+ for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
+ CDeclChain = CDeclChain->getNextClassCategory()) {
+ if (CDeclChain->getIdentifier() == CategoryName) {
+ // Class extensions can be declared multiple times.
+ Diag(CategoryLoc, diag::warn_dup_category_def)
+ << ClassName << CategoryName;
+ Diag(CDeclChain->getLocation(), diag::note_previous_definition);
+ break;
+ }
}
+ if (!CDeclChain)
+ CDecl->insertNextClassCategory();
}
- if (!CDeclChain)
- CDecl->insertNextClassCategory();
if (NumProtoRefs) {
CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
// Protocols in the class extension belong to the class.
- if (!CDecl->getIdentifier())
+ if (CDecl->IsClassExtension())
IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
NumProtoRefs, ProtoLocs,
Context);
@@ -1102,11 +1118,12 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
CollectImmediateProperties((*PI), PropMap);
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
- E = CATDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- PropMap[Prop->getIdentifier()] = Prop;
- }
+ if (!CATDecl->IsClassExtension())
+ for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
+ E = CATDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
// scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
E = CATDecl->protocol_end(); PI != E; ++PI)
@@ -1127,6 +1144,46 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
+/// LookupPropertyDecl - Looks up a property in the current class and all
+/// its protocols.
+ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ IdentifierInfo *II) {
+ if (const ObjCInterfaceDecl *IDecl =
+ dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ else if (const ObjCProtocolDecl *PDecl =
+ dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ if (Prop->getIdentifier() == II)
+ return Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI) {
+ ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
+ if (Prop)
+ return Prop;
+ }
+ }
+ return 0;
+}
+
+
void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const llvm::DenseSet<Selector>& InsMap) {
@@ -1149,7 +1206,14 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop))
continue;
-
+ if (LangOpts.ObjCNonFragileABI2) {
+ ActOnPropertyImplDecl(IMPDecl->getLocation(),
+ SourceLocation(),
+ true, DeclPtrTy::make(IMPDecl),
+ Prop->getIdentifier(),
+ Prop->getIdentifier());
+ continue;
+ }
if (!InsMap.count(Prop->getGetterName())) {
Diag(Prop->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
@@ -1214,7 +1278,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
// Check class extensions (unnamed categories)
for (ObjCCategoryDecl *Categories = I->getCategoryList();
Categories; Categories = Categories->getNextClassCategory()) {
- if (!Categories->getIdentifier()) {
+ if (Categories->IsClassExtension()) {
ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
break;
}
@@ -1222,7 +1286,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For extended class, unimplemented methods in its protocols will
// be reported in the primary class.
- if (C->getIdentifier()) {
+ if (!C->IsClassExtension()) {
for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
@@ -1443,7 +1507,8 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
- Entry.Next = new ObjCMethodList(Method, Entry.Next);
+ ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+ Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
}
// FIXME: Finish implementing -Wno-strict-selector-match.
@@ -1506,7 +1571,8 @@ void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
if (!match) {
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
- struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next);
+ ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+ ObjCMethodList *OMI = new (Mem) ObjCMethodList(Method, FirstMethod.Next);
FirstMethod.Next = OMI;
}
}
@@ -1777,17 +1843,18 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
// Compare protocol properties with those in category
CompareProperties(C, DeclPtrTy::make(C));
- if (C->getIdentifier() == 0)
+ if (C->IsClassExtension())
DiagnoseClassExtensionDupMethods(C, C->getClassInterface());
}
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) {
- // ProcessPropertyDecl is responsible for diagnosing conflicts with any
- // user-defined setter/getter. It also synthesizes setter/getter methods
- // and adds them to the DeclContext and global method pools.
- for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
- E = CDecl->prop_end();
- I != E; ++I)
- ProcessPropertyDecl(*I, CDecl);
+ if (CDecl->getIdentifier())
+ // ProcessPropertyDecl is responsible for diagnosing conflicts with any
+ // user-defined setter/getter. It also synthesizes setter/getter methods
+ // and adds them to the DeclContext and global method pools.
+ for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
+ E = CDecl->prop_end();
+ I != E; ++I)
+ ProcessPropertyDecl(*I, CDecl);
CDecl->setAtEndRange(AtEnd);
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
@@ -2088,7 +2155,22 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// May modify Attributes.
CheckObjCPropertyAttributes(T, AtLoc, Attributes);
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
- if (!CDecl->getIdentifier()) {
+ if (CDecl->IsClassExtension()) {
+ // Diagnose if this property is already in continuation class.
+ DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
+ assert(DC && "ClassDecl is not a DeclContext");
+ DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier());
+ if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
+ Diag(AtLoc, diag::err_duplicate_property);
+ Diag((*Found.first)->getLocation(), diag::note_property_declare);
+ return DeclPtrTy();
+ }
+ ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
+ FD.D.getIdentifierLoc(),
+ FD.D.getIdentifier(),
+ AtLoc, T);
+ DC->addDecl(PDecl);
+
// This is a continuation class. property requires special
// handling.
if ((CCPrimary = CDecl->getClassInterface())) {
@@ -2152,6 +2234,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
ProcessPropertyDecl(PIDecl, CCPrimary);
return DeclPtrTy();
}
+
// No matching property found in the primary class. Just fall thru
// and add property to continuation class's primary class.
ClassDecl = CCPrimary;
@@ -2246,6 +2329,28 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
return DeclPtrTy::make(PDecl);
}
+ObjCIvarDecl*
+Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
+ IdentifierInfo *NameII) {
+ ObjCIvarDecl *Ivar = 0;
+ ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
+ if (Prop && !Prop->isInvalidDecl()) {
+ DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl);
+ QualType PropType = Context.getCanonicalType(Prop->getType());
+ assert(EnclosingContext &&
+ "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar");
+ Ivar = ObjCIvarDecl::Create(Context, EnclosingContext,
+ Prop->getLocation(),
+ NameII, PropType, /*Dinfo=*/0,
+ ObjCIvarDecl::Public,
+ (Expr *)0);
+ Ivar->setLexicalDeclContext(IDecl);
+ IDecl->addDecl(Ivar);
+ Prop->setPropertyIvarDecl(Ivar);
+ }
+ return Ivar;
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
/// as @synthesize or @dynamic.
@@ -2283,7 +2388,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
}
if (const ObjCCategoryDecl *CD =
dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
- if (CD->getIdentifier()) {
+ if (!CD->IsClassExtension()) {
Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
Diag(property->getLocation(), diag::note_property_declare);
return DeclPtrTy();
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 7e2a98d0bf1f..9be411b552ad 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -12,10 +12,11 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
namespace clang {
@@ -92,6 +93,52 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
return FnT->hasExceptionSpec();
}
+bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+ bool MissingEmptyExceptionSpecification = false;
+ if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
+ diag::note_previous_declaration,
+ Old->getType()->getAs<FunctionProtoType>(),
+ Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(),
+ New->getLocation(),
+ &MissingEmptyExceptionSpecification))
+ return false;
+
+ // The failure was something other than an empty exception
+ // specification; return an error.
+ if (!MissingEmptyExceptionSpecification)
+ return true;
+
+ // The new function declaration is only missing an empty exception
+ // specification "throw()". If the throw() specification came from a
+ // function in a system header that has C linkage, just add an empty
+ // exception specification to the "new" declaration. This is an
+ // egregious workaround for glibc, which adds throw() specifications
+ // to many libc functions as an optimization. Unfortunately, that
+ // optimization isn't permitted by the C++ standard, so we're forced
+ // to work around it here.
+ if (isa<FunctionProtoType>(New->getType()) &&
+ Context.getSourceManager().isInSystemHeader(Old->getLocation()) &&
+ Old->isExternC()) {
+ const FunctionProtoType *NewProto
+ = cast<FunctionProtoType>(New->getType());
+ QualType NewType = Context.getFunctionType(NewProto->getResultType(),
+ NewProto->arg_type_begin(),
+ NewProto->getNumArgs(),
+ NewProto->isVariadic(),
+ NewProto->getTypeQuals(),
+ true, false, 0, 0,
+ NewProto->getNoReturnAttr(),
+ NewProto->getCallConv());
+ New->setType(NewType);
+ return false;
+ }
+
+ Diag(New->getLocation(), diag::err_mismatched_exception_spec);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ return true;
+}
+
/// 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
@@ -111,12 +158,26 @@ bool Sema::CheckEquivalentExceptionSpec(
bool Sema::CheckEquivalentExceptionSpec(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc) {
+ const FunctionProtoType *New, SourceLocation NewLoc,
+ bool *MissingEmptyExceptionSpecification) {
+ if (MissingEmptyExceptionSpecification)
+ *MissingEmptyExceptionSpecification = false;
+
bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
if (OldAny && NewAny)
return false;
if (OldAny || NewAny) {
+ if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() &&
+ !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 &&
+ !New->hasExceptionSpec()) {
+ // The old type has a throw() exception specification and the
+ // new type has no exception specification, and the caller asked
+ // to handle this itself.
+ *MissingEmptyExceptionSpecification = true;
+ return true;
+ }
+
Diag(NewLoc, DiagID);
if (NoteID.getDiagID() != 0)
Diag(OldLoc, NoteID);
@@ -232,8 +293,22 @@ bool Sema::CheckExceptionSpecSubset(
if (Paths.isAmbiguous(CanonicalSuperT))
continue;
- if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
- continue;
+ // Do this check from a context without privileges.
+ switch (CheckBaseClassAccess(SourceLocation(), false,
+ CanonicalSuperT, CanonicalSubT,
+ Paths.front(),
+ /*ForceCheck*/ true,
+ /*ForceUnprivileged*/ true,
+ ADK_quiet)) {
+ case AR_accessible: break;
+ case AR_inaccessible: continue;
+ case AR_dependent:
+ llvm_unreachable("access check dependent for unprivileged context");
+ break;
+ case AR_delayed:
+ llvm_unreachable("access check delayed in non-declaration");
+ break;
+ }
Contained = true;
break;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 50976f7b704b..633884f673ba 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,7 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -200,6 +200,28 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
}
}
+void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) {
+ DefaultFunctionArrayConversion(E);
+
+ QualType Ty = E->getType();
+ assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type");
+ if (!Ty->isDependentType() && Ty.hasQualifiers() &&
+ (!getLangOptions().CPlusPlus || !Ty->isRecordType()) &&
+ E->isLvalue(Context) == Expr::LV_Valid) {
+ // C++ [conv.lval]p1:
+ // [...] If T is a non-class type, the type of the rvalue is the
+ // cv-unqualified version of T. Otherwise, the type of the
+ // rvalue is T
+ //
+ // C99 6.3.2.1p2:
+ // If the lvalue has qualified type, the value has the unqualified
+ // version of the type of the lvalue; otherwise, the value has the
+ // type of the lvalue.
+ ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp);
+ }
+}
+
+
/// 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
@@ -233,7 +255,7 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
return Expr;
}
- DefaultFunctionArrayConversion(Expr);
+ DefaultFunctionArrayLvalueConversion(Expr);
return Expr;
}
@@ -678,7 +700,13 @@ static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) {
R.resolveKind();
}
+/// Determines whether the given record is "fully-formed" at the given
+/// location, i.e. whether a qualified lookup into it is assured of
+/// getting consistent results already.
static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) {
+ if (!Record->hasDefinition())
+ return false;
+
for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
E = Record->bases_end(); I != E; ++I) {
CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
@@ -686,7 +714,7 @@ static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) {
if (!BaseRT) return false;
CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!BaseRecord->isDefinition() ||
+ if (!BaseRecord->hasDefinition() ||
!IsFullyFormedScope(SemaRef, BaseRecord))
return false;
}
@@ -719,7 +747,7 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
if (Bases.count(Record->getCanonicalDecl()))
return false;
- RecordDecl *RD = Record->getDefinition(SemaRef.Context);
+ RecordDecl *RD = Record->getDefinition();
if (!RD) return false;
Record = cast<CXXRecordDecl>(RD);
@@ -1243,9 +1271,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
else
LookForIvars = (Lookup.isSingleResult() &&
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod());
-
+ ObjCInterfaceDecl *IFace = 0;
if (LookForIvars) {
- ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ IFace = getCurMethodDecl()->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
// Diagnose using an ivar in a class method.
@@ -1314,6 +1342,11 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
}
}
}
+ if (LangOpts.ObjCNonFragileABI2 && LookForIvars && Lookup.empty()) {
+ ObjCIvarDecl *Ivar = SynthesizeNewPropertyIvar(IFace, II);
+ if (Ivar)
+ return LookupInObjCMethod(Lookup, S, II, AllowBuiltinCreation);
+ }
// Sentinel value saying that we didn't do anything special.
return Owned((Expr*) 0);
}
@@ -1487,7 +1520,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
bool NeedsADL) {
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
- if (!NeedsADL && R.isSingleResult())
+ if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>())
return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl());
// We only need to check the declaration if there's exactly one
@@ -1497,16 +1530,20 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl()))
return ExprError();
+ // Otherwise, just build an unresolved lookup expression. Suppress
+ // any lookup-related diagnostics; we'll hash these out later, when
+ // we've picked a target.
+ R.suppressDiagnostics();
+
bool Dependent
= UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), 0);
UnresolvedLookupExpr *ULE
- = UnresolvedLookupExpr::Create(Context, Dependent,
+ = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(),
(NestedNameSpecifier*) SS.getScopeRep(),
SS.getRange(),
R.getLookupName(), R.getNameLoc(),
NeedsADL, R.isOverloadedResult());
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- ULE->addDecl(*I);
+ ULE->addDecls(R.begin(), R.end());
return Owned(ULE);
}
@@ -1616,8 +1653,7 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
if (cast<DeclContext>(currentDecl)->isDependentContext()) {
ResTy = Context.DependentTy;
} else {
- unsigned Length =
- PredefinedExpr::ComputeName(Context, IT, currentDecl).length();
+ unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
ResTy = Context.CharTy.withConst();
@@ -1642,6 +1678,8 @@ Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
Ty = Context.IntTy; // 'x' and L'x' -> int in C.
else if (Literal.isWide())
Ty = Context.WCharTy; // L'x' -> wchar_t in C++.
+ else if (Literal.isMultiChar())
+ Ty = Context.IntTy; // 'wxyz' -> int in C++.
else
Ty = Context.CharTy; // 'x' -> char in C++
@@ -2029,8 +2067,9 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc,
Expr *RHSExp = static_cast<Expr*>(Idx.get());
// Perform default conversions.
- DefaultFunctionArrayConversion(LHSExp);
- DefaultFunctionArrayConversion(RHSExp);
+ if (!LHSExp->getType()->getAs<VectorType>())
+ DefaultFunctionArrayLvalueConversion(LHSExp);
+ DefaultFunctionArrayLvalueConversion(RHSExp);
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
@@ -2072,7 +2111,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc,
ResultType = VTy->getElementType();
} else if (LHSTy->isArrayType()) {
// If we see an array that wasn't promoted by
- // DefaultFunctionArrayConversion, it must be an array that
+ // DefaultFunctionArrayLvalueConversion, it must be an array that
// wasn't promoted because of the C90 rule that doesn't
// allow promoting non-lvalue arrays. Warn, then
// force the promotion here.
@@ -2542,7 +2581,11 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
bool Dependent =
BaseExprType->isDependentType() ||
R.isUnresolvableResult() ||
- UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
+ OverloadExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
+
+ // Suppress any lookup-related diagnostics; we'll do these when we
+ // pick a member.
+ R.suppressDiagnostics();
UnresolvedMemberExpr *MemExpr
= UnresolvedMemberExpr::Create(Context, Dependent,
@@ -2552,8 +2595,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
Qualifier, SS.getRange(),
MemberName, MemberLoc,
TemplateArgs);
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- MemExpr->addDecl(*I);
+ MemExpr->addDecls(R.begin(), R.end());
return Owned(MemExpr);
}
@@ -3001,7 +3043,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (DiagnoseUseOfDecl(OMD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel,
+ return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel,
OMD->getResultType(),
OMD, OpLoc, MemberLoc,
NULL, 0));
@@ -3248,7 +3290,8 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
// Instantiate the expression.
- MultiLevelTemplateArgumentList ArgList = getTemplateInstantiationArgs(FD);
+ MultiLevelTemplateArgumentList ArgList
+ = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true);
InstantiatingTemplate Inst(*this, CallLoc, Param,
ArgList.getInnermost().getFlatArgumentList(),
@@ -3770,7 +3813,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
ConversionDecl);
- DefaultFunctionArrayConversion(castExpr);
+ DefaultFunctionArrayLvalueConversion(castExpr);
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
@@ -4807,7 +4850,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
//
// Suppress this for references: C++ 8.5.3p5.
if (!lhsType->isReferenceType())
- DefaultFunctionArrayConversion(rExpr);
+ DefaultFunctionArrayLvalueConversion(rExpr);
Sema::AssignConvertType result =
CheckAssignmentConstraints(lhsType, rExpr->getType());
@@ -5690,6 +5733,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_SubObjCPropertySetting:
Diag = diag::error_no_subobject_property_setting;
break;
+ case Expr::MLV_SubObjCPropertyGetterSetting:
+ Diag = diag::error_no_subobject_property_getter_setting;
+ break;
}
SourceRange Assign;
@@ -5770,7 +5816,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS,
// C99 6.5.17
QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) {
// Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions.
- DefaultFunctionArrayConversion(RHS);
+ // C++ does not perform this conversion (C++ [expr.comma]p1).
+ if (!getLangOptions().CPlusPlus)
+ DefaultFunctionArrayLvalueConversion(RHS);
// FIXME: Check that RHS type is complete in C mode (it's legal for it to be
// incomplete in C++).
@@ -5961,8 +6009,7 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
Diag(OpLoc, diag::err_typecheck_address_of)
<< "bit-field" << op->getSourceRange();
return QualType();
- } else if (isa<ExtVectorElementExpr>(op) || (isa<ArraySubscriptExpr>(op) &&
- cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType())){
+ } else if (op->refersToVectorElement()) {
// The operand cannot be an element of a vector
Diag(OpLoc, diag::err_typecheck_address_of)
<< "vector element" << op->getSourceRange();
@@ -6337,17 +6384,11 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
// the arguments.
- FunctionSet Functions;
+ UnresolvedSet<16> Functions;
OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
- if (OverOp != OO_None) {
- if (S)
- LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
- Functions);
- Expr *Args[2] = { lhs, rhs };
- DeclarationName OpName
- = Context.DeclarationNames.getCXXOperatorName(OverOp);
- ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions);
- }
+ if (S && OverOp != OO_None)
+ LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
+ Functions);
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
@@ -6383,7 +6424,7 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = CheckAddressOfOperand(Input, OpLoc);
break;
case UnaryOperator::Deref:
- DefaultFunctionArrayConversion(Input);
+ DefaultFunctionArrayLvalueConversion(Input);
resultType = CheckIndirectionOperand(Input, OpLoc);
break;
case UnaryOperator::Plus:
@@ -6420,7 +6461,7 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
break;
case UnaryOperator::LNot: // logical negation
// Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
- DefaultFunctionArrayConversion(Input);
+ DefaultFunctionArrayLvalueConversion(Input);
resultType = Input->getType();
if (resultType->isDependentType())
break;
@@ -6456,16 +6497,11 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
// the arguments.
- FunctionSet Functions;
+ UnresolvedSet<16> Functions;
OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);
- if (OverOp != OO_None) {
- if (S)
- LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
- Functions);
- DeclarationName OpName
- = Context.DeclarationNames.getCXXOperatorName(OverOp);
- ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions);
- }
+ if (S && OverOp != OO_None)
+ LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
+ Functions);
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
}
@@ -6595,7 +6631,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
// Promote the array so it looks more like a normal array subscript
// expression.
- DefaultFunctionArrayConversion(Res);
+ DefaultFunctionArrayLvalueConversion(Res);
// C99 6.5.2.1p1
Expr *Idx = static_cast<Expr*>(OC.U.E);
@@ -6772,6 +6808,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
return;
}
+
+ CurBlock->ReturnType = RetTy;
return;
}
@@ -6792,11 +6830,18 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// empty arg list, don't push any params.
CurBlock->isVariadic = false;
} else if (FTI.hasPrototype) {
- for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
- CurBlock->Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>());
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
+ if (Param->getIdentifier() == 0 &&
+ !Param->isImplicit() &&
+ !Param->isInvalidDecl() &&
+ !getLangOptions().CPlusPlus)
+ Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+ CurBlock->Params.push_back(Param);
+ }
CurBlock->isVariadic = FTI.isVariadic;
}
- CurBlock->TheDecl->setParams(Context, CurBlock->Params.data(),
+ CurBlock->TheDecl->setParams(CurBlock->Params.data(),
CurBlock->Params.size());
CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
@@ -7255,6 +7300,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// FIXME: keep track of references to static functions
Function->setUsed(true);
+
return;
}
@@ -7390,7 +7436,7 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
DiagnoseAssignmentAsCondition(E);
if (!E->isTypeDependent()) {
- DefaultFunctionArrayConversion(E);
+ DefaultFunctionArrayLvalueConversion(E);
QualType T = E->getType();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index b004fc3dba72..9eeda54299ae 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -72,18 +72,17 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
if (const RecordType *RecordT = T->getAs<RecordType>()) {
CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
// C++ [expr.typeid]p3:
+ // [...] If the type of the expression is a class type, the class
+ // shall be completely-defined.
+ if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid))
+ return ExprError();
+
+ // C++ [expr.typeid]p3:
// When typeid is applied to an expression other than an lvalue of a
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
isUnevaluatedOperand = false;
- else {
- // C++ [expr.typeid]p3:
- // [...] If the type of the expression is a class type, the class
- // shall be completely-defined.
- if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid))
- return ExprError();
- }
}
// C++ [expr.typeid]p4:
@@ -195,7 +194,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
MultiExprArg exprs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
- assert(TypeRep && "Missing type!");
+ if (!TypeRep)
+ return ExprError();
+
TypeSourceInfo *TInfo;
QualType Ty = GetTypeFromParser(TypeRep, &TInfo);
if (!TInfo)
@@ -263,29 +264,18 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
if (NumExprs > 1 || !Record->hasTrivialConstructor() ||
!Record->hasTrivialDestructor()) {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- CXXConstructorDecl *Constructor
- = PerformInitializationByConstructor(Ty, move(exprs),
- TypeRange.getBegin(),
- SourceRange(TypeRange.getBegin(),
- RParenLoc),
- DeclarationName(),
- InitializationKind::CreateDirect(TypeRange.getBegin(),
- LParenLoc,
- RParenLoc),
- ConstructorArgs);
-
- if (!Constructor)
- return ExprError();
-
- OwningExprResult Result =
- BuildCXXTemporaryObjectExpr(Constructor, Ty, TyBeginLoc,
- move_arg(ConstructorArgs), RParenLoc);
- if (Result.isInvalid())
- return ExprError();
-
- return MaybeBindToTemporary(Result.takeAs<Expr>());
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty);
+ InitializationKind Kind
+ = NumExprs ? InitializationKind::CreateDirect(TypeRange.getBegin(),
+ LParenLoc, RParenLoc)
+ : InitializationKind::CreateValue(TypeRange.getBegin(),
+ LParenLoc, RParenLoc);
+ InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
+ OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ move(exprs));
+
+ // FIXME: Improve AST representation?
+ return move(Result);
}
// Fall through to value-initialize an object of class type that
@@ -530,10 +520,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
PlacementArgs.release();
ConstructorArgs.release();
ArraySizeE.release();
- return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs,
- NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init,
- ConsArgs, NumConsArgs, OperatorDelete, ResultType,
- StartLoc, Init ? ConstructorRParen : SourceLocation()));
+ return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
+ PlaceArgs, NumPlaceArgs, ParenTypeId,
+ ArraySize, Constructor, Init,
+ ConsArgs, NumConsArgs, OperatorDelete,
+ ResultType, StartLoc,
+ Init ? ConstructorRParen :
+ SourceLocation()));
}
/// CheckAllocatedType - Checks that a type is suitable as the allocated type
@@ -636,19 +629,24 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// FIXME: handle ambiguity
- OverloadCandidateSet Candidates;
+ OverloadCandidateSet Candidates(StartLoc);
for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
// static, so don't use AddMemberCandidate.
- if (FunctionDecl *Fn =
- dyn_cast<FunctionDecl>((*Alloc)->getUnderlyingDecl())) {
- AddOverloadCandidate(Fn, Args, NumArgs, Candidates,
- /*SuppressUserConversions=*/false);
+
+ if (FunctionTemplateDecl *FnTemplate =
+ dyn_cast<FunctionTemplateDecl>((*Alloc)->getUnderlyingDecl())) {
+ AddTemplateOverloadCandidate(FnTemplate, Alloc.getAccess(),
+ /*ExplicitTemplateArgs=*/0, Args, NumArgs,
+ Candidates,
+ /*SuppressUserConversions=*/false);
continue;
- }
-
- // FIXME: Handle function templates
+ }
+
+ FunctionDecl *Fn = cast<FunctionDecl>((*Alloc)->getUnderlyingDecl());
+ AddOverloadCandidate(Fn, Alloc.getAccess(), Args, NumArgs, Candidates,
+ /*SuppressUserConversions=*/false);
}
// Do the resolution.
@@ -779,12 +777,16 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
DeclContext::lookup_iterator Alloc, AllocEnd;
for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Name);
Alloc != AllocEnd; ++Alloc) {
- // FIXME: Do we need to check for default arguments here?
- FunctionDecl *Func = cast<FunctionDecl>(*Alloc);
- if (Func->getNumParams() == 1 &&
+ // Only look at non-template functions, as it is the predefined,
+ // non-templated allocation function we are trying to declare here.
+ if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) {
+ QualType InitialParamType =
Context.getCanonicalType(
- Func->getParamDecl(0)->getType().getUnqualifiedType()) == Argument)
- return;
+ Func->getParamDecl(0)->getType().getUnqualifiedType());
+ // FIXME: Do we need to check for default arguments here?
+ if (Func->getNumParams() == 1 && InitialParamType == Argument)
+ return;
+ }
}
}
@@ -812,7 +814,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
0, Argument, /*TInfo=*/0,
VarDecl::None, 0);
- Alloc->setParams(Context, &Param, 1);
+ Alloc->setParams(&Param, 1);
// FIXME: Also add this declaration to the IdentifierResolver, but
// make sure it is at the end of the chain to coincide with the
@@ -1487,9 +1489,9 @@ QualType Sema::CheckPointerToMemberOperands(
static QualType TargetType(const ImplicitConversionSequence &ICS) {
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
- return ICS.Standard.getToType();
+ return ICS.Standard.getToType(2);
case ImplicitConversionSequence::UserDefinedConversion:
- return ICS.UserDefined.After.getToType();
+ return ICS.UserDefined.After.getToType(2);
case ImplicitConversionSequence::AmbiguousConversion:
return ICS.Ambiguous.getToType();
case ImplicitConversionSequence::EllipsisConversion:
@@ -1587,7 +1589,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
SourceLocation Loc) {
Expr *Args[2] = { LHS, RHS };
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet);
OverloadCandidateSet::iterator Best;
@@ -1689,8 +1691,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (LVoid || RVoid) {
// ... then the [l2r] conversions are performed on the second and third
// operands ...
- DefaultFunctionArrayConversion(LHS);
- DefaultFunctionArrayConversion(RHS);
+ DefaultFunctionArrayLvalueConversion(LHS);
+ DefaultFunctionArrayLvalueConversion(RHS);
LTy = LHS->getType();
RTy = RHS->getType();
@@ -1776,8 +1778,8 @@ 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.
- DefaultFunctionArrayConversion(LHS);
- DefaultFunctionArrayConversion(RHS);
+ DefaultFunctionArrayLvalueConversion(LHS);
+ DefaultFunctionArrayLvalueConversion(RHS);
LTy = LHS->getType();
RTy = RHS->getType();
@@ -1987,10 +1989,8 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (!RT)
return Owned(E);
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDestructor())
- return Owned(E);
-
+ // If this is the result of a call expression, our source might
+ // actually be a reference, in which case we shouldn't bind.
if (CallExpr *CE = dyn_cast<CallExpr>(E)) {
QualType Ty = CE->getCallee()->getType();
if (const PointerType *PT = Ty->getAs<PointerType>())
@@ -2000,6 +2000,13 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (FTy->getResultType()->isReferenceType())
return Owned(E);
}
+
+ // That should be enough to guarantee that this type is complete.
+ // If it has a trivial destructor, we can avoid the extra copy.
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->hasTrivialDestructor())
+ return Owned(E);
+
CXXTemporary *Temp = CXXTemporary::Create(Context,
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index ea8f4e3e890f..0c5d8efa288b 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -470,11 +470,13 @@ Sema::ExprResult Sema::ActOnClassMessage(
// now, we simply pass the "super" identifier through (which isn't consistent
// with instance methods.
if (isSuper)
- return new (Context) ObjCMessageExpr(receiverName, Sel, returnType, Method,
- lbrac, rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, receiverName, Sel, returnType,
+ Method, lbrac, rbrac, ArgExprs,
+ NumArgs);
else
- return new (Context) ObjCMessageExpr(ClassDecl, Sel, returnType, Method,
- lbrac, rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, ClassDecl, Sel, returnType,
+ Method, lbrac, rbrac, ArgExprs,
+ NumArgs);
}
// ActOnInstanceMessage - used for both unary and keyword messages.
@@ -492,7 +494,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- DefaultFunctionArrayConversion(RExpr);
+ DefaultFunctionArrayLvalueConversion(RExpr);
QualType returnType;
QualType ReceiverCType =
@@ -521,8 +523,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
+ Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
}
// Handle messages to id.
@@ -536,8 +539,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
+ Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
}
// Handle messages to Class.
@@ -582,8 +586,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
+ Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
}
ObjCMethodDecl *Method = 0;
@@ -665,7 +670,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac,
- rbrac, ArgExprs, NumArgs);
+ return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method,
+ lbrac, rbrac, ArgExprs, NumArgs);
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index fd62e1afce4f..7b4a41777b6a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -66,40 +66,6 @@ static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) {
return 0;
}
-static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
- bool DirectInit, Sema &S) {
- // Get the type before calling CheckSingleAssignmentConstraints(), since
- // it can promote the expression.
- QualType InitType = Init->getType();
-
- if (S.getLangOptions().CPlusPlus) {
- // FIXME: I dislike this error message. A lot.
- if (S.PerformImplicitConversion(Init, DeclType,
- Sema::AA_Initializing, DirectInit)) {
- ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet;
- if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined,
- CandidateSet,
- true, false, false) != OR_Ambiguous)
- return S.Diag(Init->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << Sema::AA_Initializing
- << Init->getSourceRange();
- S.Diag(Init->getSourceRange().getBegin(),
- diag::err_typecheck_convert_ambiguous)
- << DeclType << Init->getType() << Init->getSourceRange();
- S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, &Init, 1);
- return true;
- }
- return false;
- }
-
- Sema::AssignConvertType ConvTy =
- S.CheckSingleAssignmentConstraints(DeclType, Init);
- return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
- InitType, Init, Sema::AA_Initializing);
-}
-
static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) {
// Get the length of the string as parsed.
uint64_t StrLength =
@@ -174,47 +140,57 @@ class InitListChecker {
std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
- void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
+ void CheckImplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *ParentIList, QualType T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckExplicitInitList(InitListExpr *IList, QualType &T,
+ void CheckExplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
+ void CheckListElementTypes(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckSubElementType(InitListExpr *IList, QualType ElemType,
+ void CheckSubElementType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckScalarType(InitListExpr *IList, QualType DeclType,
+ void CheckScalarType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckReferenceType(InitListExpr *IList, QualType DeclType,
+ void CheckReferenceType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
+ void CheckVectorType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType,
+ void CheckStructUnionTypes(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool TopLevelObject = false);
- void CheckArrayType(InitListExpr *IList, QualType &DeclType,
+ void CheckArrayType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
- bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE,
+ bool CheckDesignatedInitializer(const InitializedEntity &Entity,
+ InitListExpr *IList, DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
RecordDecl::field_iterator *NextField,
@@ -433,7 +409,8 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
unsigned newStructuredIndex = 0;
FullyStructuredList
= getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange());
- CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
+ CheckExplicitInitList(Entity, IL, T, newIndex,
+ FullyStructuredList, newStructuredIndex,
/*TopLevelObject=*/true);
if (!hadError) {
@@ -470,7 +447,8 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
-void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
+void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *ParentIList,
QualType T, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
@@ -504,7 +482,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
// Check the element types and build the structural subobject.
unsigned StartIndex = Index;
- CheckListElementTypes(ParentIList, T, false, Index,
+ CheckListElementTypes(Entity, ParentIList, T,
+ /*SubobjectIsDesignatorContext=*/false, Index,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex,
TopLevelObject);
@@ -520,7 +499,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
}
}
-void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
+void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &T,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
@@ -528,10 +508,10 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
- CheckListElementTypes(IList, T, true, Index, StructuredList,
- StructuredIndex, TopLevelObject);
- IList->setType(T);
- StructuredList->setType(T);
+ CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
+ Index, StructuredList, StructuredIndex, TopLevelObject);
+ IList->setType(T.getNonReferenceType());
+ StructuredList->setType(T.getNonReferenceType());
if (hadError)
return;
@@ -580,7 +560,8 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
<< CodeModificationHint::CreateRemoval(IList->getLocEnd());
}
-void InitListChecker::CheckListElementTypes(InitListExpr *IList,
+void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
+ InitListExpr *IList,
QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
@@ -588,13 +569,15 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
unsigned &StructuredIndex,
bool TopLevelObject) {
if (DeclType->isScalarType()) {
- CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ CheckScalarType(Entity, IList, DeclType, Index,
+ StructuredList, StructuredIndex);
} else if (DeclType->isVectorType()) {
- CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ CheckVectorType(Entity, IList, DeclType, Index,
+ StructuredList, StructuredIndex);
} else if (DeclType->isAggregateType()) {
if (DeclType->isRecordType()) {
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
- CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
+ CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex,
TopLevelObject);
@@ -602,7 +585,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
llvm::APSInt Zero(
SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
false);
- CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
+ CheckArrayType(Entity, IList, DeclType, Zero,
+ SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
} else
assert(0 && "Aggregate that isn't a structure or array?!");
@@ -625,7 +609,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
<< DeclType << IList->getSourceRange();
hadError = true;
} else if (DeclType->isReferenceType()) {
- CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex);
+ CheckReferenceType(Entity, IList, DeclType, Index,
+ StructuredList, StructuredIndex);
} else {
// In C, all types are either scalars or aggregates, but
// additional handling is needed here for C++ (and possibly others?).
@@ -633,7 +618,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
}
}
-void InitListChecker::CheckSubElementType(InitListExpr *IList,
+void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
+ InitListExpr *IList,
QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
@@ -646,7 +632,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
= getStructuredSubobjectInit(IList, Index, ElemType,
StructuredList, StructuredIndex,
SubInitList->getSourceRange());
- CheckExplicitInitList(SubInitList, ElemType, newIndex,
+ CheckExplicitInitList(Entity, SubInitList, ElemType, newIndex,
newStructuredList, newStructuredIndex);
++StructuredIndex;
++Index;
@@ -655,9 +641,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
UpdateStructuredListElement(StructuredList, StructuredIndex, Str);
++Index;
} else if (ElemType->isScalarType()) {
- CheckScalarType(IList, ElemType, Index, StructuredList, StructuredIndex);
+ CheckScalarType(Entity, IList, ElemType, Index,
+ StructuredList, StructuredIndex);
} else if (ElemType->isReferenceType()) {
- CheckReferenceType(IList, ElemType, Index, StructuredList, StructuredIndex);
+ CheckReferenceType(Entity, IList, ElemType, Index,
+ StructuredList, StructuredIndex);
} else {
if (SemaRef.getLangOptions().CPlusPlus) {
// C++ [dcl.init.aggr]p12:
@@ -665,17 +653,21 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// initializing the aggregate member with an ini- tializer from
// an initializer-list. If the initializer can initialize a
// member, the member is initialized. [...]
- ImplicitConversionSequence ICS
- = SemaRef.TryCopyInitialization(expr, ElemType,
- /*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
-
- if (!ICS.isBad()) {
- if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
- Sema::AA_Initializing))
+
+ // FIXME: Better EqualLoc?
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation());
+ InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1);
+
+ if (Seq) {
+ Sema::OwningExprResult Result =
+ Seq.Perform(SemaRef, Entity, Kind,
+ Sema::MultiExprArg(SemaRef, (void **)&expr, 1));
+ if (Result.isInvalid())
hadError = true;
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.takeAs<Expr>());
++Index;
return;
}
@@ -707,13 +699,15 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
// considered for the initialization of the first member of
// the subaggregate.
if (ElemType->isAggregateType() || ElemType->isVectorType()) {
- CheckImplicitInitList(IList, ElemType, Index, StructuredList,
+ CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
StructuredIndex);
++StructuredIndex;
} else {
// We cannot initialize this element, so let
// PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(expr, ElemType, Sema::AA_Initializing);
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(),
+ SemaRef.Owned(expr));
+ IList->setInit(Index, 0);
hadError = true;
++Index;
++StructuredIndex;
@@ -721,7 +715,8 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
}
}
-void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
+void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -745,17 +740,26 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
return;
}
- Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
- if (CheckSingleInitializer(expr, DeclType, false, SemaRef))
+ Sema::OwningExprResult Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
+ SemaRef.Owned(expr));
+
+ Expr *ResultExpr = 0;
+
+ if (Result.isInvalid())
hadError = true; // types weren't compatible.
- else if (savExpr != expr) {
- // The type was promoted, update initializer list.
- IList->setInit(Index, expr);
+ else {
+ ResultExpr = Result.takeAs<Expr>();
+
+ if (ResultExpr != expr) {
+ // The type was promoted, update initializer list.
+ IList->setInit(Index, ResultExpr);
+ }
}
if (hadError)
++StructuredIndex;
else
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr);
++Index;
} else {
SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
@@ -767,7 +771,8 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
+void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -782,17 +787,16 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
return;
}
- Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
- if (SemaRef.CheckReferenceInit(expr, DeclType,
- /*FIXME:*/expr->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false))
+ Sema::OwningExprResult Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
+ SemaRef.Owned(expr));
+
+ if (Result.isInvalid())
hadError = true;
- else if (savExpr != expr) {
- // The type was promoted, update initializer list.
- IList->setInit(Index, expr);
- }
+
+ expr = Result.takeAs<Expr>();
+ IList->setInit(Index, expr);
+
if (hadError)
++StructuredIndex;
else
@@ -814,7 +818,8 @@ void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
+void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
@@ -825,22 +830,33 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
QualType elementType = VT->getElementType();
if (!SemaRef.getLangOptions().OpenCL) {
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
- CheckSubElementType(IList, elementType, Index,
+
+ ElementEntity.setElementIndex(Index);
+ CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
}
} else {
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
// OpenCL initializers allows vectors to be constructed from vectors.
for (unsigned i = 0; i < maxElements; ++i) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
break;
+
+ ElementEntity.setElementIndex(Index);
+
QualType IType = IList->getInit(Index)->getType();
if (!IType->isVectorType()) {
- CheckSubElementType(IList, elementType, Index,
+ CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
++numEltsInit;
} else {
@@ -848,7 +864,7 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
unsigned numIElts = IVT->getNumElements();
QualType VecType = SemaRef.Context.getExtVectorType(elementType,
numIElts);
- CheckSubElementType(IList, VecType, Index,
+ CheckSubElementType(ElementEntity, IList, VecType, Index,
StructuredList, StructuredIndex);
numEltsInit += numIElts;
}
@@ -864,7 +880,8 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
}
}
-void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
+void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
+ InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext,
unsigned &Index,
@@ -925,7 +942,7 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
DeclType, 0, &elementIndex, Index,
StructuredList, StructuredIndex, true,
false)) {
@@ -952,8 +969,11 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
if (maxElementsKnown && elementIndex == maxElements)
break;
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, StructuredIndex,
+ Entity);
// Check this element.
- CheckSubElementType(IList, elementType, Index,
+ CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
++elementIndex;
@@ -978,7 +998,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
}
}
-void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
+void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
+ InitListExpr *IList,
QualType DeclType,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext,
@@ -1027,7 +1048,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
- if (CheckDesignatedInitializer(IList, DIE, 0,
+ if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
DeclType, &Field, 0, Index,
StructuredList, StructuredIndex,
true, TopLevelObject))
@@ -1056,7 +1077,9 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
continue;
}
- CheckSubElementType(IList, Field->getType(), Index,
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+ CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
@@ -1092,12 +1115,15 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
<< *Field;
}
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+
if (isa<InitListExpr>(IList->getInit(Index)))
- CheckSubElementType(IList, Field->getType(), Index, StructuredList,
- StructuredIndex);
+ CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
+ StructuredList, StructuredIndex);
else
- CheckImplicitInitList(IList, Field->getType(), Index, StructuredList,
- StructuredIndex);
+ CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index,
+ StructuredList, StructuredIndex);
}
/// \brief Expand a field designator that refers to a member of an
@@ -1194,7 +1220,8 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
///
/// @returns true if there was an error, false otherwise.
bool
-InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
+InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
+ InitListExpr *IList,
DesignatedInitExpr *DIE,
unsigned DesigIdx,
QualType &CurrentObjectType,
@@ -1215,7 +1242,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
unsigned OldIndex = Index;
IList->setInit(OldIndex, DIE->getInit());
- CheckSubElementType(IList, CurrentObjectType, Index,
+ CheckSubElementType(Entity, IList, CurrentObjectType, Index,
StructuredList, StructuredIndex);
// Restore the designated initializer expression in the syntactic
@@ -1423,8 +1450,12 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
unsigned newStructuredIndex = FieldIndex;
unsigned OldIndex = Index;
IList->setInit(Index, DIE->getInit());
- CheckSubElementType(IList, Field->getType(), Index,
+
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+ CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, newStructuredIndex);
+
IList->setInit(OldIndex, DIE);
if (hadError && !prevHadError) {
++Field;
@@ -1438,8 +1469,12 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Recurse to check later designated subobjects.
QualType FieldType = (*Field)->getType();
unsigned newStructuredIndex = FieldIndex;
- if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, FieldType, 0, 0,
- Index, StructuredList, newStructuredIndex,
+
+ InitializedEntity MemberEntity =
+ InitializedEntity::InitializeMember(*Field, &Entity);
+ if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
+ FieldType, 0, 0, Index,
+ StructuredList, newStructuredIndex,
true, false))
return true;
}
@@ -1467,7 +1502,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
- CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
+
+ CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index,
StructuredList, FieldIndex);
return hadError && !prevHadError;
}
@@ -1552,12 +1588,19 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Move to the next designator
unsigned ElementIndex = DesignatedStartIndex.getZExtValue();
unsigned OldIndex = Index;
+
+ InitializedEntity ElementEntity =
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
+
while (DesignatedStartIndex <= DesignatedEndIndex) {
// Recurse to check later designated subobjects.
QualType ElementType = AT->getElementType();
Index = OldIndex;
- if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, ElementType, 0, 0,
- Index, StructuredList, ElementIndex,
+
+ ElementEntity.setElementIndex(ElementIndex);
+ if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1,
+ ElementType, 0, 0, Index,
+ StructuredList, ElementIndex,
(DesignatedStartIndex == DesignatedEndIndex),
false))
return true;
@@ -1581,7 +1624,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
// Check the remaining elements within this array subobject.
bool prevHadError = hadError;
- CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index,
+ CheckArrayType(Entity, IList, CurrentObjectType, DesignatedStartIndex,
+ /*SubobjectIsDesignatorContext=*/false, Index,
StructuredList, ElementIndex);
return hadError && !prevHadError;
}
@@ -1628,7 +1672,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
= new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
InitRange.getEnd());
- Result->setType(CurrentObjectType);
+ Result->setType(CurrentObjectType.getNonReferenceType());
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
@@ -1927,7 +1971,8 @@ void InitializationSequence::AddAddressOverloadResolutionStep(
Step S;
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
- S.Function = Function;
+ // Access is currently ignored for these.
+ S.Function = DeclAccessPair::make(Function, AccessSpecifier(0));
Steps.push_back(S);
}
@@ -1948,11 +1993,12 @@ void InitializationSequence::AddReferenceBindingStep(QualType T,
}
void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
+ AccessSpecifier Access,
QualType T) {
Step S;
S.Kind = SK_UserConversion;
S.Type = T;
- S.Function = Function;
+ S.Function = DeclAccessPair::make(Function, Access);
Steps.push_back(S);
}
@@ -1985,11 +2031,12 @@ void InitializationSequence::AddListInitializationStep(QualType T) {
void
InitializationSequence::AddConstructorInitializationStep(
CXXConstructorDecl *Constructor,
+ AccessSpecifier Access,
QualType T) {
Step S;
S.Kind = SK_ConstructorInitialization;
S.Type = T;
- S.Function = Constructor;
+ S.Function = DeclAccessPair::make(Constructor, Access);
Steps.push_back(S);
}
@@ -2129,10 +2176,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ S.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
&Initializer, 1, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &Initializer, 1, CandidateSet);
}
}
}
@@ -2172,11 +2222,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if ((AllowExplicit || !Conv->isExplicit()) &&
(AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer,
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ ActingDC, Initializer,
ToType, CandidateSet);
else
- S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1,
- CandidateSet);
+ S.AddConversionCandidate(Conv, I.getAccess(), ActingDC,
+ Initializer, cv1T1, CandidateSet);
}
}
}
@@ -2198,7 +2249,8 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
T2 = cv1T1;
// Add the user-defined conversion step.
- Sequence.AddUserConversionStep(Function, T2.getNonReferenceType());
+ Sequence.AddUserConversionStep(Function, Best->getAccess(),
+ T2.getNonReferenceType());
// Determine whether we need to perform derived-to-base or
// cv-qualification adjustments.
@@ -2281,16 +2333,20 @@ static void TryReferenceInitialization(Sema &S,
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
// reference-compatible with "cv2 T2," or
//
- // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a
+ // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a
// bit-field when we're determining whether the reference initialization
- // can occur. This property will be checked by PerformInitialization.
+ // can occur. However, we do pay attention to whether it is a bit-field
+ // to decide whether we're actually binding to a temporary created from
+ // the bit-field.
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
S.Context.getQualifiedType(T1, T2Quals),
/*isLValue=*/true);
if (T1Quals != T2Quals)
Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true);
- Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false);
+ bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() &&
+ (Initializer->getBitField() || Initializer->refersToVectorElement());
+ Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary);
return;
}
@@ -2319,7 +2375,7 @@ static void TryReferenceInitialization(Sema &S,
// non-volatile const type (i.e., cv1 shall be const), or the reference
// shall be an rvalue reference and the initializer expression shall
// be an rvalue.
- if (!((isLValueRef && T1Quals.hasConst()) ||
+ if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) ||
(isRValueRef && InitLvalue != Expr::LV_Valid))) {
if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
Sequence.SetOverloadFailure(
@@ -2489,10 +2545,13 @@ static void TryConstructorInitialization(Sema &S,
if (!Constructor->isInvalidDecl() &&
(AllowExplicit || !Constructor->isExplicit())) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ S.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ Args, NumArgs, CandidateSet);
}
}
@@ -2507,14 +2566,26 @@ static void TryConstructorInitialization(Sema &S,
Result);
return;
}
-
+
+ // C++0x [dcl.init]p6:
+ // If a program calls for the default initialization of an object
+ // of a const-qualified type T, T shall be a class type with a
+ // user-provided default constructor.
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ Entity.getType().isConstQualified() &&
+ cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
+
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
if (Kind.getKind() == InitializationKind::IK_Copy) {
- Sequence.AddUserConversionStep(Best->Function, DestType);
+ Sequence.AddUserConversionStep(Best->Function, Best->getAccess(), DestType);
} else {
Sequence.AddConstructorInitializationStep(
cast<CXXConstructorDecl>(Best->Function),
+ Best->getAccess(),
DestType);
}
}
@@ -2579,10 +2650,7 @@ static void TryDefaultInitialization(Sema &S,
// - if T is a (possibly cv-qualified) class type (Clause 9), the default
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
- if (DestType->isRecordType()) {
- // FIXME: If a program calls for the default initialization of an object of
- // a const-qualified type T, T shall be a class type with a user-provided
- // default constructor.
+ if (DestType->isRecordType() && S.getLangOptions().CPlusPlus) {
return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType,
Sequence);
}
@@ -2593,7 +2661,7 @@ static void TryDefaultInitialization(Sema &S,
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
// default constructor.
- if (DestType.isConstQualified())
+ if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus)
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
}
@@ -2647,10 +2715,13 @@ static void TryUserDefinedConversion(Sema &S,
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ S.AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
&Initializer, 1, CandidateSet);
else
- S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &Initializer, 1, CandidateSet);
}
}
}
@@ -2686,12 +2757,12 @@ static void TryUserDefinedConversion(Sema &S,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, ActingDC,
- Initializer, DestType,
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ ActingDC, Initializer, DestType,
CandidateSet);
else
- S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType,
- CandidateSet);
+ S.AddConversionCandidate(Conv, I.getAccess(), ActingDC,
+ Initializer, DestType, CandidateSet);
}
}
}
@@ -2712,13 +2783,13 @@ static void TryUserDefinedConversion(Sema &S,
if (isa<CXXConstructorDecl>(Function)) {
// Add the user-defined conversion step. Any cv-qualification conversion is
// subsumed by the initialization.
- Sequence.AddUserConversionStep(Function, DestType);
+ Sequence.AddUserConversionStep(Function, Best->getAccess(), DestType);
return;
}
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getResultType().getNonReferenceType();
- Sequence.AddUserConversionStep(Function, ConvType);
+ Sequence.AddUserConversionStep(Function, Best->getAccess(), ConvType);
// If the conversion following the call to the conversion function is
// interesting, add it as a separate step.
@@ -2758,7 +2829,8 @@ InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr **Args,
- unsigned NumArgs) {
+ unsigned NumArgs)
+ : FailedCandidateSet(Kind.getLocation()) {
ASTContext &Context = S.Context;
// C++0x [dcl.init]p16:
@@ -2934,15 +3006,15 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity,
bool IsCopy) {
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
- case InitializedEntity::EK_Exception:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_Member:
return !IsCopy;
case InitializedEntity::EK_New:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Base:
- case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_Exception:
return false;
case InitializedEntity::EK_Parameter:
@@ -2960,6 +3032,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Sema::OwningExprResult CurInit) {
+ Expr *CurInitExpr = (Expr *)CurInit.get();
+
SourceLocation Loc;
switch (Entity.getKind()) {
@@ -2980,6 +3054,14 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
Loc = Entity.getDecl()->getLocation();
break;
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_Member:
+ if (Entity.getType()->isReferenceType() ||
+ Kind.getKind() != InitializationKind::IK_Copy)
+ return move(CurInit);
+ Loc = CurInitExpr->getLocStart();
+ break;
+
case InitializedEntity::EK_Parameter:
// FIXME: Do we need this initialization for a parameter?
return move(CurInit);
@@ -2987,14 +3069,11 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
case InitializedEntity::EK_New:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_Base:
- case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
// We don't need to copy for any of these initialized entities.
return move(CurInit);
}
- Expr *CurInitExpr = (Expr *)CurInit.get();
CXXRecordDecl *Class = 0;
if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
@@ -3006,7 +3085,7 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
= S.Context.DeclarationNames.getCXXConstructorName(
S.Context.getCanonicalType(S.Context.getTypeDeclType(Class)));
DeclContext::lookup_iterator Con, ConEnd;
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName);
Con != ConEnd; ++Con) {
// Find the constructor (which may be a template).
@@ -3015,7 +3094,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
!Constructor->isCopyConstructor())
continue;
- S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet);
+ S.AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &CurInitExpr, 1, CandidateSet);
}
OverloadCandidateSet::iterator Best;
@@ -3111,6 +3191,9 @@ InitializationSequence::Perform(Sema &S,
if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast())
return Sema::OwningExprResult(S, Args.release()[0]);
+ if (Args.size() == 0)
+ return S.Owned((Expr *)0);
+
unsigned NumArgs = Args.size();
return S.Owned(new (S.Context) ParenListExpr(S.Context,
SourceLocation(),
@@ -3176,7 +3259,9 @@ InitializationSequence::Perform(Sema &S,
case SK_ResolveAddressOfOverloadedFunction:
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
- CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function);
+ // Access control was done in overload resolution.
+ CurInit = S.FixOverloadedFunctionReference(move(CurInit),
+ cast<FunctionDecl>(Step->Function.getDecl()));
break;
case SK_CastDerivedToBaseRValue:
@@ -3209,21 +3294,30 @@ InitializationSequence::Perform(Sema &S,
S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
return S.ExprError();
}
+
+ if (CurInitExpr->refersToVectorElement()) {
+ // References cannot bind to vector elements.
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
+ << Entity.getType().isVolatileQualified()
+ << CurInitExpr->getSourceRange();
+ return S.ExprError();
+ }
// Reference binding does not have any corresponding ASTs.
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
return S.ExprError();
+
break;
-
+
case SK_BindReferenceToTemporary:
+ // Reference binding does not have any corresponding ASTs.
+
// Check exception specifications
if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType))
return S.ExprError();
- // FIXME: At present, we have no AST to describe when we need to make a
- // temporary to bind a reference to. We should.
break;
case SK_UserConversion: {
@@ -3231,13 +3325,14 @@ InitializationSequence::Perform(Sema &S,
// or a conversion function.
CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
bool IsCopy = false;
- if (CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(Step->Function)) {
+ FunctionDecl *Fn = cast<FunctionDecl>(Step->Function.getDecl());
+ AccessSpecifier FnAccess = Step->Function.getAccess();
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
SourceLocation Loc = CurInitExpr->getLocStart();
CurInit.release(); // Ownership transferred into MultiExprArg, below.
-
+
// Determine the arguments required to actually perform the constructor
// call.
if (S.CompleteConstructorCall(Constructor,
@@ -3252,6 +3347,8 @@ InitializationSequence::Perform(Sema &S,
move_arg(ConstructorArgs));
if (CurInit.isInvalid())
return S.ExprError();
+
+ S.CheckConstructorAccess(Kind.getLocation(), Constructor, FnAccess);
CastKind = CastExpr::CK_ConstructorConversion;
QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
@@ -3260,8 +3357,11 @@ InitializationSequence::Perform(Sema &S,
IsCopy = true;
} else {
// Build a call to the conversion function.
- CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function);
+ CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
+ S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr,
+ Conversion, FnAccess);
+
// 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.
@@ -3326,8 +3426,8 @@ InitializationSequence::Perform(Sema &S,
case SK_ConstructorInitialization: {
CXXConstructorDecl *Constructor
- = cast<CXXConstructorDecl>(Step->Function);
-
+ = cast<CXXConstructorDecl>(Step->Function.getDecl());
+
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
SourceLocation Loc = Kind.getLocation();
@@ -3342,9 +3442,13 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
move_arg(ConstructorArgs),
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ Entity.getKind() == InitializedEntity::EK_Base);
if (CurInit.isInvalid())
return S.ExprError();
+
+ // Only check access if all of that succeeded.
+ S.CheckConstructorAccess(Loc, Constructor, Step->Function.getAccess());
bool Elidable
= cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable();
@@ -3422,8 +3526,13 @@ bool InitializationSequence::Diagnose(Sema &S,
QualType DestType = Entity.getType();
switch (Failure) {
case FK_TooManyInitsForReference:
- S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
- << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
+ // FIXME: Customize for the initialized entity?
+ if (NumArgs == 0)
+ S.Diag(Kind.getLocation(), diag::err_reference_without_init)
+ << DestType.getNonReferenceType();
+ else // FIXME: diagnostic below could be better!
+ S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
+ << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
break;
case FK_ArrayNeedsInitList:
@@ -3492,6 +3601,7 @@ bool InitializationSequence::Diagnose(Sema &S,
Failure == FK_NonConstLValueReferenceBindingToTemporary
? diag::err_lvalue_reference_bind_to_temporary
: diag::err_lvalue_reference_bind_to_unrelated)
+ << DestType.getNonReferenceType().isVolatileQualified()
<< DestType.getNonReferenceType()
<< Args[0]->getType()
<< Args[0]->getSourceRange();
@@ -3567,6 +3677,45 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case OR_No_Viable_Function:
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ (Entity.getKind() == InitializedEntity::EK_Base ||
+ Entity.getKind() == InitializedEntity::EK_Member) &&
+ isa<CXXConstructorDecl>(S.CurContext)) {
+ // This is implicit default initialization of a member or
+ // base within a constructor. If no viable function was
+ // found, notify the user that she needs to explicitly
+ // initialize this base/member.
+ CXXConstructorDecl *Constructor
+ = cast<CXXConstructorDecl>(S.CurContext);
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*base=*/0
+ << Entity.getType();
+
+ RecordDecl *BaseDecl
+ = Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
+ ->getDecl();
+ S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
+ << S.Context.getTagDeclType(BaseDecl);
+ } else {
+ S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*member=*/1
+ << Entity.getName();
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_field_decl);
+
+ if (const RecordType *Record
+ = Entity.getType()->getAs<RecordType>())
+ S.Diag(Record->getDecl()->getLocation(),
+ diag::note_previous_decl)
+ << S.Context.getTagDeclType(Record->getDecl());
+ }
+ break;
+ }
+
S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange;
S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates,
@@ -3597,14 +3746,217 @@ bool InitializationSequence::Diagnose(Sema &S,
}
case FK_DefaultInitOfConst:
- S.Diag(Kind.getLocation(), diag::err_default_init_const)
- << DestType;
+ if (Entity.getKind() == InitializedEntity::EK_Member &&
+ isa<CXXConstructorDecl>(S.CurContext)) {
+ // This is implicit default-initialization of a const member in
+ // a constructor. Complain that it needs to be explicitly
+ // initialized.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
+ S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
+ << Constructor->isImplicit()
+ << S.Context.getTypeDeclType(Constructor->getParent())
+ << /*const=*/1
+ << Entity.getName();
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl)
+ << Entity.getName();
+ } else {
+ S.Diag(Kind.getLocation(), diag::err_default_init_const)
+ << DestType << (bool)DestType->getAs<RecordType>();
+ }
break;
}
return true;
}
+void InitializationSequence::dump(llvm::raw_ostream &OS) const {
+ switch (SequenceKind) {
+ case FailedSequence: {
+ OS << "Failed sequence: ";
+ switch (Failure) {
+ case FK_TooManyInitsForReference:
+ OS << "too many initializers for reference";
+ break;
+
+ case FK_ArrayNeedsInitList:
+ OS << "array requires initializer list";
+ break;
+
+ case FK_ArrayNeedsInitListOrStringLiteral:
+ OS << "array requires initializer list or string literal";
+ break;
+
+ case FK_AddressOfOverloadFailed:
+ OS << "address of overloaded function failed";
+ break;
+
+ case FK_ReferenceInitOverloadFailed:
+ OS << "overload resolution for reference initialization failed";
+ break;
+
+ case FK_NonConstLValueReferenceBindingToTemporary:
+ OS << "non-const lvalue reference bound to temporary";
+ break;
+
+ case FK_NonConstLValueReferenceBindingToUnrelated:
+ OS << "non-const lvalue reference bound to unrelated type";
+ break;
+
+ case FK_RValueReferenceBindingToLValue:
+ OS << "rvalue reference bound to an lvalue";
+ break;
+
+ case FK_ReferenceInitDropsQualifiers:
+ OS << "reference initialization drops qualifiers";
+ break;
+
+ case FK_ReferenceInitFailed:
+ OS << "reference initialization failed";
+ break;
+
+ case FK_ConversionFailed:
+ OS << "conversion failed";
+ break;
+
+ case FK_TooManyInitsForScalar:
+ OS << "too many initializers for scalar";
+ break;
+
+ case FK_ReferenceBindingToInitList:
+ OS << "referencing binding to initializer list";
+ break;
+
+ case FK_InitListBadDestinationType:
+ OS << "initializer list for non-aggregate, non-scalar type";
+ break;
+
+ case FK_UserConversionOverloadFailed:
+ OS << "overloading failed for user-defined conversion";
+ break;
+
+ case FK_ConstructorOverloadFailed:
+ OS << "constructor overloading failed";
+ break;
+
+ case FK_DefaultInitOfConst:
+ OS << "default initialization of a const variable";
+ break;
+ }
+ OS << '\n';
+ return;
+ }
+
+ case DependentSequence:
+ OS << "Dependent sequence: ";
+ return;
+
+ case UserDefinedConversion:
+ OS << "User-defined conversion sequence: ";
+ break;
+
+ case ConstructorInitialization:
+ OS << "Constructor initialization sequence: ";
+ break;
+
+ case ReferenceBinding:
+ OS << "Reference binding: ";
+ break;
+
+ case ListInitialization:
+ OS << "List initialization: ";
+ break;
+
+ case ZeroInitialization:
+ OS << "Zero initialization\n";
+ return;
+
+ case NoInitialization:
+ OS << "No initialization\n";
+ return;
+
+ case StandardConversion:
+ OS << "Standard conversion: ";
+ break;
+
+ case CAssignment:
+ OS << "C assignment: ";
+ break;
+
+ case StringInit:
+ OS << "String initialization: ";
+ break;
+ }
+
+ for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
+ if (S != step_begin()) {
+ OS << " -> ";
+ }
+
+ switch (S->Kind) {
+ case SK_ResolveAddressOfOverloadedFunction:
+ OS << "resolve address of overloaded function";
+ break;
+
+ case SK_CastDerivedToBaseRValue:
+ OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")";
+ break;
+
+ case SK_CastDerivedToBaseLValue:
+ OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")";
+ break;
+
+ case SK_BindReference:
+ OS << "bind reference to lvalue";
+ break;
+
+ case SK_BindReferenceToTemporary:
+ OS << "bind reference to a temporary";
+ break;
+
+ case SK_UserConversion:
+ OS << "user-defined conversion via " << S->Function->getNameAsString();
+ break;
+
+ case SK_QualificationConversionRValue:
+ OS << "qualification conversion (rvalue)";
+
+ case SK_QualificationConversionLValue:
+ OS << "qualification conversion (lvalue)";
+ break;
+
+ case SK_ConversionSequence:
+ OS << "implicit conversion sequence (";
+ S->ICS->DebugPrint(); // FIXME: use OS
+ OS << ")";
+ break;
+
+ case SK_ListInitialization:
+ OS << "list initialization";
+ break;
+
+ case SK_ConstructorInitialization:
+ OS << "constructor initialization";
+ break;
+
+ case SK_ZeroInitialization:
+ OS << "zero initialization";
+ break;
+
+ case SK_CAssignment:
+ OS << "C assignment";
+ break;
+
+ case SK_StringInit:
+ OS << "string initialization";
+ break;
+ }
+ }
+}
+
+void InitializationSequence::dump() const {
+ dump(llvm::errs());
+}
+
//===----------------------------------------------------------------------===//
// Initialization helper functions
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index d7d3756020f8..2b49df28fe86 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -15,12 +15,17 @@
#include "SemaOverload.h"
#include "clang/AST/Type.h"
+#include "clang/AST/UnresolvedSet.h"
#include "clang/Parse/Action.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include <cassert>
+namespace llvm {
+ class raw_ostream;
+}
+
namespace clang {
class CXXBaseSpecifier;
@@ -62,7 +67,6 @@ public:
/// \brief The entity being initialized is an element of a vector.
/// or vector.
EK_VectorElement
-
};
private:
@@ -91,8 +95,8 @@ private:
/// base class.
CXXBaseSpecifier *Base;
- /// \brief When Kind = EK_ArrayOrVectorElement, the index of the
- /// array or vector element being initialized.
+ /// \brief When Kind = EK_ArrayElement or EK_VectorElement, the
+ /// index of the array or vector element being initialized.
unsigned Index;
};
@@ -197,6 +201,12 @@ public:
/// initialized.
DeclaratorDecl *getDecl() const;
+ /// \brief Retrieve the base specifier.
+ CXXBaseSpecifier *getBaseSpecifier() const {
+ assert(getKind() == EK_Base && "Not a base specifier");
+ return Base;
+ }
+
/// \brief Determine the location of the 'return' keyword when initializing
/// the result of a function call.
SourceLocation getReturnLoc() const {
@@ -440,7 +450,11 @@ public:
/// \brief When Kind == SK_ResolvedOverloadedFunction or Kind ==
/// SK_UserConversion, the function that the expression should be
/// resolved to or the conversion function to call, respectively.
- FunctionDecl *Function;
+ ///
+ /// Always a FunctionDecl.
+ /// For conversion decls, the naming class is the source type.
+ /// For construct decls, the naming class is the target type.
+ DeclAccessPair Function;
/// \brief When Kind = SK_ConversionSequence, the implicit conversion
/// sequence
@@ -607,7 +621,9 @@ public:
/// \brief Add a new step invoking a conversion function, which is either
/// a constructor or a conversion function.
- void AddUserConversionStep(FunctionDecl *Function, QualType T);
+ void AddUserConversionStep(FunctionDecl *Function,
+ AccessSpecifier Access,
+ QualType T);
/// \brief Add a new step that performs a qualification conversion to the
/// given type.
@@ -622,6 +638,7 @@ public:
/// \brief Add a constructor-initialization step.
void AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
+ AccessSpecifier Access,
QualType T);
/// \brief Add a zero-initialization step.
@@ -658,6 +675,14 @@ public:
assert(getKind() == FailedSequence && "Not an initialization failure!");
return Failure;
}
+
+ /// \brief Dump a representation of this initialization sequence to
+ /// the given stream, for debugging purposes.
+ void dump(llvm::raw_ostream &OS) const;
+
+ /// \brief Dump a representation of this initialization sequence to
+ /// standard error, for debugging purposes.
+ void dump() const;
};
} // end namespace clang
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index f5d2a7d89988..c7569d6eda25 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -404,7 +404,7 @@ void LookupResult::resolveKind() {
}
void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
- CXXBasePaths::paths_iterator I, E;
+ CXXBasePaths::const_paths_iterator I, E;
DeclContext::lookup_iterator DI, DE;
for (I = P.begin(), E = P.end(); I != E; ++I)
for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)
@@ -438,9 +438,42 @@ void LookupResult::print(llvm::raw_ostream &Out) {
}
}
+/// \brief Lookup a builtin function, when name lookup would otherwise
+/// fail.
+static bool LookupBuiltin(Sema &S, LookupResult &R) {
+ Sema::LookupNameKind NameKind = R.getLookupKind();
+
+ // 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 (NameKind == Sema::LookupOrdinaryName ||
+ NameKind == Sema::LookupRedeclarationWithLinkage) {
+ IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
+ if (II) {
+ // If this is a builtin on this (or all) targets, create the decl.
+ if (unsigned BuiltinID = II->getBuiltinID()) {
+ // In C++, we don't have any predefined library functions like
+ // 'malloc'. Instead, we'll just error.
+ if (S.getLangOptions().CPlusPlus &&
+ S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ return false;
+
+ NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
+ S.TUScope, R.isForRedeclaration(),
+ R.getNameLoc());
+ if (D)
+ R.addDecl(D);
+ return (D != NULL);
+ }
+ }
+ }
+
+ return false;
+}
+
// Adds all qualifying matches for a name within a decl context to the
// given lookup result. Returns true if any matches were found.
-static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
+static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
bool Found = false;
DeclContext::lookup_const_iterator I, E;
@@ -452,87 +485,89 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
}
}
+ if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R))
+ return true;
+
if (R.getLookupName().getNameKind()
- == DeclarationName::CXXConversionFunctionName &&
- !R.getLookupName().getCXXNameType()->isDependentType() &&
- isa<CXXRecordDecl>(DC)) {
+ != DeclarationName::CXXConversionFunctionName ||
+ R.getLookupName().getCXXNameType()->isDependentType() ||
+ !isa<CXXRecordDecl>(DC))
+ return Found;
+
+ // C++ [temp.mem]p6:
+ // A specialization of a conversion function template is not found by
+ // name lookup. Instead, any conversion function templates visible in the
+ // context of the use are considered. [...]
+ const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ if (!Record->isDefinition())
+ return Found;
+
+ const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
+ for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
+ UEnd = Unresolved->end(); U != UEnd; ++U) {
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
+ if (!ConvTemplate)
+ continue;
+
+ // When we're performing lookup for the purposes of redeclaration, just
+ // add the conversion function template. When we deduce template
+ // arguments for specializations, we'll end up unifying the return
+ // type of the new declaration with the type of the function template.
+ if (R.isForRedeclaration()) {
+ R.addDecl(ConvTemplate);
+ Found = true;
+ continue;
+ }
+
// C++ [temp.mem]p6:
- // A specialization of a conversion function template is not found by
- // name lookup. Instead, any conversion function templates visible in the
- // context of the use are considered. [...]
- const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- if (!Record->isDefinition())
- return Found;
-
- const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
- for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
- UEnd = Unresolved->end(); U != UEnd; ++U) {
- FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
- if (!ConvTemplate)
- continue;
-
- // When we're performing lookup for the purposes of redeclaration, just
- // add the conversion function template. When we deduce template
- // arguments for specializations, we'll end up unifying the return
- // type of the new declaration with the type of the function template.
- if (R.isForRedeclaration()) {
- R.addDecl(ConvTemplate);
- Found = true;
- continue;
- }
-
- // C++ [temp.mem]p6:
- // [...] For each such operator, if argument deduction succeeds
- // (14.9.2.3), the resulting specialization is used as if found by
- // name lookup.
- //
- // When referencing a conversion function for any purpose other than
- // a redeclaration (such that we'll be building an expression with the
- // result), perform template argument deduction and place the
- // specialization into the result set. We do this to avoid forcing all
- // callers to perform special deduction for conversion functions.
- Sema::TemplateDeductionInfo Info(R.getSema().Context);
- FunctionDecl *Specialization = 0;
-
- const FunctionProtoType *ConvProto
- = ConvTemplate->getTemplatedDecl()->getType()
- ->getAs<FunctionProtoType>();
- assert(ConvProto && "Nonsensical conversion function template type");
-
- // Compute the type of the function that we would expect the conversion
- // function to have, if it were to match the name given.
- // FIXME: Calling convention!
- QualType ExpectedType
- = R.getSema().Context.getFunctionType(
- R.getLookupName().getCXXNameType(),
- 0, 0, ConvProto->isVariadic(),
- ConvProto->getTypeQuals(),
- false, false, 0, 0,
- ConvProto->getNoReturnAttr());
-
- // Perform template argument deduction against the type that we would
- // expect the function to have.
- if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
- Specialization, Info)
- == Sema::TDK_Success) {
- R.addDecl(Specialization);
- Found = true;
- }
+ // [...] For each such operator, if argument deduction succeeds
+ // (14.9.2.3), the resulting specialization is used as if found by
+ // name lookup.
+ //
+ // When referencing a conversion function for any purpose other than
+ // a redeclaration (such that we'll be building an expression with the
+ // result), perform template argument deduction and place the
+ // specialization into the result set. We do this to avoid forcing all
+ // callers to perform special deduction for conversion functions.
+ Sema::TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc());
+ FunctionDecl *Specialization = 0;
+
+ const FunctionProtoType *ConvProto
+ = ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>();
+ assert(ConvProto && "Nonsensical conversion function template type");
+
+ // Compute the type of the function that we would expect the conversion
+ // function to have, if it were to match the name given.
+ // FIXME: Calling convention!
+ QualType ExpectedType
+ = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
+ 0, 0, ConvProto->isVariadic(),
+ ConvProto->getTypeQuals(),
+ false, false, 0, 0,
+ ConvProto->getNoReturnAttr());
+
+ // Perform template argument deduction against the type that we would
+ // expect the function to have.
+ if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
+ Specialization, Info)
+ == Sema::TDK_Success) {
+ R.addDecl(Specialization);
+ Found = true;
}
}
-
+
return Found;
}
// Performs C++ unqualified lookup into the given file context.
static bool
-CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS,
- UnqualUsingDirectiveSet &UDirs) {
+CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context,
+ DeclContext *NS, UnqualUsingDirectiveSet &UDirs) {
assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!");
// Perform direct name lookup into the LookupCtx.
- bool Found = LookupDirect(R, NS);
+ bool Found = LookupDirect(S, R, NS);
// Perform direct name lookup into the namespaces nominated by the
// using directives whose common ancestor is this namespace.
@@ -540,7 +575,7 @@ CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS,
llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS);
for (; UI != UEnd; ++UI)
- if (LookupDirect(R, UI->getNominatedNamespace()))
+ if (LookupDirect(S, R, UI->getNominatedNamespace()))
Found = true;
R.resolveKind();
@@ -650,12 +685,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
for (; S; S = S->getParent()) {
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- if (!Ctx || Ctx->isTransparentContext())
+ if (Ctx && Ctx->isTransparentContext())
continue;
- assert(Ctx && Ctx->isFileContext() &&
- "We should have been looking only at file context here already.");
-
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) {
@@ -669,16 +701,21 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
}
}
- // Look into context considering using-directives.
- if (CppNamespaceLookup(R, Context, Ctx, UDirs))
- Found = true;
+ if (Ctx) {
+ assert(Ctx->isFileContext() &&
+ "We should have been looking only at file context here already.");
+
+ // Look into context considering using-directives.
+ if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs))
+ Found = true;
+ }
if (Found) {
R.resolveKind();
return true;
}
- if (R.isForRedeclaration() && !Ctx->isTransparentContext())
+ if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext())
return false;
}
@@ -793,26 +830,9 @@ 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 (NameKind == LookupOrdinaryName ||
- NameKind == LookupRedeclarationWithLinkage) {
- IdentifierInfo *II = Name.getAsIdentifierInfo();
- if (II && AllowBuiltinCreation) {
- // If this is a builtin on this (or all) targets, create the decl.
- if (unsigned BuiltinID = II->getBuiltinID()) {
- // In C++, we don't have any predefined library functions like
- // 'malloc'. Instead, we'll just error.
- if (getLangOptions().CPlusPlus &&
- Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return false;
+ if (AllowBuiltinCreation)
+ return LookupBuiltin(*this, R);
- NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, R.isForRedeclaration(),
- R.getNameLoc());
- if (D) R.addDecl(D);
- return (D != NULL);
- }
- }
- }
return false;
}
@@ -842,7 +862,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
/// class or enumeration name if and only if the declarations are
/// from the same namespace; otherwise (the declarations are from
/// different namespaces), the program is ill-formed.
-static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
+static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
DeclContext *StartDC) {
assert(StartDC->isFileContext() && "start context is not a file context");
@@ -885,7 +905,7 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
// between LookupResults.
bool UseLocal = !R.empty();
LookupResult &DirectR = UseLocal ? LocalR : R;
- bool FoundDirect = LookupDirect(DirectR, ND);
+ bool FoundDirect = LookupDirect(S, DirectR, ND);
if (FoundDirect) {
// First do any local hiding.
@@ -965,7 +985,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
"Declaration context must already be complete!");
// Perform qualified name lookup into the LookupCtx.
- if (LookupDirect(R, LookupCtx)) {
+ if (LookupDirect(*this, R, LookupCtx)) {
R.resolveKind();
if (isa<CXXRecordDecl>(LookupCtx))
R.setNamingClass(cast<CXXRecordDecl>(LookupCtx));
@@ -986,7 +1006,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// If this is a namespace, look it up in the implied namespaces.
if (LookupCtx->isFileContext())
- return LookupQualifiedNameInUsingDirectives(R, LookupCtx);
+ return LookupQualifiedNameInUsingDirectives(*this, R, LookupCtx);
// If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
@@ -1407,6 +1427,12 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
AssociatedClasses);
}
+ // Only recurse into base classes for complete types.
+ if (!Class->hasDefinition()) {
+ // FIXME: we might need to instantiate templates here
+ return;
+ }
+
// Add direct and indirect base classes along with their associated
// namespaces.
llvm::SmallVector<CXXRecordDecl *, 32> Bases;
@@ -1693,7 +1719,7 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
- FunctionSet &Functions) {
+ UnresolvedSetImpl &Functions) {
// C++ [over.match.oper]p3:
// -- The set of non-member candidates is the result of the
// unqualified lookup of operator@ in the context of the
@@ -1719,29 +1745,58 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
Op != OpEnd; ++Op) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) {
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- Functions.insert(FD); // FIXME: canonical FD
+ Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD
} else if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>(*Op)) {
// FIXME: friend operators?
// FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
// later?
if (!FunTmpl->getDeclContext()->isRecord())
- Functions.insert(FunTmpl);
+ Functions.addDecl(FunTmpl, Op.getAccess());
}
}
}
-static void CollectFunctionDecl(Sema::FunctionSet &Functions,
- Decl *D) {
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- Functions.insert(Func);
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
- Functions.insert(FunTmpl);
+void ADLResult::insert(NamedDecl *New) {
+ NamedDecl *&Old = Decls[cast<NamedDecl>(New->getCanonicalDecl())];
+
+ // If we haven't yet seen a decl for this key, or the last decl
+ // was exactly this one, we're done.
+ if (Old == 0 || Old == New) {
+ Old = New;
+ return;
+ }
+
+ // Otherwise, decide which is a more recent redeclaration.
+ FunctionDecl *OldFD, *NewFD;
+ if (isa<FunctionTemplateDecl>(New)) {
+ OldFD = cast<FunctionTemplateDecl>(Old)->getTemplatedDecl();
+ NewFD = cast<FunctionTemplateDecl>(New)->getTemplatedDecl();
+ } else {
+ OldFD = cast<FunctionDecl>(Old);
+ NewFD = cast<FunctionDecl>(New);
+ }
+
+ FunctionDecl *Cursor = NewFD;
+ while (true) {
+ Cursor = Cursor->getPreviousDeclaration();
+
+ // If we got to the end without finding OldFD, OldFD is the newer
+ // declaration; leave things as they are.
+ if (!Cursor) return;
+
+ // If we do find OldFD, then NewFD is newer.
+ if (Cursor == OldFD) break;
+
+ // Otherwise, keep looking.
+ }
+
+ Old = New;
}
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
- FunctionSet &Functions) {
+ ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
@@ -1784,7 +1839,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
// lookup (11.4).
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
- Decl *D = *I;
+ NamedDecl *D = *I;
// If the only declaration here is an ordinary friend, consider
// it only if it was declared in an associated classes.
if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
@@ -1793,10 +1848,18 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
continue;
}
- FunctionDecl *Fn;
- if (!Operator || !(Fn = dyn_cast<FunctionDecl>(D)) ||
- IsAcceptableNonMemberOperatorCandidate(Fn, T1, T2, Context))
- CollectFunctionDecl(Functions, D);
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ if (isa<FunctionDecl>(D)) {
+ if (Operator &&
+ !IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D),
+ T1, T2, Context))
+ continue;
+ } else if (!isa<FunctionTemplateDecl>(D))
+ continue;
+
+ Result.insert(D);
}
}
}
@@ -1985,6 +2048,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
bool InBaseClass,
VisibleDeclConsumer &Consumer,
VisibleDeclsRecord &Visited) {
+ if (!Ctx)
+ return;
+
// Make sure we don't visit the same context twice.
if (Visited.visitedContext(Ctx->getPrimaryContext()))
return;
@@ -2022,6 +2088,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Traverse the contexts of inherited C++ classes.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ if (!Record->hasDefinition())
+ return;
+
for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
BEnd = Record->bases_end();
B != BEnd; ++B) {
@@ -2138,9 +2207,9 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// For instance methods, look for ivars in the method's interface.
LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
Result.getNameLoc(), Sema::LookupMemberName);
- ObjCInterfaceDecl *IFace = Method->getClassInterface();
- LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited);
+ if (ObjCInterfaceDecl *IFace = Method->getClassInterface())
+ LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false, Consumer, Visited);
}
// We've already performed all of the name lookup that we need
@@ -2312,9 +2381,16 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
DeclContext *MemberContext, bool EnteringContext,
const ObjCObjectPointerType *OPT) {
-
if (Diags.hasFatalErrorOccurred())
return false;
+
+ // Provide a stop gap for files that are just seriously broken. Trying
+ // to correct all typos can turn into a HUGE performance penalty, causing
+ // some files to take minutes to get rejected by the parser.
+ // FIXME: Is this the right solution?
+ if (TyposCorrected == 20)
+ return false;
+ ++TyposCorrected;
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 44a8f15e57b6..b79b1cc99375 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -148,7 +148,7 @@ bool StandardConversionSequence::isPointerConversionToBool() const {
// array-to-pointer or function-to-pointer implicit conversions, so
// check for their presence as well as checking whether FromType is
// a pointer.
- if (getToType()->isBooleanType() &&
+ if (getToType(1)->isBooleanType() &&
(getFromType()->isPointerType() || getFromType()->isBlockPointerType() ||
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
return true;
@@ -164,7 +164,7 @@ bool
StandardConversionSequence::
isPointerConversionToVoidPointer(ASTContext& Context) const {
QualType FromType = getFromType();
- QualType ToType = getToType();
+ QualType ToType = getToType(1);
// Note that FromType has not necessarily been transformed by the
// array-to-pointer implicit conversion, so check for its presence
@@ -447,16 +447,24 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
bool InOverloadResolution,
bool UserCast) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet Conversions;
- OverloadingResult UserDefResult = OR_Success;
- if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard))
+ if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) {
ICS.setStandard();
- else if (getLangOptions().CPlusPlus &&
- (UserDefResult = IsUserDefinedConversion(From, ToType,
- ICS.UserDefined,
- Conversions,
- !SuppressUserConversions, AllowExplicit,
- ForceRValue, UserCast)) == OR_Success) {
+ return ICS;
+ }
+
+ if (!getLangOptions().CPlusPlus) {
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
+ return ICS;
+ }
+
+ OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadingResult UserDefResult
+ = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions,
+ !SuppressUserConversions, AllowExplicit,
+ ForceRValue, UserCast);
+
+ if (UserDefResult == OR_Success) {
ICS.setUserDefined();
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
@@ -477,7 +485,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(From->getType());
- ICS.Standard.setToType(ToType);
+ ICS.Standard.setAllToTypes(ToType);
ICS.Standard.CopyConstructor = Constructor;
if (ToCanon != FromCanon)
ICS.Standard.Second = ICK_Derived_To_Base;
@@ -595,7 +603,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// conversion (4.4). (C++ 4.2p2)
SCS.Second = ICK_Identity;
SCS.Third = ICK_Qualification;
- SCS.setToType(ToType);
+ SCS.setAllToTypes(FromType);
return true;
}
} else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
@@ -634,6 +642,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// We don't require any conversions for the first step.
SCS.First = ICK_Identity;
}
+ SCS.setToType(0, FromType);
// The second conversion can be an integral promotion, floating
// point promotion, integral conversion, floating point conversion,
@@ -714,6 +723,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// No second conversion required.
SCS.Second = ICK_Identity;
}
+ SCS.setToType(1, FromType);
QualType CanonFrom;
QualType CanonTo;
@@ -740,13 +750,13 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
CanonFrom = CanonTo;
}
}
+ SCS.setToType(2, FromType);
// If we have not converted the argument type to the parameter type,
// this is a bad conversion sequence.
if (CanonFrom != CanonTo)
return false;
- SCS.setToType(FromType);
return true;
}
@@ -766,7 +776,8 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// int can represent all the values of the source type; otherwise,
// the source rvalue can be converted to an rvalue of type unsigned
// int (C++ 4.5p1).
- if (FromType->isPromotableIntegerType() && !FromType->isBooleanType()) {
+ if (FromType->isPromotableIntegerType() && !FromType->isBooleanType() &&
+ !FromType->isEnumeralType()) {
if (// We can promote any signed, promotable integer type to an int
(FromType->isSignedIntegerType() ||
// We can promote any unsigned integer type whose size is
@@ -1344,14 +1355,13 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
/// CheckMemberPointerConversion - Check the member pointer conversion from the
/// expression From to the type ToType. This routine checks for ambiguous or
-/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions
+/// virtual or inaccessible base-to-derived member pointer conversions
/// for which IsMemberPointerConversion has already returned true. It returns
/// true and produces a diagnostic if there was an error, or returns false
/// otherwise.
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
bool IgnoreBaseAccess) {
- (void)IgnoreBaseAccess;
QualType FromType = From->getType();
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
if (!FromPtrType) {
@@ -1374,7 +1384,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
assert(FromClass->isRecordType() && "Pointer into non-class.");
assert(ToClass->isRecordType() && "Pointer into non-class.");
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true,
/*DetectVirtual=*/true);
bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
assert(DerivationOkay &&
@@ -1383,13 +1393,6 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
getUnqualifiedType())) {
- // Derivation is ambiguous. Redo the check to find the exact paths.
- Paths.clear();
- Paths.setRecordingPaths(true);
- bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths);
- assert(StillOkay && "Derivation changed due to quantum fluctuation.");
- (void)StillOkay;
-
std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv)
<< 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
@@ -1403,6 +1406,10 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
return true;
}
+ if (!IgnoreBaseAccess)
+ CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true,
+ FromClass, ToClass, Paths.front());
+
// Must be a base to derived member conversion.
Kind = CastExpr::CK_BaseToDerivedMemberPointer;
return false;
@@ -1418,7 +1425,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
// If FromType and ToType are the same type, this is not a
// qualification conversion.
- if (FromType == ToType)
+ if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
return false;
// (C++ 4.4p4):
@@ -1526,13 +1533,16 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (!Constructor->isInvalidDecl() &&
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
- AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+ AddTemplateOverloadCandidate(ConstructorTmpl,
+ ConstructorTmpl->getAccess(),
+ /*ExplicitArgs*/ 0,
&From, 1, CandidateSet,
SuppressUserConversions, ForceRValue);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
- AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
+ AddOverloadCandidate(Constructor, Constructor->getAccess(),
+ &From, 1, CandidateSet,
SuppressUserConversions, ForceRValue);
}
}
@@ -1568,11 +1578,12 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, ActingContext,
- From, ToType, CandidateSet);
+ AddTemplateConversionCandidate(ConvTemplate, I.getAccess(),
+ ActingContext, From, ToType,
+ CandidateSet);
else
- AddConversionCandidate(Conv, ActingContext, From, ToType,
- CandidateSet);
+ AddConversionCandidate(Conv, I.getAccess(), ActingContext,
+ From, ToType, CandidateSet);
}
}
}
@@ -1601,7 +1612,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
User.After.setAsIdentityConversion();
User.After.setFromType(
ThisType->getAs<PointerType>()->getPointeeType());
- User.After.setToType(ToType);
+ User.After.setAllToTypes(ToType);
return OR_Success;
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
@@ -1647,7 +1658,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
bool
Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(From->getExprLoc());
OverloadingResult OvResult =
IsUserDefinedConversion(From, ToType, ICS.UserDefined,
CandidateSet, true, false, false);
@@ -1718,6 +1729,43 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
return ImplicitConversionSequence::Indistinguishable;
}
+// Per 13.3.3.2p3, compare the given standard conversion sequences to
+// determine if one is a proper subset of the other.
+static ImplicitConversionSequence::CompareKind
+compareStandardConversionSubsets(ASTContext &Context,
+ const StandardConversionSequence& SCS1,
+ const StandardConversionSequence& SCS2) {
+ ImplicitConversionSequence::CompareKind Result
+ = ImplicitConversionSequence::Indistinguishable;
+
+ if (SCS1.Second != SCS2.Second) {
+ if (SCS1.Second == ICK_Identity)
+ Result = ImplicitConversionSequence::Better;
+ else if (SCS2.Second == ICK_Identity)
+ Result = ImplicitConversionSequence::Worse;
+ else
+ return ImplicitConversionSequence::Indistinguishable;
+ } else if (!Context.hasSameType(SCS1.getToType(1), SCS2.getToType(1)))
+ return ImplicitConversionSequence::Indistinguishable;
+
+ if (SCS1.Third == SCS2.Third) {
+ return Context.hasSameType(SCS1.getToType(2), SCS2.getToType(2))? Result
+ : ImplicitConversionSequence::Indistinguishable;
+ }
+
+ if (SCS1.Third == ICK_Identity)
+ return Result == ImplicitConversionSequence::Worse
+ ? ImplicitConversionSequence::Indistinguishable
+ : ImplicitConversionSequence::Better;
+
+ if (SCS2.Third == ICK_Identity)
+ return Result == ImplicitConversionSequence::Better
+ ? ImplicitConversionSequence::Indistinguishable
+ : ImplicitConversionSequence::Worse;
+
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
/// CompareStandardConversionSequences - Compare two standard
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2p3).
@@ -1733,21 +1781,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// excluding any Lvalue Transformation; the identity conversion
// sequence is considered to be a subsequence of any
// non-identity conversion sequence) or, if not that,
- if (SCS1.Second == SCS2.Second && SCS1.Third == SCS2.Third)
- // Neither is a proper subsequence of the other. Do nothing.
- ;
- else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) ||
- (SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) ||
- (SCS1.Second == ICK_Identity &&
- SCS1.Third == ICK_Identity))
- // SCS1 is a proper subsequence of SCS2.
- return ImplicitConversionSequence::Better;
- else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) ||
- (SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) ||
- (SCS2.Second == ICK_Identity &&
- SCS2.Third == ICK_Identity))
- // SCS2 is a proper subsequence of SCS1.
- return ImplicitConversionSequence::Worse;
+ if (ImplicitConversionSequence::CompareKind CK
+ = compareStandardConversionSubsets(Context, SCS1, SCS2))
+ return CK;
// -- the rank of S1 is better than the rank of S2 (by the rules
// defined below), or, if not that,
@@ -1852,8 +1888,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// top-level cv-qualifiers, and the type to which the reference
// initialized by S2 refers is more cv-qualified than the type
// to which the reference initialized by S1 refers.
- QualType T1 = SCS1.getToType();
- QualType T2 = SCS2.getToType();
+ QualType T1 = SCS1.getToType(2);
+ QualType T2 = SCS2.getToType(2);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
Qualifiers T1Quals, T2Quals;
@@ -1894,8 +1930,8 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
// FIXME: the example in the standard doesn't use a qualification
// conversion (!)
- QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
- QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ QualType T1 = SCS1.getToType(2);
+ QualType T2 = SCS2.getToType(2);
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
Qualifiers T1Quals, T2Quals;
@@ -1984,9 +2020,9 @@ ImplicitConversionSequence::CompareKind
Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
QualType FromType1 = SCS1.getFromType();
- QualType ToType1 = SCS1.getToType();
+ QualType ToType1 = SCS1.getToType(1);
QualType FromType2 = SCS2.getFromType();
- QualType ToType2 = SCS2.getToType();
+ QualType ToType2 = SCS2.getToType(1);
// Adjust the types we're converting from via the array-to-pointer
// conversion, if we need to.
@@ -2276,7 +2312,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType,
// Success. Mark this as a reference binding.
ICS.setStandard();
ICS.Standard.setFromType(FromType);
- ICS.Standard.setToType(ImplicitParamType);
+ ICS.Standard.setAllToTypes(ImplicitParamType);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = true;
ICS.Standard.RRefBinding = false;
@@ -2360,6 +2396,7 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
/// code completion.
void
Sema::AddOverloadCandidate(FunctionDecl *Function,
+ AccessSpecifier Access,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@@ -2380,7 +2417,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// function, e.g., X::f(). We use an empty type for the implied
// object argument (C++ [over.call.func]p3), and the acting context
// is irrelevant.
- AddMethodCandidate(Method, Method->getParent(),
+ AddMethodCandidate(Method, Access, Method->getParent(),
QualType(), Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
return;
@@ -2410,6 +2447,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Function;
+ Candidate.Access = Access;
Candidate.Viable = true;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
@@ -2469,35 +2507,33 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
/// \brief Add all of the function declarations in the given function set to
/// the overload canddiate set.
-void Sema::AddFunctionCandidates(const FunctionSet &Functions,
+void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
- for (FunctionSet::const_iterator F = Functions.begin(),
- FEnd = Functions.end();
- F != FEnd; ++F) {
+ for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
// FIXME: using declarations
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) {
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
- AddMethodCandidate(cast<CXXMethodDecl>(FD),
+ AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getAccess(),
cast<CXXMethodDecl>(FD)->getParent(),
Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet, SuppressUserConversions);
else
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet,
SuppressUserConversions);
} else {
FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F);
if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
- AddMethodTemplateCandidate(FunTmpl,
+ AddMethodTemplateCandidate(FunTmpl, F.getAccess(),
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
/*FIXME: explicit args */ 0,
Args[0]->getType(), Args + 1, NumArgs - 1,
CandidateSet,
SuppressUserConversions);
else
- AddTemplateOverloadCandidate(FunTmpl,
+ AddTemplateOverloadCandidate(FunTmpl, AS_none,
/*FIXME: explicit args */ 0,
Args, NumArgs, CandidateSet,
SuppressUserConversions);
@@ -2508,6 +2544,7 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
/// AddMethodCandidate - Adds a named decl (which is some kind of
/// method) as a method candidate to the given overload set.
void Sema::AddMethodCandidate(NamedDecl *Decl,
+ AccessSpecifier Access,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -2520,13 +2557,13 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) {
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
"Expected a member function template");
- AddMethodTemplateCandidate(TD, ActingContext, /*ExplicitArgs*/ 0,
+ AddMethodTemplateCandidate(TD, Access, ActingContext, /*ExplicitArgs*/ 0,
ObjectType, Args, NumArgs,
CandidateSet,
SuppressUserConversions,
ForceRValue);
} else {
- AddMethodCandidate(cast<CXXMethodDecl>(Decl), ActingContext,
+ AddMethodCandidate(cast<CXXMethodDecl>(Decl), Access, ActingContext,
ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
@@ -2542,8 +2579,9 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
/// a slightly hacky way to implement the overloading rules for elidable copy
/// initialization in C++0x (C++0x 12.8p15).
void
-Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
- QualType ObjectType, Expr **Args, unsigned NumArgs,
+Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access,
+ CXXRecordDecl *ActingContext, QualType ObjectType,
+ Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions, bool ForceRValue) {
const FunctionProtoType* Proto
@@ -2562,6 +2600,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Method;
+ Candidate.Access = Access;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
@@ -2639,6 +2678,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
/// function template specialization.
void
Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
@@ -2658,7 +2698,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs,
@@ -2674,8 +2714,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
assert(Specialization && "Missing member function template specialization?");
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
- AddMethodCandidate(cast<CXXMethodDecl>(Specialization), ActingContext,
- ObjectType, Args, NumArgs,
+ AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Access,
+ ActingContext, ObjectType, Args, NumArgs,
CandidateSet, SuppressUserConversions, ForceRValue);
}
@@ -2684,6 +2724,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
/// an appropriate function template specialization.
void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -2701,29 +2742,30 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// functions. In such a case, the candidate functions generated from each
// function template are combined with the set of non-template candidate
// functions.
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
Args, NumArgs, Specialization, Info)) {
- // FIXME: Record what happened with template argument deduction, so
- // that we can give the user a beautiful diagnostic.
- (void) Result;
-
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate &Candidate = CandidateSet.back();
Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Access = Access;
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
+
+ // TODO: record more information about failed template arguments
+ Candidate.DeductionFailure.Result = Result;
+ Candidate.DeductionFailure.TemplateParameter = Info.Param.getOpaqueValue();
return;
}
// Add the function template specialization produced by template argument
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(Specialization, Access, Args, NumArgs, CandidateSet,
SuppressUserConversions, ForceRValue);
}
@@ -2735,6 +2777,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
/// conversion function produces).
void
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet) {
@@ -2751,11 +2794,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Conversion;
+ Candidate.Access = Access;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
Candidate.FinalConversion.setFromType(Conversion->getConversionType());
- Candidate.FinalConversion.setToType(ToType);
+ Candidate.FinalConversion.setAllToTypes(ToType);
// Determine the implicit conversion sequence for the implicit
// object parameter.
@@ -2837,6 +2881,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
/// [temp.deduct.conv]).
void
Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+ AccessSpecifier Access,
CXXRecordDecl *ActingDC,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet) {
@@ -2846,7 +2891,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
CXXConversionDecl *Specialization = 0;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
@@ -2860,7 +2905,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
// Add the conversion function template specialization produced by
// template argument deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddConversionCandidate(Specialization, ActingDC, From, ToType, CandidateSet);
+ AddConversionCandidate(Specialization, Access, ActingDC, From, ToType,
+ CandidateSet);
}
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -2869,6 +2915,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
/// with the given arguments (C++ [over.call.object]p2-4). Proto is
/// the type of function that we'll eventually be calling.
void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
+ AccessSpecifier Access,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
QualType ObjectType,
@@ -2883,6 +2930,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
+ Candidate.Access = Access;
Candidate.Surrogate = Conversion;
Candidate.Viable = true;
Candidate.IsSurrogate = true;
@@ -2968,7 +3016,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange) {
- FunctionSet Functions;
+ UnresolvedSet<16> Fns;
QualType T1 = Args[0]->getType();
QualType T2;
@@ -2977,9 +3025,10 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
if (S)
- LookupOverloadedOperatorName(Op, S, T1, T2, Functions);
- ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, Functions);
- AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet);
+ LookupOverloadedOperatorName(Op, S, T1, T2, Fns);
+ AddFunctionCandidates(Fns, Args, NumArgs, CandidateSet, false);
+ AddArgumentDependentLookupCandidates(OpName, false, Args, NumArgs, 0,
+ CandidateSet);
AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange);
AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet);
}
@@ -3029,7 +3078,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
OperEnd = Operators.end();
Oper != OperEnd;
++Oper)
- AddMethodCandidate(*Oper, Args[0]->getType(),
+ AddMethodCandidate(*Oper, Oper.getAccess(), Args[0]->getType(),
Args + 1, NumArgs - 1, CandidateSet,
/* SuppressUserConversions = */ false);
}
@@ -3055,6 +3104,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
+ Candidate.Access = AS_none;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.BuiltinTypes.ResultTy = ResultTy;
@@ -3362,6 +3412,9 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
+ if (!ClassDecl->hasDefinition())
+ return VRQuals;
+
const UnresolvedSetImpl *Conversions =
ClassDecl->getVisibleConversionFunctions();
@@ -4108,54 +4161,45 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/// candidate set (C++ [basic.lookup.argdep]).
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
+ bool Operator,
Expr **Args, unsigned NumArgs,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading) {
- FunctionSet Functions;
+ ADLResult Fns;
- // FIXME: Should we be trafficking in canonical function decls throughout?
-
- // Record all of the function candidates that we've already
- // added to the overload set, so that we don't add those same
- // candidates a second time.
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
- CandEnd = CandidateSet.end();
- Cand != CandEnd; ++Cand)
- if (Cand->Function) {
- Functions.insert(Cand->Function);
- if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate())
- Functions.insert(FunTmpl);
- }
+ // FIXME: This approach for uniquing ADL results (and removing
+ // redundant candidates from the set) relies on pointer-equality,
+ // which means we need to key off the canonical decl. However,
+ // always going back to the canonical decl might not get us the
+ // right set of default arguments. What default arguments are
+ // we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, /*Operator*/false, Args, NumArgs, Functions);
+ ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns);
// Erase all of the candidates we already knew about.
- // FIXME: This is suboptimal. Is there a better way?
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
CandEnd = CandidateSet.end();
Cand != CandEnd; ++Cand)
if (Cand->Function) {
- Functions.erase(Cand->Function);
+ Fns.erase(Cand->Function);
if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate())
- Functions.erase(FunTmpl);
+ Fns.erase(FunTmpl);
}
// For each of the ADL candidates we found, add it to the overload
// set.
- for (FunctionSet::iterator Func = Functions.begin(),
- FuncEnd = Functions.end();
- Func != FuncEnd; ++Func) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) {
+ for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
if (ExplicitTemplateArgs)
continue;
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet,
false, false, PartialOverloading);
} else
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),
- ExplicitTemplateArgs,
+ AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I),
+ AS_none, ExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
}
}
@@ -4164,7 +4208,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
/// candidate is a better candidate than the second (C++ 13.3.3p1).
bool
Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
- const OverloadCandidate& Cand2) {
+ const OverloadCandidate& Cand2,
+ SourceLocation Loc) {
// Define viable functions to be better candidates than non-viable
// functions.
if (!Cand2.Viable)
@@ -4227,6 +4272,7 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
if (FunctionTemplateDecl *BetterTemplate
= getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
Cand2.Function->getPrimaryTemplate(),
+ Loc,
isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
: TPOC_Call))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
@@ -4279,7 +4325,8 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand) {
if (Cand->Viable) {
- if (Best == CandidateSet.end() || isBetterOverloadCandidate(*Cand, *Best))
+ if (Best == CandidateSet.end() ||
+ isBetterOverloadCandidate(*Cand, *Best, Loc))
Best = Cand;
}
}
@@ -4294,7 +4341,7 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
Cand != CandidateSet.end(); ++Cand) {
if (Cand->Viable &&
Cand != Best &&
- !isBetterOverloadCandidate(*Best, *Cand)) {
+ !isBetterOverloadCandidate(*Best, *Cand, Loc)) {
Best = CandidateSet.end();
return OR_Ambiguous;
}
@@ -4414,6 +4461,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
QualType FromTy = Conv.Bad.getFromType();
QualType ToTy = Conv.Bad.getToType();
+ if (FromTy == S.Context.OverloadTy) {
+ assert(FromExpr);
+ Expr *E = FromExpr->IgnoreParens();
+ if (isa<UnaryOperator>(E))
+ E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
+ DeclarationName Name = cast<OverloadExpr>(E)->getName();
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_overload)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << ToTy << Name << I+1;
+ return;
+ }
+
// Do some hand-waving analysis to see if the non-viability is due
// to a qualifier mismatch.
CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
@@ -4520,6 +4581,58 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
}
+/// Diagnose a failed template-argument deduction.
+void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
+ Expr **Args, unsigned NumArgs) {
+ FunctionDecl *Fn = Cand->Function; // pattern
+
+ TemplateParameter Param = TemplateParameter::getFromOpaqueValue(
+ Cand->DeductionFailure.TemplateParameter);
+
+ switch (Cand->DeductionFailure.Result) {
+ case Sema::TDK_Success:
+ llvm_unreachable("TDK_success while diagnosing bad deduction");
+
+ case Sema::TDK_Incomplete: {
+ NamedDecl *ParamD;
+ (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
+ (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
+ assert(ParamD && "no parameter found for incomplete deduction result");
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_incomplete_deduction)
+ << ParamD->getDeclName();
+ return;
+ }
+
+ // TODO: diagnose these individually, then kill off
+ // note_ovl_candidate_bad_deduction, which is uselessly vague.
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_InconsistentQuals:
+ case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_FailedOverloadResolution:
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
+ return;
+ }
+}
+
+/// Generates a 'note' diagnostic for an overload candidate. We've
+/// already generated a primary error at the call site.
+///
+/// It really does need to be a single diagnostic with its caret
+/// pointed at the candidate declaration. Yes, this creates some
+/// major challenges of technical writing. Yes, this makes pointing
+/// out problems with specific arguments quite awkward. It's still
+/// better than generating twenty screens of text for every failed
+/// overload.
+///
+/// It would be great to be able to express per-candidate problems
+/// more richly for those diagnostic clients that cared, but we'd
+/// still have to be just as careful with the default diagnostics.
void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
Expr **Args, unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function;
@@ -4546,6 +4659,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
+ return DiagnoseBadDeduction(S, Cand, Args, NumArgs);
+
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
return S.NoteOverloadCandidate(Fn);
@@ -4651,8 +4766,8 @@ struct CompareOverloadCandidatesForDisplay {
// TODO: introduce a tri-valued comparison for overload
// candidates. Would be more worthwhile if we had a sort
// that could exploit it.
- if (S.isBetterOverloadCandidate(*L, *R)) return true;
- if (S.isBetterOverloadCandidate(*R, *L)) return false;
+ if (S.isBetterOverloadCandidate(*L, *R, SourceLocation())) return true;
+ if (S.isBetterOverloadCandidate(*R, *L, SourceLocation())) return false;
} else if (R->Viable)
return false;
@@ -4842,6 +4957,14 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
}
}
+static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, NamedDecl *D,
+ AccessSpecifier AS) {
+ if (isa<UnresolvedLookupExpr>(E))
+ return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D, AS);
+
+ return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D, AS);
+}
+
/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
/// an overloaded function (C++ [over.over]), where @p From is an
/// expression with overloaded function type and @p ToType is the type
@@ -4878,52 +5001,28 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
// Find the actual overloaded function declaration.
+ if (From->getType() != Context.OverloadTy)
+ return 0;
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
- Expr *OvlExpr = From->IgnoreParens();
-
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
- if (UnOp->getOpcode() == UnaryOperator::AddrOf)
- OvlExpr = UnOp->getSubExpr()->IgnoreParens();
+ OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer();
+ TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0;
+ if (OvlExpr->hasExplicitTemplateArgs()) {
+ OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
+ ExplicitTemplateArgs = &ETABuffer;
}
- bool HasExplicitTemplateArgs = false;
- TemplateArgumentListInfo ExplicitTemplateArgs;
-
- llvm::SmallVector<NamedDecl*,8> Fns;
-
- // Look into the overloaded expression.
- if (UnresolvedLookupExpr *UL
- = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
- Fns.append(UL->decls_begin(), UL->decls_end());
- if (UL->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- } else if (UnresolvedMemberExpr *ME
- = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
- Fns.append(ME->decls_begin(), ME->decls_end());
- if (ME->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- }
-
- // If we didn't actually find anything, we're done.
- if (Fns.empty())
- return 0;
-
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
- llvm::SmallPtrSet<FunctionDecl *, 4> Matches;
+ UnresolvedSet<4> Matches; // contains only FunctionDecls
bool FoundNonTemplateFunction = false;
- for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
- E = Fns.end(); I != E; ++I) {
+ for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
+ E = OvlExpr->decls_end(); I != E; ++I) {
// Look through any using declarations to find the underlying function.
NamedDecl *Fn = (*I)->getUnderlyingDecl();
@@ -4953,10 +5052,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// overloaded functions considered.
// FIXME: We don't really want to build the specialization here, do we?
FunctionDecl *Specialization = 0;
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(FunctionTemplate,
- (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0),
+ = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
FunctionType, Specialization, Info)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
@@ -4965,8 +5063,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// a candidate? Find a testcase before changing the code.
assert(FunctionType
== Context.getCanonicalType(Specialization->getType()));
- Matches.insert(
- cast<FunctionDecl>(Specialization->getCanonicalDecl()));
+ Matches.addDecl(cast<FunctionDecl>(Specialization->getCanonicalDecl()),
+ I.getAccess());
}
continue;
@@ -4979,7 +5077,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
continue;
// If we have explicit template arguments, skip non-templates.
- if (HasExplicitTemplateArgs)
+ if (OvlExpr->hasExplicitTemplateArgs())
continue;
} else if (IsMember)
continue;
@@ -4989,7 +5087,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) ||
IsNoReturnConversion(Context, FunDecl->getType(), FunctionType,
ResultTy)) {
- Matches.insert(cast<FunctionDecl>(FunDecl->getCanonicalDecl()));
+ Matches.addDecl(cast<FunctionDecl>(FunDecl->getCanonicalDecl()),
+ I.getAccess());
FoundNonTemplateFunction = true;
}
}
@@ -4999,14 +5098,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
if (Matches.empty())
return 0;
else if (Matches.size() == 1) {
- FunctionDecl *Result = *Matches.begin();
+ FunctionDecl *Result = cast<FunctionDecl>(*Matches.begin());
MarkDeclarationReferenced(From->getLocStart(), Result);
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, Result, Matches.begin().getAccess());
return Result;
}
// C++ [over.over]p4:
// If more than one function is selected, [...]
- typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter;
if (!FoundNonTemplateFunction) {
// [...] and any given function template specialization F1 is
// eliminated if the set contains a second function template
@@ -5018,41 +5118,50 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// two-pass algorithm (similar to the one used to identify the
// best viable function in an overload set) that identifies the
// best function template (if it exists).
- llvm::SmallVector<FunctionDecl *, 8> TemplateMatches(Matches.begin(),
- Matches.end());
- FunctionDecl *Result =
- getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(),
+
+ UnresolvedSetIterator Result =
+ getMostSpecialized(Matches.begin(), Matches.end(),
TPOC_Other, From->getLocStart(),
PDiag(),
PDiag(diag::err_addr_ovl_ambiguous)
- << TemplateMatches[0]->getDeclName(),
+ << Matches[0]->getDeclName(),
PDiag(diag::note_ovl_candidate)
<< (unsigned) oc_function_template);
- MarkDeclarationReferenced(From->getLocStart(), Result);
- return Result;
+ assert(Result != Matches.end() && "no most-specialized template");
+ MarkDeclarationReferenced(From->getLocStart(), *Result);
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, *Result, Result.getAccess());
+ return cast<FunctionDecl>(*Result);
}
// [...] any function template specializations in the set are
// eliminated if the set also contains a non-template function, [...]
- llvm::SmallVector<FunctionDecl *, 4> RemainingMatches;
- for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M)
- if ((*M)->getPrimaryTemplate() == 0)
- RemainingMatches.push_back(*M);
+ for (unsigned I = 0, N = Matches.size(); I != N; ) {
+ if (cast<FunctionDecl>(Matches[I].getDecl())->getPrimaryTemplate() == 0)
+ ++I;
+ else {
+ Matches.erase(I);
+ --N;
+ }
+ }
// [...] After such eliminations, if any, there shall remain exactly one
// selected function.
- if (RemainingMatches.size() == 1) {
- FunctionDecl *Result = RemainingMatches.front();
- MarkDeclarationReferenced(From->getLocStart(), Result);
- return Result;
+ if (Matches.size() == 1) {
+ UnresolvedSetIterator Match = Matches.begin();
+ MarkDeclarationReferenced(From->getLocStart(), *Match);
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, *Match, Match.getAccess());
+ return cast<FunctionDecl>(*Match);
}
// FIXME: We should probably return the same thing that BestViableFunction
// returns (even if we issue the diagnostics here).
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
- << RemainingMatches[0]->getDeclName();
- for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I)
- NoteOverloadCandidate(RemainingMatches[I]);
+ << Matches[0]->getDeclName();
+ for (UnresolvedSetIterator I = Matches.begin(),
+ E = Matches.end(); I != E; ++I)
+ NoteOverloadCandidate(cast<FunctionDecl>(*I));
return 0;
}
@@ -5067,47 +5176,27 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
// C++ [over.over]p1:
// [...] [Note: any redundant set of parentheses surrounding the
// overloaded function name is ignored (5.1). ]
- Expr *OvlExpr = From->IgnoreParens();
-
// C++ [over.over]p1:
// [...] The overloaded function name can be preceded by the &
// operator.
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
- if (UnOp->getOpcode() == UnaryOperator::AddrOf)
- OvlExpr = UnOp->getSubExpr()->IgnoreParens();
- }
-
- bool HasExplicitTemplateArgs = false;
- TemplateArgumentListInfo ExplicitTemplateArgs;
-
- llvm::SmallVector<NamedDecl*,8> Fns;
-
- // Look into the overloaded expression.
- if (UnresolvedLookupExpr *UL
- = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
- Fns.append(UL->decls_begin(), UL->decls_end());
- if (UL->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- } else if (UnresolvedMemberExpr *ME
- = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
- Fns.append(ME->decls_begin(), ME->decls_end());
- if (ME->hasExplicitTemplateArgs()) {
- HasExplicitTemplateArgs = true;
- ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
- }
- }
+
+ if (From->getType() != Context.OverloadTy)
+ return 0;
+
+ OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer();
// If we didn't actually find any template-ids, we're done.
- if (Fns.empty() || !HasExplicitTemplateArgs)
+ if (!OvlExpr->hasExplicitTemplateArgs())
return 0;
+
+ TemplateArgumentListInfo ExplicitTemplateArgs;
+ OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
FunctionDecl *Matched = 0;
- for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
- E = Fns.end(); I != E; ++I) {
+ for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
+ E = OvlExpr->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
@@ -5123,7 +5212,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);
+ TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info)) {
@@ -5145,6 +5234,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
/// \brief Add a single candidate to the overload set.
static void AddOverloadedCallCandidate(Sema &S,
NamedDecl *Callee,
+ AccessSpecifier Access,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
@@ -5154,14 +5244,14 @@ static void AddOverloadedCallCandidate(Sema &S,
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
assert(!ExplicitTemplateArgs && "Explicit template arguments?");
- S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false,
- PartialOverloading);
+ S.AddOverloadCandidate(Func, Access, Args, NumArgs, CandidateSet,
+ false, false, PartialOverloading);
return;
}
if (FunctionTemplateDecl *FuncTemplate
= dyn_cast<FunctionTemplateDecl>(Callee)) {
- S.AddTemplateOverloadCandidate(FuncTemplate, ExplicitTemplateArgs,
+ S.AddTemplateOverloadCandidate(FuncTemplate, Access, ExplicitTemplateArgs,
Args, NumArgs, CandidateSet);
return;
}
@@ -5217,12 +5307,13 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
E = ULE->decls_end(); I != E; ++I)
- AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs,
+ AddOverloadedCallCandidate(*this, *I, I.getAccess(), ExplicitTemplateArgs,
Args, NumArgs, CandidateSet,
PartialOverloading);
if (ULE->requiresADL())
- AddArgumentDependentLookupCandidates(ULE->getName(), Args, NumArgs,
+ AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
+ Args, NumArgs,
ExplicitTemplateArgs,
CandidateSet,
PartialOverloading);
@@ -5321,7 +5412,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
}
#endif
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Fn->getExprLoc());
// Add the functions denoted by the callee to the set of candidate
// functions, including those from argument-dependent lookup.
@@ -5338,6 +5429,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
+ CheckUnresolvedLookupAccess(ULE, FDecl, Best->getAccess());
Fn = FixOverloadedFunctionReference(Fn, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
@@ -5372,7 +5464,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
return ExprError();
}
-static bool IsOverloaded(const Sema::FunctionSet &Functions) {
+static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
return Functions.size() > 1 ||
(Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
}
@@ -5393,10 +5485,10 @@ static bool IsOverloaded(const Sema::FunctionSet &Functions) {
/// by CreateOverloadedUnaryOp().
///
/// \param input The input argument.
-Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
- unsigned OpcIn,
- FunctionSet &Functions,
- ExprArg input) {
+Sema::OwningExprResult
+Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
+ const UnresolvedSetImpl &Fns,
+ ExprArg input) {
UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
Expr *Input = (Expr *)input.get();
@@ -5418,14 +5510,12 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
}
if (Input->isTypeDependent()) {
+ CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /*ADL*/ true, IsOverloaded(Functions));
- for (FunctionSet::iterator Func = Functions.begin(),
- FuncEnd = Functions.end();
- Func != FuncEnd; ++Func)
- Fn->addDecl(*Func);
+ /*ADL*/ true, IsOverloaded(Fns));
+ Fn->addDecls(Fns.begin(), Fns.end());
input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
@@ -5435,14 +5525,20 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(OpLoc);
// Add the candidates from the given function set.
- AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false);
+ AddFunctionCandidates(Fns, &Args[0], NumArgs, CandidateSet, false);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
+ // Add candidates from ADL.
+ AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
+ Args, NumArgs,
+ /*ExplicitTemplateArgs*/ 0,
+ CandidateSet);
+
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
@@ -5459,6 +5555,8 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+
if (PerformObjectArgumentInitialization(Input, Method))
return ExprError();
} else {
@@ -5555,7 +5653,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
Sema::OwningExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned OpcIn,
- FunctionSet &Functions,
+ const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=0; //Please use only Args instead of LHS/RHS couple
@@ -5567,7 +5665,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If either side is type-dependent, create an appropriate dependent
// expression.
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
- if (Functions.empty()) {
+ if (Fns.empty()) {
// If there are no functions to store, just build a dependent
// BinaryOperator or CompoundAssignment.
if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign)
@@ -5580,17 +5678,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Context.DependentTy,
OpLoc));
}
-
+
+ // FIXME: save results of ADL from here?
+ CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, OpLoc,
- /* ADL */ true, IsOverloaded(Functions));
-
- for (FunctionSet::iterator Func = Functions.begin(),
- FuncEnd = Functions.end();
- Func != FuncEnd; ++Func)
- Fn->addDecl(*Func);
+ /*ADL*/ true, IsOverloaded(Fns));
+ Fn->addDecls(Fns.begin(), Fns.end());
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
Args, 2,
Context.DependentTy,
@@ -5612,14 +5708,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(OpLoc);
// Add the candidates from the given function set.
- AddFunctionCandidates(Functions, Args, 2, CandidateSet, false);
+ AddFunctionCandidates(Fns, Args, 2, CandidateSet, false);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
+ // Add candidates from ADL.
+ AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
+ Args, 2,
+ /*ExplicitTemplateArgs*/ 0,
+ CandidateSet);
+
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
@@ -5636,6 +5738,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ // Best->Access is only meaningful for class members.
+ CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+
OwningExprResult Arg1
= PerformCopyInitialization(
InitializedEntity::InitializeParameter(
@@ -5770,8 +5875,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// expression.
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
+ CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true,
+ = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass,
0, SourceRange(), OpName, LLoc,
/*ADL*/ true, /*Overloaded*/ false);
// Can't add any actual overloads yet
@@ -5785,7 +5891,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(LLoc);
// Subscript can only be overloaded as a member function.
@@ -5806,14 +5912,24 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
+ CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess());
+
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
- if (PerformObjectArgumentInitialization(Args[0], Method) ||
- PerformCopyInitialization(Args[1],
- FnDecl->getParamDecl(0)->getType(),
- AA_Passing))
+ if (PerformObjectArgumentInitialization(Args[0], Method))
return ExprError();
+ // Convert the arguments.
+ OwningExprResult InputInit
+ = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(0)),
+ SourceLocation(),
+ Owned(Args[1]));
+ if (InputInit.isInvalid())
+ return ExprError();
+
+ Args[1] = InputInit.takeAs<Expr>();
+
// Determine the result type
QualType ResultTy
= FnDecl->getType()->getAs<FunctionType>()->getResultType();
@@ -5914,7 +6030,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
QualType ObjectType = UnresExpr->getBaseType();
// Add overload candidates
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc());
// FIXME: avoid copy.
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
@@ -5937,11 +6053,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (TemplateArgs)
continue;
- AddMethodCandidate(Method, ActingDC, ObjectType, Args, NumArgs,
+ AddMethodCandidate(Method, I.getAccess(), ActingDC, ObjectType,
+ Args, NumArgs,
CandidateSet, /*SuppressUserConversions=*/false);
} else {
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
- ActingDC, TemplateArgs,
+ I.getAccess(), ActingDC, TemplateArgs,
ObjectType, Args, NumArgs,
CandidateSet,
/*SuppressUsedConversions=*/false);
@@ -5954,6 +6071,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
+ CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess());
break;
case OR_No_Viable_Function:
@@ -6043,7 +6161,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
// (E).operator().
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(LParenLoc);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object->getType(),
@@ -6057,7 +6175,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
- AddMethodCandidate(*Oper, Object->getType(), Args, NumArgs, CandidateSet,
+ AddMethodCandidate(*Oper, Oper.getAccess(), Object->getType(),
+ Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/ false);
}
@@ -6101,7 +6220,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
ConvType = ConvPtrType->getPointeeType();
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
- AddSurrogateCandidate(Conv, ActingContext, Proto,
+ AddSurrogateCandidate(Conv, I.getAccess(), ActingContext, Proto,
Object->getType(), Args, NumArgs,
CandidateSet);
}
@@ -6158,6 +6277,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
+ CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess());
+
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
// on the object argument, then let ActOnCallExpr finish the job.
@@ -6171,6 +6292,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
CommaLocs, RParenLoc).release();
}
+ CheckMemberOperatorAccess(LParenLoc, Object,
+ Best->Function, Best->getAccess());
+
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
// parameter and passing along the remaining arguments.
@@ -6232,8 +6356,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
Arg = Args[i];
// Pass the argument.
- QualType ProtoArgType = Proto->getArgType(i);
- IsError |= PerformCopyInitialization(Arg, ProtoArgType, AA_Passing);
+
+ OwningExprResult InputInit
+ = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ Method->getParamDecl(i)),
+ SourceLocation(), Owned(Arg));
+
+ IsError |= InputInit.isInvalid();
+ Arg = InputInit.takeAs<Expr>();
} else {
OwningExprResult DefArg
= BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
@@ -6274,6 +6404,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
Expr *Base = static_cast<Expr *>(BaseIn.get());
assert(Base->getType()->isRecordType() && "left-hand side must have class type");
+ SourceLocation Loc = Base->getExprLoc();
+
// C++ [over.ref]p1:
//
// [...] An expression x->m is interpreted as (x.operator->())->m
@@ -6281,10 +6413,10 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
// the operator is selected as the best match function by the
// overload resolution mechanism (13.3).
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
- OverloadCandidateSet CandidateSet;
+ OverloadCandidateSet CandidateSet(Loc);
const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
- if (RequireCompleteType(Base->getLocStart(), Base->getType(),
+ if (RequireCompleteType(Loc, Base->getType(),
PDiag(diag::err_typecheck_incomplete_tag)
<< Base->getSourceRange()))
return ExprError();
@@ -6300,7 +6432,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- AddMethodCandidate(cast<CXXMethodDecl>(D), ActingContext,
+ AddMethodCandidate(cast<CXXMethodDecl>(D), Oper.getAccess(), ActingContext,
Base->getType(), 0, 0, CandidateSet,
/*SuppressUserConversions=*/false);
}
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index f8353e3db1bd..e6dfa742355f 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -139,9 +139,10 @@ namespace clang {
/// QualType.
void *FromTypePtr;
- /// ToType - The type that this conversion is converting to. This
- /// is an opaque pointer that can be translated into a QualType.
- void *ToTypePtr;
+ /// ToType - The types that this conversion is converting to in
+ /// each step. This is an opaque pointer that can be translated
+ /// into a QualType.
+ void *ToTypePtrs[3];
/// CopyConstructor - The copy constructor that is used to perform
/// this conversion, when the conversion is actually just the
@@ -151,12 +152,22 @@ namespace clang {
CXXConstructorDecl *CopyConstructor;
void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
- void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+ void setToType(unsigned Idx, QualType T) {
+ assert(Idx < 3 && "To type index is out of range");
+ ToTypePtrs[Idx] = T.getAsOpaquePtr();
+ }
+ void setAllToTypes(QualType T) {
+ ToTypePtrs[0] = T.getAsOpaquePtr();
+ ToTypePtrs[1] = ToTypePtrs[0];
+ ToTypePtrs[2] = ToTypePtrs[0];
+ }
+
QualType getFromType() const {
return QualType::getFromOpaquePtr(FromTypePtr);
}
- QualType getToType() const {
- return QualType::getFromOpaquePtr(ToTypePtr);
+ QualType getToType(unsigned Idx) const {
+ assert(Idx < 3 && "To type index is out of range");
+ return QualType::getFromOpaquePtr(ToTypePtrs[Idx]);
}
void setAsIdentityConversion();
@@ -446,11 +457,33 @@ namespace clang {
/// Actually an OverloadFailureKind.
unsigned char FailureKind;
- /// FinalConversion - For a conversion function (where Function is
- /// a CXXConversionDecl), the standard conversion that occurs
- /// after the call to the overload candidate to convert the result
- /// of calling the conversion function to the required type.
- StandardConversionSequence FinalConversion;
+ /// PathAccess - The 'path access' to the given function/conversion.
+ /// Actually an AccessSpecifier.
+ unsigned Access;
+
+ AccessSpecifier getAccess() const {
+ return AccessSpecifier(Access);
+ }
+
+ /// A structure used to record information about a failed
+ /// template argument deduction.
+ struct DeductionFailureInfo {
+ // A Sema::TemplateDeductionResult.
+ unsigned Result;
+
+ // A TemplateParameter.
+ void *TemplateParameter;
+ };
+
+ union {
+ DeductionFailureInfo DeductionFailure;
+
+ /// FinalConversion - For a conversion function (where Function is
+ /// a CXXConversionDecl), the standard conversion that occurs
+ /// after the call to the overload candidate to convert the result
+ /// of calling the conversion function to the required type.
+ StandardConversionSequence FinalConversion;
+ };
/// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not.
@@ -468,8 +501,13 @@ namespace clang {
class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> {
typedef llvm::SmallVector<OverloadCandidate, 16> inherited;
llvm::SmallPtrSet<Decl *, 16> Functions;
-
+
+ SourceLocation Loc;
public:
+ OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {}
+
+ SourceLocation getLocation() const { return Loc; }
+
/// \brief Determine when this overload candidate will be new to the
/// overload set.
bool isNewCandidate(Decl *F) {
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 0c207fa6e87d..fa42634a3475 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -93,6 +93,15 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (isa<ObjCImplicitSetterGetterRefExpr>(E))
DiagID = diag::warn_unused_property_expr;
+ if (const CXXExprWithTemporaries *Temps = dyn_cast<CXXExprWithTemporaries>(E))
+ E = Temps->getSubExpr();
+ if (const CXXZeroInitValueExpr *Zero = dyn_cast<CXXZeroInitValueExpr>(E)) {
+ if (const RecordType *RecordT = Zero->getType()->getAs<RecordType>())
+ if (CXXRecordDecl *RecordD = dyn_cast<CXXRecordDecl>(RecordT->getDecl()))
+ if (!RecordD->hasTrivialDestructor())
+ return;
+ }
+
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
// If the callee has attribute pure, const, or warn_unused_result, warn with
// a more specific message to make it clear what is happening.
@@ -370,6 +379,22 @@ static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs,
return false;
}
+/// CmpEnumVals - Comparison predicate for sorting enumeration values.
+///
+static bool CmpEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
+ const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
+{
+ return lhs.first < rhs.first;
+}
+
+/// EqEnumVals - Comparison preficate for uniqing enumeration values.
+///
+static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
+ const std::pair<llvm::APSInt, EnumConstantDecl*>& rhs)
+{
+ return lhs.first == rhs.first;
+}
+
/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
/// potentially integral-promoted expression @p expr.
static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) {
@@ -482,6 +507,16 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
return false;
}
+/// ActOnSwitchBodyError - This is called if there is an error parsing the
+/// body of the switch stmt instead of ActOnFinishSwitchStmt.
+void Sema::ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
+ StmtArg Body) {
+ // Keep the switch stack balanced.
+ assert(getSwitchStack().back() == (SwitchStmt*)Switch.get() &&
+ "switch stack missing push/pop!");
+ getSwitchStack().pop_back();
+}
+
Action::OwningStmtResult
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
StmtArg Body) {
@@ -550,7 +585,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
CaseValsTy CaseVals;
// Keep track of any GNU case ranges we see. The APSInt is the low value.
- std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges;
+ typedef std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRangesTy;
+ CaseRangesTy CaseRanges;
DefaultStmt *TheDefaultStmt = 0;
@@ -713,6 +749,75 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
}
}
}
+
+ // Check to see if switch is over an Enum and handles all of its
+ // values
+ const EnumType* ET = dyn_cast<EnumType>(CondTypeBeforePromotion);
+ // If switch has default case, then ignore it.
+ if (!CaseListIsErroneous && !TheDefaultStmt && ET) {
+ const EnumDecl *ED = ET->getDecl();
+ typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
+ EnumValsTy EnumVals;
+
+ // Gather all enum values, set their type and sort them, allowing easier comparison
+ // with CaseVals.
+ for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin(); EDI != ED->enumerator_end(); EDI++) {
+ llvm::APSInt Val = (*EDI)->getInitVal();
+ if(Val.getBitWidth() < CondWidth)
+ Val.extend(CondWidth);
+ Val.setIsSigned(CondIsSigned);
+ EnumVals.push_back(std::make_pair(Val, (*EDI)));
+ }
+ std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
+ EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+ // See which case values aren't in enum
+ EnumValsTy::const_iterator EI = EnumVals.begin();
+ for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) {
+ while (EI != EIend && EI->first < CI->first)
+ EI++;
+ if (EI == EIend || EI->first > CI->first)
+ Diag(CI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ }
+ // See which of case ranges aren't in enum
+ EI = EnumVals.begin();
+ for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) {
+ while (EI != EIend && EI->first < RI->first)
+ EI++;
+
+ if (EI == EIend || EI->first != RI->first) {
+ Diag(RI->second->getLHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ }
+
+ llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+ while (EI != EIend && EI->first < Hi)
+ EI++;
+ if (EI == EIend || EI->first != Hi)
+ Diag(RI->second->getRHS()->getExprLoc(), diag::not_in_enum) << ED->getDeclName();
+ }
+ //Check which enum vals aren't in switch
+ CaseValsTy::const_iterator CI = CaseVals.begin();
+ CaseRangesTy::const_iterator RI = CaseRanges.begin();
+ EI = EnumVals.begin();
+ for (; EI != EIend; EI++) {
+ //Drop unneeded case values
+ llvm::APSInt CIVal;
+ while (CI != CaseVals.end() && CI->first < EI->first)
+ CI++;
+
+ if (CI != CaseVals.end() && CI->first == EI->first)
+ continue;
+
+ //Drop unneeded case ranges
+ for (; RI != CaseRanges.end(); RI++) {
+ llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+ if (EI->first <= Hi)
+ break;
+ }
+
+ if (RI == CaseRanges.end() || EI->first < RI->first)
+ Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) << EI->second->getDeclName();
+ }
+ }
}
// FIXME: If the case list was broken is some way, we don't have a good system
@@ -863,7 +968,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
<< FirstType << First->getSourceRange();
}
if (Second) {
- DefaultFunctionArrayConversion(Second);
+ DefaultFunctionArrayLvalueConversion(Second);
QualType SecondType = Second->getType();
if (!SecondType->isObjCObjectPointerType())
Diag(ForLoc, diag::err_collection_expr_type)
@@ -896,10 +1001,10 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
Expr* E = DestExp.takeAs<Expr>();
if (!E->isTypeDependent()) {
QualType ETy = E->getType();
+ QualType DestTy = Context.getPointerType(Context.VoidTy.withConst());
AssignConvertType ConvTy =
- CheckSingleAssignmentConstraints(Context.VoidPtrTy, E);
- if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy,
- E, AA_Passing))
+ CheckSingleAssignmentConstraints(DestTy, E);
+ if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
return StmtError();
}
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
@@ -937,7 +1042,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (RetValExp) {
// Don't call UsualUnaryConversions(), since we don't want to do
// integer promotions here.
- DefaultFunctionArrayConversion(RetValExp);
+ DefaultFunctionArrayLvalueConversion(RetValExp);
CurBlock->ReturnType = RetValExp->getType();
if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
// We have to remove a 'const' added to copied-in variable which was
@@ -981,11 +1086,19 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// In C++ the return statement is handled via a copy initialization.
// the C version of which boils down to CheckSingleAssignmentConstraints.
- // FIXME: Leaks RetValExp.
- if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning))
+ OwningExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(ReturnLoc,
+ FnRetType),
+ SourceLocation(),
+ Owned(RetValExp));
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
return StmtError();
-
- if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ }
+
+ RetValExp = Res.takeAs<Expr>();
+ if (RetValExp)
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
@@ -1025,7 +1138,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
QualType FnRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->hasAttr<NoReturnAttr>() ||
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl())
@@ -1121,6 +1235,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
/// This method checks to see if the argument is an acceptable l-value and
/// returns false if it is a case we can handle.
static bool CheckAsmLValue(const Expr *E, Sema &S) {
+ // Type dependent expressions will be checked during instantiation.
+ if (E->isTypeDependent())
+ return false;
+
if (E->isLvalue(S.Context) == Expr::LV_Valid)
return false; // Cool, this is an lvalue.
@@ -1148,7 +1266,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
bool IsVolatile,
unsigned NumOutputs,
unsigned NumInputs,
- std::string *Names,
+ IdentifierInfo **Names,
MultiExprArg constraints,
MultiExprArg exprs,
ExprArg asmString,
@@ -1175,9 +1293,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
- Literal->getByteLength(),
- Names[i]);
+ llvm::StringRef OutputName;
+ if (Names[i])
+ OutputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
if (!Context.Target.validateOutputConstraint(Info))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_invalid_output_constraint)
@@ -1202,9 +1322,11 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- TargetInfo::ConstraintInfo Info(Literal->getStrData(),
- Literal->getByteLength(),
- Names[i]);
+ llvm::StringRef InputName;
+ if (Names[i])
+ InputName = Names[i]->getName();
+
+ TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(),
NumOutputs, Info)) {
return StmtError(Diag(Literal->getLocStart(),
@@ -1232,7 +1354,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
}
}
- DefaultFunctionArrayConversion(Exprs[i]);
+ DefaultFunctionArrayLvalueConversion(Exprs[i]);
InputConstraintInfos.push_back(Info);
}
@@ -1244,11 +1366,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
<< Literal->getSourceRange());
- std::string Clobber(Literal->getStrData(),
- Literal->getStrData() +
- Literal->getByteLength());
+ llvm::StringRef Clobber = Literal->getString();
- if (!Context.Target.isValidGCCRegisterName(Clobber.c_str()))
+ if (!Context.Target.isValidGCCRegisterName(Clobber))
return StmtError(Diag(Literal->getLocStart(),
diag::err_asm_unknown_register_name) << Clobber);
}
@@ -1258,9 +1378,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
asmString.release();
clobbers.release();
AsmStmt *NS =
- new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs,
- NumInputs, Names, Constraints, Exprs, AsmString,
- NumClobbers, Clobbers, RParenLoc);
+ new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
+ NumOutputs, NumInputs, Names, Constraints, Exprs,
+ AsmString, NumClobbers, Clobbers, RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
@@ -1527,7 +1647,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
CurFunctionNeedsScopeChecking = true;
RawHandlers.release();
- return Owned(new (Context) CXXTryStmt(TryLoc,
- static_cast<Stmt*>(TryBlock.release()),
- Handlers, NumHandlers));
+ return Owned(CXXTryStmt::Create(Context, TryLoc,
+ static_cast<Stmt*>(TryBlock.release()),
+ Handlers, NumHandlers));
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 00401560c6a0..10e411f5825a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -823,7 +823,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Check for redefinition of this class template.
if (TUK == TUK_Definition) {
- if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) {
+ if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
// FIXME: Would it make sense to try to "forget" the previous
@@ -1235,18 +1235,14 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// such a member, the member declaration shall be preceded by a
// template<> for each enclosing class template that is
// explicitly specialized.
- // We interpret this as forbidding typedefs of template
- // specializations in the scope specifiers of out-of-line decls.
- if (const TypedefType *TT = dyn_cast<TypedefType>(T)) {
- const Type *UnderlyingT = TT->LookThroughTypedefs().getTypePtr();
- if (isa<TemplateSpecializationType>(UnderlyingT))
- // FIXME: better source location information.
- Diag(DeclStartLoc, diag::err_typedef_in_def_scope) << QualType(T,0);
- T = UnderlyingT;
- }
+ //
+ // Following the existing practice of GNU and EDG, we allow a typedef of a
+ // template specialization type.
+ if (const TypedefType *TT = dyn_cast<TypedefType>(T))
+ T = TT->LookThroughTypedefs().getTypePtr();
if (const TemplateSpecializationType *SpecType
- = dyn_cast<TemplateSpecializationType>(T)) {
+ = dyn_cast<TemplateSpecializationType>(T)) {
TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
if (!Template)
continue; // FIXME: should this be an error? probably...
@@ -1525,17 +1521,19 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
QualifierRange = SS.getRange();
}
+
+ // We don't want lookup warnings at this point.
+ R.suppressDiagnostics();
bool Dependent
= UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(),
&TemplateArgs);
UnresolvedLookupExpr *ULE
- = UnresolvedLookupExpr::Create(Context, Dependent,
+ = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(),
Qualifier, QualifierRange,
R.getLookupName(), R.getNameLoc(),
RequiresADL, TemplateArgs);
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- ULE->addDecl(*I);
+ ULE->addDecls(R.begin(), R.end());
return Owned(ULE);
}
@@ -2305,7 +2303,17 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
} else
DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE || !isa<ValueDecl>(DRE->getDecl()))
+ if (!DRE)
+ return Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
+
+ // Stop checking the precise nature of the argument if it is value dependent,
+ // it should be checked when instantiated.
+ if (Arg->isValueDependent())
+ return false;
+
+ if (!isa<ValueDecl>(DRE->getDecl()))
return Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_object_or_func_form)
<< Arg->getSourceRange();
@@ -2324,7 +2332,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// Functions must have external linkage.
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- if (Func->getLinkage() != NamedDecl::ExternalLinkage) {
+ if (!isExternalLinkage(Func->getLinkage())) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_function_not_extern)
<< Func << Arg->getSourceRange();
@@ -2339,7 +2347,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
}
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (Var->getLinkage() != NamedDecl::ExternalLinkage) {
+ if (!isExternalLinkage(Var->getLinkage())) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_object_not_extern)
<< Var << Arg->getSourceRange();
@@ -2656,9 +2664,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ } else {
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(Entity);
+ }
return false;
}
@@ -2696,9 +2708,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ } else {
+ if (Entity)
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(Entity);
+ }
return false;
}
@@ -2712,7 +2728,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamRefType->getPointeeType()->isObjectType() &&
"Only object references allowed here");
- if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) {
+ QualType ReferredType = ParamRefType->getPointeeType();
+ if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_no_ref_bind)
<< InstantiatedParamType << Arg->getType()
@@ -2722,7 +2739,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
unsigned ParamQuals
- = Context.getCanonicalType(ParamType).getCVRQualifiers();
+ = Context.getCanonicalType(ReferredType).getCVRQualifiers();
unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
if ((ParamQuals | ArgQuals) != ParamQuals) {
@@ -2738,8 +2755,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ } else {
+ Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+ Converted = TemplateArgument(Entity);
+ }
return false;
}
@@ -3375,12 +3396,23 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// FIXME: Diagnose friend partial specializations
- // FIXME: Template parameter list matters, too
- ClassTemplatePartialSpecializationDecl::Profile(ID,
- Converted.getFlatArguments(),
- Converted.flatSize(),
- Context);
- } else
+ if (!Name.isDependent() &&
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs.getArgumentArray(),
+ TemplateArgs.size())) {
+ Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
+ << ClassTemplate->getDeclName();
+ isPartialSpecialization = false;
+ } else {
+ // FIXME: Template parameter list matters, too
+ ClassTemplatePartialSpecializationDecl::Profile(ID,
+ Converted.getFlatArguments(),
+ Converted.flatSize(),
+ Context);
+ }
+ }
+
+ if (!isPartialSpecialization)
ClassTemplateSpecializationDecl::Profile(ID,
Converted.getFlatArguments(),
Converted.flatSize(),
@@ -3410,7 +3442,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
QualType CanonType;
if (PrevDecl &&
(PrevDecl->getSpecializationKind() == TSK_Undeclared ||
- TUK == TUK_Friend)) {
+ TUK == TUK_Friend)) {
// Since the only prior class template specialization with these
// arguments was referenced but not declared, or we're only
// referencing this specialization as a friend, reuse that
@@ -3423,8 +3455,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
} else if (isPartialSpecialization) {
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
- CanonType = Context.getTemplateSpecializationType(
- TemplateName(ClassTemplate),
+ TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
+ CanonType = Context.getTemplateSpecializationType(CanonTemplate,
Converted.getFlatArguments(),
Converted.flatSize());
@@ -3532,7 +3564,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Check that this isn't a redefinition of this specialization.
if (TUK == TUK_Definition) {
- if (RecordDecl *Def = Specialization->getDefinition(Context)) {
+ if (RecordDecl *Def = Specialization->getDefinition()) {
SourceRange Range(TemplateNameLoc, RAngleLoc);
Diag(TemplateNameLoc, diag::err_redefinition)
<< Context.getTypeDeclType(Specialization) << Range;
@@ -3619,6 +3651,16 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
return DeclPtrTy();
}
+/// \brief Strips various properties off an implicit instantiation
+/// that has just been explicitly specialized.
+static void StripImplicitInstantiation(NamedDecl *D) {
+ D->invalidateAttrs();
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ FD->setInlineSpecified(false);
+ }
+}
+
/// \brief Diagnose cases where we have an explicit template specialization
/// before/after an explicit template instantiation, producing diagnostics
/// for those cases where they are required and determining whether the
@@ -3669,6 +3711,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
if (PrevPointOfInstantiation.isInvalid()) {
// The declaration itself has not actually been instantiated, so it is
// still okay to specialize it.
+ StripImplicitInstantiation(PrevDecl);
return false;
}
// Fall through
@@ -3817,8 +3860,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
LookupResult &Previous) {
// The set of function template specializations that could match this
// explicit function template specialization.
- typedef llvm::SmallVector<FunctionDecl *, 8> CandidateSet;
- CandidateSet Candidates;
+ UnresolvedSet<8> Candidates;
DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
@@ -3837,7 +3879,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Perform template argument deduction to determine whether we may be
// specializing this template.
// FIXME: It is somewhat wasteful to build
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, FD->getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
@@ -3851,22 +3893,24 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
}
// Record this candidate.
- Candidates.push_back(Specialization);
+ Candidates.addDecl(Specialization, I.getAccess());
}
}
// Find the most specialized function template.
- FunctionDecl *Specialization = getMostSpecialized(Candidates.data(),
- Candidates.size(),
- TPOC_Other,
- FD->getLocation(),
+ UnresolvedSetIterator Result
+ = getMostSpecialized(Candidates.begin(), Candidates.end(),
+ TPOC_Other, FD->getLocation(),
PartialDiagnostic(diag::err_function_template_spec_no_match)
<< FD->getDeclName(),
PartialDiagnostic(diag::err_function_template_spec_ambiguous)
<< FD->getDeclName() << (ExplicitTemplateArgs != 0),
PartialDiagnostic(diag::note_function_template_spec_matched));
- if (!Specialization)
+ if (Result == Candidates.end())
return true;
+
+ // Ignore access information; it doesn't figure into redeclaration checking.
+ FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
@@ -3887,15 +3931,15 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
- if (SpecInfo->getPointOfInstantiation().isValid()) {
- Diag(FD->getLocation(), diag::err_specialization_after_instantiation)
- << FD;
- Diag(SpecInfo->getPointOfInstantiation(),
- diag::note_instantiation_required_here)
- << (Specialization->getTemplateSpecializationKind()
- != TSK_ImplicitInstantiation);
+
+ bool SuppressNew = false;
+ if (CheckSpecializationInstantiationRedecl(FD->getLocation(),
+ TSK_ExplicitSpecialization,
+ Specialization,
+ SpecInfo->getTemplateSpecializationKind(),
+ SpecInfo->getPointOfInstantiation(),
+ SuppressNew))
return true;
- }
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
@@ -3904,8 +3948,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Turn the given function declaration into a function template
// specialization, with the template arguments from the previous
// specialization.
- FD->setFunctionTemplateSpecialization(Context,
- Specialization->getPrimaryTemplate(),
+ FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(),
new (Context) TemplateArgumentList(
*Specialization->getTemplateSpecializationArgs()),
/*InsertPos=*/0,
@@ -3997,14 +4040,15 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// instantiation to take place, in every translation unit in which such a
// use occurs; no diagnostic is required.
assert(MSInfo && "Member specialization info missing?");
- if (MSInfo->getPointOfInstantiation().isValid()) {
- Diag(Member->getLocation(), diag::err_specialization_after_instantiation)
- << Member;
- Diag(MSInfo->getPointOfInstantiation(),
- diag::note_instantiation_required_here)
- << (MSInfo->getTemplateSpecializationKind() != TSK_ImplicitInstantiation);
+
+ bool SuppressNew = false;
+ if (CheckSpecializationInstantiationRedecl(Member->getLocation(),
+ TSK_ExplicitSpecialization,
+ Instantiation,
+ MSInfo->getTemplateSpecializationKind(),
+ MSInfo->getPointOfInstantiation(),
+ SuppressNew))
return true;
- }
// Check the scope of this explicit specialization.
if (CheckTemplateSpecializationScope(*this,
@@ -4288,13 +4332,13 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// instantiation.
ClassTemplateSpecializationDecl *Def
= cast_or_null<ClassTemplateSpecializationDecl>(
- Specialization->getDefinition(Context));
+ Specialization->getDefinition());
if (!Def)
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
// Instantiate the members of this class template specialization.
Def = cast_or_null<ClassTemplateSpecializationDecl>(
- Specialization->getDefinition(Context));
+ Specialization->getDefinition());
if (Def)
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
@@ -4371,7 +4415,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Verify that it is okay to explicitly instantiate here.
CXXRecordDecl *PrevDecl
= cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration());
- if (!PrevDecl && Record->getDefinition(Context))
+ if (!PrevDecl && Record->getDefinition())
PrevDecl = Record;
if (PrevDecl) {
MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo();
@@ -4388,13 +4432,13 @@ Sema::ActOnExplicitInstantiation(Scope *S,
}
CXXRecordDecl *RecordDef
- = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+ = cast_or_null<CXXRecordDecl>(Record->getDefinition());
if (!RecordDef) {
// C++ [temp.explicit]p3:
// A definition of a member class of a class template shall be in scope
// at the point of an explicit instantiation of the member class.
CXXRecordDecl *Def
- = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+ = cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
if (!Def) {
Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member)
<< 0 << Record->getDeclName() << Record->getDeclContext();
@@ -4407,7 +4451,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
TSK))
return true;
- RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+ RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition());
if (!RecordDef)
return true;
}
@@ -4568,7 +4612,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// A member function [...] of a class template can be explicitly
// instantiated from the member definition associated with its class
// template.
- llvm::SmallVector<FunctionDecl *, 8> Matches;
+ UnresolvedSet<8> Matches;
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
P != PEnd; ++P) {
NamedDecl *Prev = *P;
@@ -4577,7 +4621,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
Matches.clear();
- Matches.push_back(Method);
+ Matches.addDecl(Method, P.getAccess());
if (Method->getTemplateSpecializationKind() == TSK_Undeclared)
break;
}
@@ -4588,7 +4632,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!FunTmpl)
continue;
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, D.getIdentifierLoc());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl,
@@ -4599,19 +4643,22 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
continue;
}
- Matches.push_back(Specialization);
+ Matches.addDecl(Specialization, P.getAccess());
}
// Find the most specialized function template specialization.
- FunctionDecl *Specialization
- = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other,
+ UnresolvedSetIterator Result
+ = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other,
D.getIdentifierLoc(),
PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
PartialDiagnostic(diag::note_explicit_instantiation_candidate));
- if (!Specialization)
+ if (Result == Matches.end())
return true;
+
+ // Ignore access control bits, we don't need them for redeclaration checking.
+ FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) {
Diag(D.getIdentifierLoc(),
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 7b433e901e33..df4d4a828d48 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -49,7 +49,7 @@ namespace clang {
using namespace clang;
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -72,7 +72,7 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
llvm::APSInt Value,
Sema::TemplateDeductionInfo &Info,
@@ -84,7 +84,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
QualType T = NTTP->getType();
// FIXME: Make sure we didn't overflow our data type!
- unsigned AllowedBits = Context.getTypeSize(T);
+ unsigned AllowedBits = S.Context.getTypeSize(T);
if (Value.getBitWidth() != AllowedBits)
Value.extOrTrunc(AllowedBits);
Value.setIsSigned(T->isSignedIntegerType());
@@ -126,7 +126,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
///
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
Sema::TemplateDeductionInfo &Info,
@@ -152,8 +152,8 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) {
// Compare the expressions for equality
llvm::FoldingSetNodeID ID1, ID2;
- Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, Context, true);
- Value->Profile(ID2, Context, true);
+ Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, S.Context, true);
+ Value->Profile(ID2, S.Context, true);
if (ID1 == ID2)
return Sema::TDK_Success;
@@ -169,7 +169,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
///
/// \returns true if deduction succeeded, false otherwise.
static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(ASTContext &Context,
+DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Decl *D,
Sema::TemplateDeductionInfo &Info,
@@ -202,7 +202,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
TemplateName Param,
TemplateName Arg,
@@ -221,13 +221,13 @@ DeduceTemplateArguments(ASTContext &Context,
TemplateArgument &ExistingArg = Deduced[TempParam->getIndex()];
if (ExistingArg.isNull()) {
// This is the first deduction for this template template parameter.
- ExistingArg = TemplateArgument(Context.getCanonicalTemplateName(Arg));
+ ExistingArg = TemplateArgument(S.Context.getCanonicalTemplateName(Arg));
return Sema::TDK_Success;
}
// Verify that the previous binding matches this deduction.
assert(ExistingArg.getKind() == TemplateArgument::Template);
- if (Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg))
+ if (S.Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg))
return Sema::TDK_Success;
// Inconsistent deduction.
@@ -238,7 +238,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
// Verify that the two template names are equivalent.
- if (Context.hasSameTemplateName(Param, Arg))
+ if (S.Context.hasSameTemplateName(Param, Arg))
return Sema::TDK_Success;
// Mismatch of non-dependent template parameter to argument.
@@ -250,7 +250,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// \brief Deduce the template arguments by comparing the template parameter
/// type (which is a template-id) with the template argument type.
///
-/// \param Context the AST context in which this deduction occurs.
+/// \param S the Sema
///
/// \param TemplateParams the template parameters that we are deducing
///
@@ -266,7 +266,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateSpecializationType *Param,
QualType Arg,
@@ -279,7 +279,7 @@ DeduceTemplateArguments(ASTContext &Context,
= dyn_cast<TemplateSpecializationType>(Arg)) {
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
Param->getTemplateName(),
SpecArg->getTemplateName(),
Info, Deduced))
@@ -291,7 +291,7 @@ DeduceTemplateArguments(ASTContext &Context,
unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs());
for (unsigned I = 0; I != NumArgs; ++I)
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
Param->getArg(I),
SpecArg->getArg(I),
Info, Deduced))
@@ -314,7 +314,7 @@ DeduceTemplateArguments(ASTContext &Context,
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context,
+ = DeduceTemplateArguments(S,
TemplateParams,
Param->getTemplateName(),
TemplateName(SpecArg->getSpecializedTemplate()),
@@ -328,7 +328,7 @@ DeduceTemplateArguments(ASTContext &Context,
for (unsigned I = 0; I != NumArgs; ++I)
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
Param->getArg(I),
ArgArgs.get(I),
Info, Deduced))
@@ -340,7 +340,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
-/// \param Context the AST context in which this deduction occurs.
+/// \param S the semantic analysis object within which we are deducing
///
/// \param TemplateParams the template parameters that we are deducing
///
@@ -359,7 +359,7 @@ DeduceTemplateArguments(ASTContext &Context,
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
@@ -367,8 +367,8 @@ DeduceTemplateArguments(ASTContext &Context,
unsigned TDF) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
- QualType Param = Context.getCanonicalType(ParamIn);
- QualType Arg = Context.getCanonicalType(ArgIn);
+ QualType Param = S.Context.getCanonicalType(ParamIn);
+ QualType Arg = S.Context.getCanonicalType(ArgIn);
// C++0x [temp.deduct.call]p4 bullet 1:
// - If the original P is a reference type, the deduced A (i.e., the type
@@ -376,10 +376,10 @@ DeduceTemplateArguments(ASTContext &Context,
// transformed A.
if (TDF & TDF_ParamWithReferenceType) {
Qualifiers Quals;
- QualType UnqualParam = Context.getUnqualifiedArrayType(Param, Quals);
+ QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals);
Quals.setCVRQualifiers(Quals.getCVRQualifiers() &
Arg.getCVRQualifiersThroughArrayTypes());
- Param = Context.getQualifiedType(UnqualParam, Quals);
+ Param = S.Context.getQualifiedType(UnqualParam, Quals);
}
// If the parameter type is not dependent, there is nothing to deduce.
@@ -409,9 +409,9 @@ DeduceTemplateArguments(ASTContext &Context,
// FIXME: address spaces, ObjC GC qualifiers
if (isa<ArrayType>(Arg)) {
Qualifiers Quals;
- Arg = Context.getUnqualifiedArrayType(Arg, Quals);
+ Arg = S.Context.getUnqualifiedArrayType(Arg, Quals);
if (Quals) {
- Arg = Context.getQualifiedType(Arg, Quals);
+ Arg = S.Context.getQualifiedType(Arg, Quals);
RecanonicalizeArg = true;
}
}
@@ -426,11 +426,11 @@ DeduceTemplateArguments(ASTContext &Context,
}
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
- assert(Arg != Context.OverloadTy && "Unresolved overloaded function");
+ assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function");
QualType DeducedType = Arg;
DeducedType.removeCVRQualifiers(Param.getCVRQualifiers());
if (RecanonicalizeArg)
- DeducedType = Context.getCanonicalType(DeducedType);
+ DeducedType = S.Context.getCanonicalType(DeducedType);
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(DeducedType);
@@ -479,7 +479,7 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_NonDeducedMismatch;
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
PointerArg->getPointeeType(),
Info, Deduced, SubTDF);
@@ -491,7 +491,7 @@ DeduceTemplateArguments(ASTContext &Context,
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
Info, Deduced, 0);
@@ -503,7 +503,7 @@ DeduceTemplateArguments(ASTContext &Context,
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
cast<RValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
Info, Deduced, 0);
@@ -512,12 +512,12 @@ DeduceTemplateArguments(ASTContext &Context,
// T [] (implied, but not stated explicitly)
case Type::IncompleteArray: {
const IncompleteArrayType *IncompleteArrayArg =
- Context.getAsIncompleteArrayType(Arg);
+ S.Context.getAsIncompleteArrayType(Arg);
if (!IncompleteArrayArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
- Context.getAsIncompleteArrayType(Param)->getElementType(),
+ return DeduceTemplateArguments(S, TemplateParams,
+ S.Context.getAsIncompleteArrayType(Param)->getElementType(),
IncompleteArrayArg->getElementType(),
Info, Deduced, 0);
}
@@ -525,16 +525,16 @@ DeduceTemplateArguments(ASTContext &Context,
// T [integer-constant]
case Type::ConstantArray: {
const ConstantArrayType *ConstantArrayArg =
- Context.getAsConstantArrayType(Arg);
+ S.Context.getAsConstantArrayType(Arg);
if (!ConstantArrayArg)
return Sema::TDK_NonDeducedMismatch;
const ConstantArrayType *ConstantArrayParm =
- Context.getAsConstantArrayType(Param);
+ S.Context.getAsConstantArrayType(Param);
if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
ConstantArrayParm->getElementType(),
ConstantArrayArg->getElementType(),
Info, Deduced, 0);
@@ -542,15 +542,15 @@ DeduceTemplateArguments(ASTContext &Context,
// type [i]
case Type::DependentSizedArray: {
- const ArrayType *ArrayArg = Context.getAsArrayType(Arg);
+ const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg);
if (!ArrayArg)
return Sema::TDK_NonDeducedMismatch;
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
- = Context.getAsDependentSizedArrayType(Param);
+ = S.Context.getAsDependentSizedArrayType(Param);
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
DependentArrayParm->getElementType(),
ArrayArg->getElementType(),
Info, Deduced, 0))
@@ -569,12 +569,12 @@ DeduceTemplateArguments(ASTContext &Context,
if (const ConstantArrayType *ConstantArrayArg
= dyn_cast<ConstantArrayType>(ArrayArg)) {
llvm::APSInt Size(ConstantArrayArg->getSize());
- return DeduceNonTypeTemplateArgument(Context, NTTP, Size,
+ return DeduceNonTypeTemplateArgument(S, NTTP, Size,
Info, Deduced);
}
if (const DependentSizedArrayType *DependentArrayArg
= dyn_cast<DependentSizedArrayType>(ArrayArg))
- return DeduceNonTypeTemplateArgument(Context, NTTP,
+ return DeduceNonTypeTemplateArgument(S, NTTP,
DependentArrayArg->getSizeExpr(),
Info, Deduced);
@@ -606,7 +606,7 @@ DeduceTemplateArguments(ASTContext &Context,
// Check return types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
FunctionProtoParam->getResultType(),
FunctionProtoArg->getResultType(),
Info, Deduced, 0))
@@ -615,7 +615,7 @@ DeduceTemplateArguments(ASTContext &Context,
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
// Check argument types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
FunctionProtoParam->getArgType(I),
FunctionProtoArg->getArgType(I),
Info, Deduced, 0))
@@ -636,7 +636,7 @@ DeduceTemplateArguments(ASTContext &Context,
// Try to deduce template arguments from the template-id.
Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams, SpecParam, Arg,
+ = DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg,
Info, Deduced);
if (Result && (TDF & TDF_DerivedClass)) {
@@ -649,7 +649,13 @@ DeduceTemplateArguments(ASTContext &Context,
// More importantly:
// These alternatives are considered only if type deduction would
// otherwise fail.
- if (const RecordType *RecordT = dyn_cast<RecordType>(Arg)) {
+ if (const RecordType *RecordT = Arg->getAs<RecordType>()) {
+ // We cannot inspect base classes as part of deduction when the type
+ // is incomplete, so either instantiate any templates necessary to
+ // complete the type, or skip over it if it cannot be completed.
+ if (S.RequireCompleteType(Info.getLocation(), Arg, 0))
+ return Result;
+
// Use data recursion to crawl through the list of base classes.
// Visited contains the set of nodes we have already visited, while
// ToVisit is our stack of records that we still need to visit.
@@ -670,7 +676,7 @@ DeduceTemplateArguments(ASTContext &Context,
// deduction from it.
if (NextT != RecordT) {
Sema::TemplateDeductionResult BaseResult
- = DeduceTemplateArguments(Context, TemplateParams, SpecParam,
+ = DeduceTemplateArguments(S, TemplateParams, SpecParam,
QualType(NextT, 0), Info, Deduced);
// If template argument deduction for this base was successful,
@@ -715,14 +721,14 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_NonDeducedMismatch;
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
MemPtrParam->getPointeeType(),
MemPtrArg->getPointeeType(),
Info, Deduced,
TDF & TDF_IgnoreQualifiers))
return Result;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
QualType(MemPtrParam->getClass(), 0),
QualType(MemPtrArg->getClass(), 0),
Info, Deduced, 0);
@@ -740,7 +746,7 @@ DeduceTemplateArguments(ASTContext &Context,
if (!BlockPtrArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
BlockPtrParam->getPointeeType(),
BlockPtrArg->getPointeeType(), Info,
Deduced, 0);
@@ -761,7 +767,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
@@ -774,7 +780,7 @@ DeduceTemplateArguments(ASTContext &Context,
case TemplateArgument::Type:
if (Arg.getKind() == TemplateArgument::Type)
- return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
+ return DeduceTemplateArguments(S, TemplateParams, Param.getAsType(),
Arg.getAsType(), Info, Deduced, 0);
Info.FirstArg = Param;
Info.SecondArg = Arg;
@@ -782,7 +788,7 @@ DeduceTemplateArguments(ASTContext &Context,
case TemplateArgument::Template:
if (Arg.getKind() == TemplateArgument::Template)
- return DeduceTemplateArguments(Context, TemplateParams,
+ return DeduceTemplateArguments(S, TemplateParams,
Param.getAsTemplate(),
Arg.getAsTemplate(), Info, Deduced);
Info.FirstArg = Param;
@@ -826,14 +832,14 @@ DeduceTemplateArguments(ASTContext &Context,
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
// FIXME: Sign problems here
- return DeduceNonTypeTemplateArgument(Context, NTTP,
+ return DeduceNonTypeTemplateArgument(S, NTTP,
*Arg.getAsIntegral(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
- return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
+ return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Declaration)
- return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsDecl(),
+ return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(),
Info, Deduced);
assert(false && "Type/value mismatch");
@@ -854,7 +860,7 @@ DeduceTemplateArguments(ASTContext &Context,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(ASTContext &Context,
+DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
@@ -863,7 +869,7 @@ DeduceTemplateArguments(ASTContext &Context,
assert(ParamList.size() == ArgList.size());
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(Context, TemplateParams,
+ = DeduceTemplateArguments(S, TemplateParams,
ParamList[I], ArgList[I],
Info, Deduced))
return Result;
@@ -951,7 +957,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context,
+ = ::DeduceTemplateArguments(*this,
Partial->getTemplateParameters(),
Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
@@ -1306,6 +1312,91 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
return TDK_Success;
}
+static QualType GetTypeOfFunction(ASTContext &Context,
+ bool isAddressOfOperand,
+ FunctionDecl *Fn) {
+ if (!isAddressOfOperand) return Fn->getType();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
+ if (Method->isInstance())
+ return Context.getMemberPointerType(Fn->getType(),
+ Context.getTypeDeclType(Method->getParent()).getTypePtr());
+ return Context.getPointerType(Fn->getType());
+}
+
+/// Apply the deduction rules for overload sets.
+///
+/// \return the null type if this argument should be treated as an
+/// undeduced context
+static QualType
+ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
+ Expr *Arg, QualType ParamType) {
+ llvm::PointerIntPair<OverloadExpr*,1> R = OverloadExpr::find(Arg);
+
+ bool isAddressOfOperand = bool(R.getInt());
+ OverloadExpr *Ovl = R.getPointer();
+
+ // If there were explicit template arguments, we can only find
+ // something via C++ [temp.arg.explicit]p3, i.e. if the arguments
+ // unambiguously name a full specialization.
+ if (Ovl->hasExplicitTemplateArgs()) {
+ // But we can still look for an explicit specialization.
+ if (FunctionDecl *ExplicitSpec
+ = S.ResolveSingleFunctionTemplateSpecialization(Ovl))
+ return GetTypeOfFunction(S.Context, isAddressOfOperand, ExplicitSpec);
+ return QualType();
+ }
+
+ // C++0x [temp.deduct.call]p6:
+ // When P is a function type, pointer to function type, or pointer
+ // to member function type:
+
+ if (!ParamType->isFunctionType() &&
+ !ParamType->isFunctionPointerType() &&
+ !ParamType->isMemberFunctionPointerType())
+ return QualType();
+
+ QualType Match;
+ for (UnresolvedSetIterator I = Ovl->decls_begin(),
+ E = Ovl->decls_end(); I != E; ++I) {
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+
+ // - If the argument is an overload set containing one or more
+ // function templates, the parameter is treated as a
+ // non-deduced context.
+ if (isa<FunctionTemplateDecl>(D))
+ return QualType();
+
+ FunctionDecl *Fn = cast<FunctionDecl>(D);
+ QualType ArgType = GetTypeOfFunction(S.Context, isAddressOfOperand, Fn);
+
+ // - If the argument is an overload set (not containing function
+ // templates), trial argument deduction is attempted using each
+ // of the members of the set. If deduction succeeds for only one
+ // of the overload set members, that member is used as the
+ // argument value for the deduction. If deduction succeeds for
+ // more than one member of the overload set the parameter is
+ // treated as a non-deduced context.
+
+ // We do all of this in a fresh context per C++0x [temp.deduct.type]p2:
+ // Type deduction is done independently for each P/A pair, and
+ // the deduced template argument values are then combined.
+ // So we do not reject deductions which were made elsewhere.
+ llvm::SmallVector<TemplateArgument, 8> Deduced(TemplateParams->size());
+ Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
+ unsigned TDF = 0;
+
+ Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(S, TemplateParams,
+ ParamType, ArgType,
+ Info, Deduced, TDF);
+ if (Result) continue;
+ if (!Match.isNull()) return QualType();
+ Match = ArgType;
+ }
+
+ return Match;
+}
+
/// \brief Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
@@ -1384,6 +1475,15 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ParamType = ParamTypes[I];
QualType ArgType = Args[I]->getType();
+ // Overload sets usually make this parameter an undeduced
+ // context, but there are sometimes special circumstances.
+ if (ArgType == Context.OverloadTy) {
+ ArgType = ResolveOverloadForDeduction(*this, TemplateParams,
+ Args[I], ParamType);
+ if (ArgType.isNull())
+ continue;
+ }
+
// C++ [temp.deduct.call]p2:
// If P is not a reference type:
QualType CanonParamType = Context.getCanonicalType(ParamType);
@@ -1454,38 +1554,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
ParamType->getAs<PointerType>()->getPointeeType())))
TDF |= TDF_DerivedClass;
- // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
- // pointer parameters.
-
- if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) {
- // We know that template argument deduction will fail if the argument is
- // still an overloaded function. Check whether we can resolve this
- // argument as a single function template specialization per
- // C++ [temp.arg.explicit]p3.
- FunctionDecl *ExplicitSpec
- = ResolveSingleFunctionTemplateSpecialization(Args[I]);
- Expr *ResolvedArg = 0;
- if (ExplicitSpec)
- ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec);
- if (!ExplicitSpec || !ResolvedArg) {
- // Template argument deduction fails if we can't resolve the overloaded
- // function.
- return TDK_FailedOverloadResolution;
- }
-
- // Get the type of the resolved argument, and adjust it per
- // C++0x [temp.deduct.call]p3.
- ArgType = ResolvedArg->getType();
- if (!ParamWasReference && ArgType->isFunctionType())
- ArgType = Context.getPointerType(ArgType);
- if (ArgType->isPointerType() || ArgType->isMemberPointerType())
- TDF |= TDF_IgnoreQualifiers;
-
- ResolvedArg->Destroy(Context);
- }
-
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context, TemplateParams,
+ = ::DeduceTemplateArguments(*this, TemplateParams,
ParamType, ArgType, Info, Deduced,
TDF))
return Result;
@@ -1548,11 +1618,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Trap any errors that might occur.
SFINAETrap Trap(*this);
+ Deduced.resize(TemplateParams->size());
+
if (!ArgFunctionType.isNull()) {
// Deduce template arguments from the function type.
- Deduced.resize(TemplateParams->size());
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context, TemplateParams,
+ = ::DeduceTemplateArguments(*this, TemplateParams,
FunctionType, ArgFunctionType, Info,
Deduced, 0))
return Result;
@@ -1651,7 +1722,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
(P->isMemberPointerType() && P->isMemberPointerType()))
TDF |= TDF_IgnoreQualifiers;
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(Context, TemplateParams,
+ = ::DeduceTemplateArguments(*this, TemplateParams,
P, A, Info, Deduced, TDF))
return Result;
@@ -1702,7 +1773,7 @@ enum DeductionQualifierComparison {
/// \brief Deduce the template arguments during partial ordering by comparing
/// the parameter type and the argument type (C++0x [temp.deduct.partial]).
///
-/// \param Context the AST context in which this deduction occurs.
+/// \param S the semantic analysis object within which we are deducing
///
/// \param TemplateParams the template parameters that we are deducing
///
@@ -1718,14 +1789,14 @@ enum DeductionQualifierComparison {
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context,
+DeduceTemplateArgumentsDuringPartialOrdering(Sema &S,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced,
llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
- CanQualType Param = Context.getCanonicalType(ParamIn);
- CanQualType Arg = Context.getCanonicalType(ArgIn);
+ CanQualType Param = S.Context.getCanonicalType(ParamIn);
+ CanQualType Arg = S.Context.getCanonicalType(ArgIn);
// C++0x [temp.deduct.partial]p5:
// Before the partial ordering is done, certain transformations are
@@ -1772,7 +1843,7 @@ DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context,
// described in 14.9.2.5. If deduction succeeds for a given type, the type
// from the argument template is considered to be at least as specialized
// as the type from the parameter template.
- return DeduceTemplateArguments(Context, TemplateParams, Param, Arg, Info,
+ return DeduceTemplateArguments(S, TemplateParams, Param, Arg, Info,
Deduced, TDF_None);
}
@@ -1785,6 +1856,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
/// \brief Determine whether the function template \p FT1 is at least as
/// specialized as \p FT2.
static bool isAtLeastAsSpecializedAs(Sema &S,
+ SourceLocation Loc,
FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
@@ -1802,14 +1874,14 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// C++0x [temp.deduct.partial]p3:
// The types used to determine the ordering depend on the context in which
// the partial ordering is done:
- Sema::TemplateDeductionInfo Info(S.Context);
+ Sema::TemplateDeductionInfo Info(S.Context, Loc);
switch (TPOC) {
case TPOC_Call: {
// - In the context of a function call, the function parameter types are
// used.
unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
for (unsigned I = 0; I != NumParams; ++I)
- if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S,
TemplateParams,
Proto2->getArgType(I),
Proto1->getArgType(I),
@@ -1824,7 +1896,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Conversion:
// - In the context of a call to a conversion operator, the return types
// of the conversion function templates are used.
- if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S,
TemplateParams,
Proto2->getResultType(),
Proto1->getResultType(),
@@ -1837,7 +1909,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Other:
// - In other contexts (14.6.6.2) the function template’s function type
// is used.
- if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S,
TemplateParams,
FD2->getType(),
FD1->getType(),
@@ -1916,10 +1988,11 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
FunctionTemplateDecl *
Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
+ SourceLocation Loc,
TemplatePartialOrderingContext TPOC) {
llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons;
- bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0);
- bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC,
+ bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, 0);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
&QualifierComparisons);
if (Better1 != Better2) // We have a clear winner
@@ -1987,11 +2060,11 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// \brief Retrieve the most specialized of the given function template
/// specializations.
///
-/// \param Specializations the set of function template specializations that
-/// we will be comparing.
+/// \param SpecBegin the start iterator of the function template
+/// specializations that we will be comparing.
///
-/// \param NumSpecializations the number of function template specializations in
-/// \p Specializations
+/// \param SpecEnd the end iterator of the function template
+/// specializations, paired with \p SpecBegin.
///
/// \param TPOC the partial ordering context to use to compare the function
/// template specializations.
@@ -2015,42 +2088,38 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// specialization.
///
/// \returns the most specialized function template specialization, if
-/// found. Otherwise, returns NULL.
+/// found. Otherwise, returns SpecEnd.
///
/// \todo FIXME: Consider passing in the "also-ran" candidates that failed
/// template argument deduction.
-FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
- unsigned NumSpecializations,
- TemplatePartialOrderingContext TPOC,
- SourceLocation Loc,
- const PartialDiagnostic &NoneDiag,
- const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &CandidateDiag,
- unsigned *Index) {
- if (NumSpecializations == 0) {
+UnresolvedSetIterator
+Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
+ UnresolvedSetIterator SpecEnd,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag) {
+ if (SpecBegin == SpecEnd) {
Diag(Loc, NoneDiag);
- return 0;
+ return SpecEnd;
}
- if (NumSpecializations == 1) {
- if (Index)
- *Index = 0;
-
- return Specializations[0];
- }
-
+ if (SpecBegin + 1 == SpecEnd)
+ return SpecBegin;
// Find the function template that is better than all of the templates it
// has been compared to.
- unsigned Best = 0;
+ UnresolvedSetIterator Best = SpecBegin;
FunctionTemplateDecl *BestTemplate
- = Specializations[Best]->getPrimaryTemplate();
+ = cast<FunctionDecl>(*Best)->getPrimaryTemplate();
assert(BestTemplate && "Not a function template specialization?");
- for (unsigned I = 1; I != NumSpecializations; ++I) {
- FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ for (UnresolvedSetIterator I = SpecBegin + 1; I != SpecEnd; ++I) {
+ FunctionTemplateDecl *Challenger
+ = cast<FunctionDecl>(*I)->getPrimaryTemplate();
assert(Challenger && "Not a function template specialization?");
- if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
- TPOC),
+ if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ Loc, TPOC),
Challenger)) {
Best = I;
BestTemplate = Challenger;
@@ -2060,11 +2129,12 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
// Make sure that the "best" function template is more specialized than all
// of the others.
bool Ambiguous = false;
- for (unsigned I = 0; I != NumSpecializations; ++I) {
- FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) {
+ FunctionTemplateDecl *Challenger
+ = cast<FunctionDecl>(*I)->getPrimaryTemplate();
if (I != Best &&
!isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
- TPOC),
+ Loc, TPOC),
BestTemplate)) {
Ambiguous = true;
break;
@@ -2073,22 +2143,20 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
if (!Ambiguous) {
// We found an answer. Return it.
- if (Index)
- *Index = Best;
- return Specializations[Best];
+ return Best;
}
// Diagnose the ambiguity.
Diag(Loc, AmbigDiag);
// FIXME: Can we order the candidates in some sane way?
- for (unsigned I = 0; I != NumSpecializations; ++I)
- Diag(Specializations[I]->getLocation(), CandidateDiag)
+ for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I)
+ Diag((*I)->getLocation(), CandidateDiag)
<< getTemplateArgumentBindingsText(
- Specializations[I]->getPrimaryTemplate()->getTemplateParameters(),
- *Specializations[I]->getTemplateSpecializationArgs());
+ cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(),
+ *cast<FunctionDecl>(*I)->getTemplateSpecializationArgs());
- return 0;
+ return SpecEnd;
}
/// \brief Returns the more specialized class template partial specialization
@@ -2104,7 +2172,8 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
ClassTemplatePartialSpecializationDecl *
Sema::getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
- ClassTemplatePartialSpecializationDecl *PS2) {
+ ClassTemplatePartialSpecializationDecl *PS2,
+ SourceLocation Loc) {
// C++ [temp.class.order]p1:
// For two class template partial specializations, the first is at least as
// specialized as the second if, given the following rewrite to two
@@ -2127,11 +2196,11 @@ Sema::getMoreSpecializedPartialSpecialization(
// template partial ordering, because class template partial specializations
// are more constrained. We know that every template parameter is deduc
llvm::SmallVector<TemplateArgument, 4> Deduced;
- Sema::TemplateDeductionInfo Info(Context);
+ Sema::TemplateDeductionInfo Info(Context, Loc);
// Determine whether PS1 is at least as specialized as PS2
Deduced.resize(PS2->getTemplateParameters()->size());
- bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS2->getTemplateParameters(),
Context.getTypeDeclType(PS2),
Context.getTypeDeclType(PS1),
@@ -2142,7 +2211,7 @@ Sema::getMoreSpecializedPartialSpecialization(
// Determine whether PS2 is at least as specialized as PS1
Deduced.clear();
Deduced.resize(PS1->getTemplateParameters()->size());
- bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS1->getTemplateParameters(),
Context.getTypeDeclType(PS1),
Context.getTypeDeclType(PS2),
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 2db0deb5098b..51e17fe472e5 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -33,9 +33,15 @@ using namespace clang;
/// arguments.
///
/// \param Innermost if non-NULL, the innermost template argument list.
+///
+/// \param RelativeToPrimary true if we should get the template
+/// arguments relative to the primary template, even when we're
+/// dealing with a specialization. This is only relevant for function
+/// template specializations.
MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D,
- const TemplateArgumentList *Innermost) {
+ const TemplateArgumentList *Innermost,
+ bool RelativeToPrimary) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -64,8 +70,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
}
// Add template arguments from a function template specialization.
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
- if (Function->getTemplateSpecializationKind()
- == TSK_ExplicitSpecialization)
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
break;
if (const TemplateArgumentList *TemplateArgs
@@ -86,11 +93,13 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
if (Function->getFriendObjectKind() &&
Function->getDeclContext()->isFileContext()) {
Ctx = Function->getLexicalDeclContext();
+ RelativeToPrimary = false;
continue;
}
}
Ctx = Ctx->getParent();
+ RelativeToPrimary = false;
}
return Result;
@@ -555,6 +564,8 @@ namespace {
Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+ Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
+ NonTypeTemplateParmDecl *D);
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
@@ -569,6 +580,14 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+ // If the corresponding template argument is NULL or non-existent, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template, but there were some
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
+ TTP->getPosition()))
+ return D;
+
TemplateName Template
= TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
@@ -576,14 +595,6 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
return Template.getAsTemplateDecl();
}
- // If the corresponding template argument is NULL or non-existent, it's
- // because we are performing instantiation from explicitly-specified
- // template arguments in a function template, but there were some
- // arguments left unspecified.
- if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
- TTP->getPosition()))
- return D;
-
// Fall through to find the instantiated declaration for this template
// template parameter.
}
@@ -676,8 +687,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
PredefinedExpr::IdentType IT = E->getIdentType();
- unsigned Length =
- PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length();
+ unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
QualType ResTy = getSema().Context.CharTy.withConst();
@@ -689,88 +699,145 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
}
Sema::OwningExprResult
-TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
- // FIXME: Clean this up a bit
- NamedDecl *D = E->getDecl();
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
- if (NTTP->getDepth() < TemplateArgs.getNumLevels()) {
- // If the corresponding template argument is NULL or non-existent, it's
- // because we are performing instantiation from explicitly-specified
- // template arguments in a function template, but there were some
- // arguments left unspecified.
- if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
- NTTP->getPosition()))
- return SemaRef.Owned(E->Retain());
+TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
+ NonTypeTemplateParmDecl *NTTP) {
+ // If the corresponding template argument is NULL or non-existent, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template, but there were some
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
+ NTTP->getPosition()))
+ return SemaRef.Owned(E->Retain());
- const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(),
- NTTP->getPosition());
+ const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(),
+ NTTP->getPosition());
- // The template argument itself might be an expression, in which
- // case we just return that expression.
- if (Arg.getKind() == TemplateArgument::Expression)
- return SemaRef.Owned(Arg.getAsExpr()->Retain());
+ // The template argument itself might be an expression, in which
+ // case we just return that expression.
+ if (Arg.getKind() == TemplateArgument::Expression)
+ return SemaRef.Owned(Arg.getAsExpr()->Retain());
- if (Arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+ if (Arg.getKind() == TemplateArgument::Declaration) {
+ ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
- VD = cast_or_null<ValueDecl>(
+ // Find the instantiation of the template argument. This is
+ // required for nested templates.
+ VD = cast_or_null<ValueDecl>(
getSema().FindInstantiatedDecl(VD, TemplateArgs));
- if (!VD)
+ if (!VD)
+ return SemaRef.ExprError();
+
+ // Derive the type we want the substituted decl to have. This had
+ // better be non-dependent, or these checks will have serious problems.
+ QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs,
+ E->getLocation(),
+ DeclarationName());
+ assert(!TargetType.isNull() && "type substitution failed for param type");
+ assert(!TargetType->isDependentType() && "param type still dependent");
+
+ if (VD->getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
+ // If the value is a class member, we might have a pointer-to-member.
+ // Determine whether the non-type template template parameter is of
+ // pointer-to-member type. If so, we need to build an appropriate
+ // expression for a pointer-to-member, since a "normal" DeclRefExpr
+ // would refer to the member itself.
+ if (TargetType->isMemberPointerType()) {
+ QualType ClassType
+ = SemaRef.Context.getTypeDeclType(
+ cast<RecordDecl>(VD->getDeclContext()));
+ NestedNameSpecifier *Qualifier
+ = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
+ ClassType.getTypePtr());
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ OwningExprResult RefExpr
+ = SemaRef.BuildDeclRefExpr(VD,
+ VD->getType().getNonReferenceType(),
+ E->getLocation(),
+ &SS);
+ if (RefExpr.isInvalid())
return SemaRef.ExprError();
- if (VD->getDeclContext()->isRecord()) {
- // If the value is a class member, we might have a pointer-to-member.
- // Determine whether the non-type template template parameter is of
- // pointer-to-member type. If so, we need to build an appropriate
- // expression for a pointer-to-member, since a "normal" DeclRefExpr
- // would refer to the member itself.
- if (NTTP->getType()->isMemberPointerType()) {
- QualType ClassType
- = SemaRef.Context.getTypeDeclType(
- cast<RecordDecl>(VD->getDeclContext()));
- NestedNameSpecifier *Qualifier
- = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
- ClassType.getTypePtr());
- CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- OwningExprResult RefExpr
- = SemaRef.BuildDeclRefExpr(VD,
- VD->getType().getNonReferenceType(),
- E->getLocation(),
- &SS);
- if (RefExpr.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
- UnaryOperator::AddrOf,
- move(RefExpr));
- }
- }
+ RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
+ UnaryOperator::AddrOf,
+ move(RefExpr));
+ assert(!RefExpr.isInvalid() &&
+ SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(),
+ TargetType));
+ return move(RefExpr);
+ }
+ }
- return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
- E->getLocation());
+ QualType T = VD->getType().getNonReferenceType();
+
+ if (TargetType->isPointerType()) {
+ // C++03 [temp.arg.nontype]p5:
+ // - For a non-type template-parameter of type pointer to
+ // object, qualification conversions and the array-to-pointer
+ // conversion are applied.
+ // - For a non-type template-parameter of type pointer to
+ // function, only the function-to-pointer conversion is
+ // applied.
+
+ OwningExprResult RefExpr
+ = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
+ if (RefExpr.isInvalid())
+ return SemaRef.ExprError();
+
+ // Decay functions and arrays.
+ Expr *RefE = (Expr *)RefExpr.get();
+ SemaRef.DefaultFunctionArrayConversion(RefE);
+ if (RefE != RefExpr.get()) {
+ RefExpr.release();
+ RefExpr = SemaRef.Owned(RefE);
}
- assert(Arg.getKind() == TemplateArgument::Integral);
- QualType T = Arg.getIntegralType();
- if (T->isCharType() || T->isWideCharType())
- return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
+ // Qualification conversions.
+ RefExpr.release();
+ SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(),
+ CastExpr::CK_NoOp);
+ return SemaRef.Owned(RefE);
+ }
+
+ // If the non-type template parameter has reference type, qualify the
+ // resulting declaration reference with the extra qualifiers on the
+ // type that the reference refers to.
+ if (const ReferenceType *TargetRef = TargetType->getAs<ReferenceType>())
+ T = SemaRef.Context.getQualifiedType(T,
+ TargetRef->getPointeeType().getQualifiers());
+
+ return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
+ }
+
+ assert(Arg.getKind() == TemplateArgument::Integral);
+ QualType T = Arg.getIntegralType();
+ if (T->isCharType() || T->isWideCharType())
+ return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
Arg.getAsIntegral()->getZExtValue(),
T->isWideCharType(),
T,
E->getSourceRange().getBegin()));
- if (T->isBooleanType())
- return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
+ if (T->isBooleanType())
+ return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
Arg.getAsIntegral()->getBoolValue(),
T,
E->getSourceRange().getBegin()));
- assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
- return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
+ assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
+ return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
*Arg.getAsIntegral(),
T,
E->getSourceRange().getBegin()));
- }
+}
+
+
+Sema::OwningExprResult
+TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
+ NamedDecl *D = E->getDecl();
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ if (NTTP->getDepth() < TemplateArgs.getNumLevels())
+ return TransformTemplateParmRefExpr(E, NTTP);
// We have a non-type template parameter that isn't fully substituted;
// FindInstantiatedDecl will find it in the local instantiation scope.
@@ -986,7 +1053,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
bool Invalid = false;
CXXRecordDecl *PatternDef
- = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+ = cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
if (!PatternDef) {
if (!Complain) {
// Say nothing
@@ -1063,9 +1130,18 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// If this is a polymorphic C++ class without a key function, we'll
// have to mark all of the virtual members to allow emission of a vtable
// in this translation unit.
- if (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation))
+ if (Instantiation->isDynamicClass() &&
+ !Context.getKeyFunction(Instantiation)) {
+ // Local classes need to have their methods instantiated immediately in
+ // order to have the correct instantiation scope.
+ if (Instantiation->isLocalClass()) {
+ MarkVirtualMembersReferenced(PointOfInstantiation,
+ Instantiation);
+ } else {
ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation,
PointOfInstantiation));
+ }
+ }
if (!Invalid)
Consumer.HandleTagDeclDefinition(Instantiation);
@@ -1124,7 +1200,7 @@ Sema::InstantiateClassTemplateSpecialization(
PartialEnd = Template->getPartialSpecializations().end();
Partial != PartialEnd;
++Partial) {
- TemplateDeductionInfo Info(Context);
+ TemplateDeductionInfo Info(Context, PointOfInstantiation);
if (TemplateDeductionResult Result
= DeduceTemplateArguments(&*Partial,
ClassTemplateSpec->getTemplateArgs(),
@@ -1154,7 +1230,8 @@ Sema::InstantiateClassTemplateSpecialization(
for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
PEnd = Matched.end();
P != PEnd; ++P) {
- if (getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ if (getMoreSpecializedPartialSpecialization(P->first, Best->first,
+ PointOfInstantiation)
== P->first)
Best = P;
}
@@ -1166,7 +1243,8 @@ Sema::InstantiateClassTemplateSpecialization(
PEnd = Matched.end();
P != PEnd; ++P) {
if (P != Best &&
- getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ getMoreSpecializedPartialSpecialization(P->first, Best->first,
+ PointOfInstantiation)
!= Best->first) {
Ambiguous = true;
break;
@@ -1327,8 +1405,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
assert(Pattern && "Missing instantiated-from-template information");
- if (!Record->getDefinition(Context)) {
- if (!Pattern->getDefinition(Context)) {
+ if (!Record->getDefinition()) {
+ if (!Pattern->getDefinition()) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
@@ -1348,7 +1426,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
TSK);
}
- Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
+ Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition());
if (Pattern)
InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs,
TSK);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 23a9430d746f..0b0efcb83327 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -43,6 +43,7 @@ namespace {
// clang/AST/DeclNodes.def.
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
+ Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
@@ -126,6 +127,21 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
return D;
}
+Decl *
+TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+ NamespaceAliasDecl *Inst
+ = NamespaceAliasDecl::Create(SemaRef.Context, Owner,
+ D->getNamespaceLoc(),
+ D->getAliasLoc(),
+ D->getNamespace()->getIdentifier(),
+ D->getQualifierRange(),
+ D->getQualifier(),
+ D->getTargetNameLoc(),
+ D->getNamespace());
+ Owner->addDecl(Inst);
+ return Inst;
+}
+
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
@@ -217,6 +233,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// FIXME: having to fake up a LookupResult is dumb.
LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(),
Sema::LookupOrdinaryName);
+ if (D->isStaticDataMember())
+ SemaRef.LookupQualifiedName(Previous, Owner, false);
SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration);
if (D->isOutOfLine()) {
@@ -232,7 +250,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
TSK_ImplicitInstantiation);
- if (D->getInit()) {
+ if (Var->getAnyInitializer()) {
+ // We already have an initializer in the class.
+ } else if (D->getInit()) {
if (Var->isStaticDataMember() && !D->isOutOfLine())
SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated);
else
@@ -241,6 +261,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Extract the initializer, skipping through any temporary-binding
// expressions and look at the subexpression as it was written.
Expr *DInit = D->getInit();
+ if (CXXExprWithTemporaries *ExprTemp
+ = dyn_cast<CXXExprWithTemporaries>(DInit))
+ DInit = ExprTemp->getSubExpr();
while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit))
DInit = Binder->getSubExpr();
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit))
@@ -408,9 +431,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
Decl *NewND;
// Hack to make this work almost well pending a rewrite.
- if (ND->getDeclContext()->isRecord())
- NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs);
- else if (D->wasSpecialization()) {
+ if (ND->getDeclContext()->isRecord()) {
+ if (!ND->getDeclContext()->isDependentContext()) {
+ NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs);
+ } else {
+ // FIXME: Hack to avoid crashing when incorrectly trying to instantiate
+ // templated friend declarations. This doesn't produce a correct AST;
+ // however this is sufficient for some AST analysis. The real solution
+ // must be put in place during the pending rewrite. See PR5848.
+ return 0;
+ }
+ } else if (D->wasSpecialization()) {
// Totally egregious hack to work around PR5866
return 0;
} else
@@ -493,6 +524,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
}
if (EnumConst) {
+ EnumConst->setAccess(Enum->getAccess());
Enum->addDecl(EnumConst);
Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst));
LastEnumConst = EnumConst;
@@ -734,9 +766,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (T.isNull())
return 0;
- // Build the instantiated method declaration.
- DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(),
- TemplateArgs);
+ // If we're instantiating a local function declaration, put the result
+ // in the owner; otherwise we need to find the instantiated context.
+ DeclContext *DC;
+ if (D->getDeclContext()->isFunctionOrMethod())
+ DC = Owner;
+ else
+ DC = SemaRef.FindInstantiatedContext(D->getDeclContext(), TemplateArgs);
+
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getDeclName(), T, D->getTypeSourceInfo(),
@@ -747,7 +784,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
- Function->setParams(SemaRef.Context, Params.data(), Params.size());
+ Function->setParams(Params.data(), Params.size());
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
@@ -772,8 +809,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
} else if (FunctionTemplate) {
// Record this function template specialization.
- Function->setFunctionTemplateSpecialization(SemaRef.Context,
- FunctionTemplate,
+ Function->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
}
@@ -926,8 +962,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (FunctionTemplate) {
// Record this function template specialization.
- Method->setFunctionTemplateSpecialization(SemaRef.Context,
- FunctionTemplate,
+ Method->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
} else {
@@ -944,7 +979,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Method);
- Method->setParams(SemaRef.Context, Params.data(), Params.size());
+ Method->setParams(Params.data(), Params.size());
if (InitMethodInstantiation(Method, D))
Method->setInvalidDecl();
@@ -1804,7 +1839,6 @@ void Sema::InstantiateStaticDataMemberDefinition(
CurContext = PreviousContext;
if (Var) {
- Var->setPreviousDeclaration(OldVar);
MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
assert(MSInfo && "Missing member specialization information?");
Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(),
@@ -1829,7 +1863,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
const MultiLevelTemplateArgumentList &TemplateArgs) {
llvm::SmallVector<MemInitTy*, 4> NewInits;
-
+ bool AnyErrors = false;
+
// Instantiate all the initializers.
for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
InitsEnd = Tmpl->init_end();
@@ -1837,26 +1872,38 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
CXXBaseOrMemberInitializer *Init = *Inits;
ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this);
+ llvm::SmallVector<SourceLocation, 4> CommaLocs;
// Instantiate all the arguments.
- for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end();
- Args != ArgsEnd; ++Args) {
- OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs);
-
- if (NewArg.isInvalid())
- New->setInvalidDecl();
- else
- NewArgs.push_back(NewArg.takeAs<Expr>());
+ Expr *InitE = Init->getInit();
+ if (!InitE) {
+ // Nothing to instantiate;
+ } else if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(InitE)) {
+ if (InstantiateInitializationArguments(*this, ParenList->getExprs(),
+ ParenList->getNumExprs(),
+ TemplateArgs, CommaLocs,
+ NewArgs)) {
+ AnyErrors = true;
+ continue;
+ }
+ } else {
+ OwningExprResult InitArg = SubstExpr(InitE, TemplateArgs);
+ if (InitArg.isInvalid()) {
+ AnyErrors = true;
+ continue;
+ }
+
+ NewArgs.push_back(InitArg.release());
}
-
+
MemInitResult NewInit;
-
if (Init->isBaseInitializer()) {
TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!BaseTInfo) {
+ AnyErrors = true;
New->setInvalidDecl();
continue;
}
@@ -1884,9 +1931,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
Init->getRParenLoc());
}
- if (NewInit.isInvalid())
+ if (NewInit.isInvalid()) {
+ AnyErrors = true;
New->setInvalidDecl();
- else {
+ } else {
// FIXME: It would be nice if ASTOwningVector had a release function.
NewArgs.take();
@@ -1898,7 +1946,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
ActOnMemInitializers(DeclPtrTy::make(New),
/*FIXME: ColonLoc */
SourceLocation(),
- NewInits.data(), NewInits.size());
+ NewInits.data(), NewInits.size(),
+ AnyErrors);
}
// TODO: this could be templated if the various decl types used the
@@ -2140,7 +2189,7 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
- isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
+ isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
ParentDC->isFunctionOrMethod()) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
@@ -2151,10 +2200,11 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
if (!Record->isDependentContext())
return D;
- // If the RecordDecl is actually the injected-class-name or a "templated"
- // declaration for a class template or class template partial
- // specialization, substitute into the injected-class-name of the
- // class template or partial specialization to find the new DeclContext.
+ // If the RecordDecl is actually the injected-class-name or a
+ // "templated" declaration for a class template, class template
+ // partial specialization, or a member class of a class template,
+ // substitute into the injected-class-name of the class template
+ // or partial specialization to find the new DeclContext.
QualType T;
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
@@ -2164,15 +2214,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
T = Context.getTypeDeclType(Record);
ClassTemplate = PartialSpec->getSpecializedTemplate();
- }
+ }
if (!T.isNull()) {
- // Substitute into the injected-class-name to get the type corresponding
- // to the instantiation we want. This substitution should never fail,
- // since we know we can instantiate the injected-class-name or we wouldn't
- // have gotten to the injected-class-name!
- // FIXME: Can we use the CurrentInstantiationScope to avoid this extra
- // instantiation in the common case?
+ // Substitute into the injected-class-name to get the type
+ // corresponding to the instantiation we want, which may also be
+ // the current instantiation (if we're in a template
+ // definition). This substitution should never fail, since we
+ // know we can instantiate the injected-class-name or we
+ // wouldn't have gotten to the injected-class-name!
+
+ // FIXME: Can we use the CurrentInstantiationScope to avoid this
+ // extra instantiation in the common case?
T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
@@ -2181,26 +2234,37 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
return T->getAs<RecordType>()->getDecl();
}
- // We are performing "partial" template instantiation to create the
- // member declarations for the members of a class template
- // specialization. Therefore, D is actually referring to something in
- // the current instantiation. Look through the current context,
- // which contains actual instantiations, to find the instantiation of
- // the "current instantiation" that D refers to.
+ // We are performing "partial" template instantiation to create
+ // the member declarations for the members of a class template
+ // specialization. Therefore, D is actually referring to something
+ // in the current instantiation. Look through the current
+ // context, which contains actual instantiations, to find the
+ // instantiation of the "current instantiation" that D refers
+ // to.
+ bool SawNonDependentContext = false;
for (DeclContext *DC = CurContext; !DC->isFileContext();
DC = DC->getParent()) {
if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(DC))
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC))
if (isInstantiationOf(ClassTemplate,
Spec->getSpecializedTemplate()))
return Spec;
+
+ if (!DC->isDependentContext())
+ SawNonDependentContext = true;
}
- assert(false &&
+ // We're performing "instantiation" of a member of the current
+ // instantiation while we are type-checking the
+ // definition. Compute the declaration context and return that.
+ assert(!SawNonDependentContext &&
+ "No dependent context while instantiating record");
+ DeclContext *DC = computeDeclContext(T);
+ assert(DC &&
"Unable to find declaration for the current instantiation");
- return Record;
+ return cast<CXXRecordDecl>(DC);
}
-
+
// Fall through to deal with other dependent record types (e.g.,
// anonymous unions in class templates).
}
@@ -2275,6 +2339,24 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
VarDecl *Var = cast<VarDecl>(Inst.first);
assert(Var->isStaticDataMember() && "Not a static data member?");
+ // Don't try to instantiate declarations if the most recent redeclaration
+ // is invalid.
+ if (Var->getMostRecentDeclaration()->isInvalidDecl())
+ continue;
+
+ // Check if the most recent declaration has changed the specialization kind
+ // and removed the need for implicit instantiation.
+ switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ assert(false && "Cannot instantitiate an undeclared specialization.");
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ case TSK_ExplicitSpecialization:
+ continue; // No longer need implicit instantiation.
+ case TSK_ImplicitInstantiation:
+ break;
+ }
+
PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Var),
Var->getLocation(), *this,
Context.getSourceManager(),
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 906576115a56..7911e76d446a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -68,12 +68,41 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
return false;
}
+typedef std::pair<const AttributeList*,QualType> DelayedAttribute;
+typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet;
+
+static void ProcessTypeAttributeList(Sema &S, QualType &Type,
+ const AttributeList *Attrs,
+ DelayedAttributeSet &DelayedFnAttrs);
+static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr);
+
+static void ProcessDelayedFnAttrs(Sema &S, QualType &Type,
+ DelayedAttributeSet &Attrs) {
+ for (DelayedAttributeSet::iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I)
+ if (ProcessFnAttr(S, Type, *I->first))
+ S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
+ << I->first->getName() << I->second;
+ Attrs.clear();
+}
+
+static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) {
+ for (DelayedAttributeSet::iterator I = Attrs.begin(),
+ E = Attrs.end(); I != E; ++I) {
+ S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
+ << I->first->getName() << I->second;
+ }
+ Attrs.clear();
+}
+
/// \brief Convert the specified declspec to the appropriate type
/// object.
/// \param D the declarator containing the declaration specifier.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
-static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
+static QualType ConvertDeclSpecToType(Sema &TheSema,
+ Declarator &TheDeclarator,
+ DelayedAttributeSet &Delayed) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
const DeclSpec &DS = TheDeclarator.getDeclSpec();
@@ -343,6 +372,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
if (TheSema.getLangOptions().Freestanding)
TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex);
Result = Context.getComplexType(Result);
+ } else if (DS.isTypeAltiVecVector()) {
+ unsigned typeSize = static_cast<unsigned>(Context.getTypeSize(Result));
+ assert(typeSize > 0 && "type size for vector must be greater than 0 bits");
+ Result = Context.getVectorType(Result, 128/typeSize, true,
+ DS.isTypeAltiVecPixel());
}
assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary &&
@@ -351,7 +385,7 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
// See if there are any attributes on the declspec that apply to the type (as
// opposed to the decl).
if (const AttributeList *AL = DS.getAttributes())
- TheSema.ProcessTypeAttributeList(Result, AL);
+ ProcessTypeAttributeList(TheSema, Result, AL, Delayed);
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -885,15 +919,23 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// have a type.
QualType T;
+ llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec;
+
switch (D.getName().getKind()) {
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId:
- T = ConvertDeclSpecToType(D, *this);
+ T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec);
- if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned())
- *OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
+ if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) {
+ TagDecl* Owned = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
+ // 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());
+ if (OwnedDecl) *OwnedDecl = Owned;
+ }
break;
case UnqualifiedId::IK_ConstructorName:
@@ -962,6 +1004,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getIdentifier())
Name = D.getIdentifier();
+ llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk;
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -1181,6 +1225,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data());
}
+
+ // For GCC compatibility, we allow attributes that apply only to
+ // function types to be placed on a function's return type
+ // instead (as long as that type doesn't happen to be function
+ // or function-pointer itself).
+ ProcessDelayedFnAttrs(*this, T, FnAttrsFromPreviousChunk);
+
break;
}
case DeclaratorChunk::MemberPointer:
@@ -1239,9 +1290,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
T = Context.IntTy;
}
+ DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
+
// See if there are any attributes on this declarator chunk.
if (const AttributeList *AL = DeclType.getAttrs())
- ProcessTypeAttributeList(T, AL);
+ ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk);
}
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
@@ -1271,10 +1324,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
}
- // If there were any type attributes applied to the decl itself (not the
- // type, apply the type attribute to the type!)
- if (const AttributeList *Attrs = D.getAttributes())
- ProcessTypeAttributeList(T, Attrs);
+ // Process any function attributes we might have delayed from the
+ // declaration-specifiers.
+ ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec);
+
+ // If there were any type attributes applied to the decl itself, not
+ // the type, apply them to the result type. But don't do this for
+ // block-literal expressions, which are parsed wierdly.
+ if (D.getContext() != Declarator::BlockLiteralContext)
+ if (const AttributeList *Attrs = D.getAttributes())
+ ProcessTypeAttributeList(*this, T, Attrs, FnAttrsFromPreviousChunk);
+
+ DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
if (TInfo) {
if (D.isInvalidType())
@@ -1645,20 +1706,79 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
Type = S.Context.getObjCGCQualType(Type, GCAttr);
}
-/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the
-/// specified type. The attribute contains 0 arguments.
-static void HandleNoReturnTypeAttribute(QualType &Type,
- const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0)
- return;
+/// Process an individual function attribute. Returns true if the
+/// attribute does not make sense to apply to this type.
+bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
+ if (Attr.getKind() == AttributeList::AT_noreturn) {
+ // Complain immediately if the arg count is wrong.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return false;
+ }
- // We only apply this to a pointer to function or a pointer to block.
- if (!Type->isFunctionPointerType()
- && !Type->isBlockPointerType()
- && !Type->isFunctionType())
- return;
+ // Delay if this is not a function or pointer to block.
+ if (!Type->isFunctionPointerType()
+ && !Type->isBlockPointerType()
+ && !Type->isFunctionType())
+ return true;
- Type = S.Context.getNoReturnType(Type);
+ // Otherwise we can process right away.
+ Type = S.Context.getNoReturnType(Type);
+ return false;
+ }
+
+ // Otherwise, a calling convention.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return false;
+ }
+
+ QualType T = Type;
+ if (const PointerType *PT = Type->getAs<PointerType>())
+ T = PT->getPointeeType();
+ const FunctionType *Fn = T->getAs<FunctionType>();
+
+ // Delay if the type didn't work out to a function.
+ if (!Fn) return true;
+
+ // TODO: diagnose uses of these conventions on the wrong target.
+ CallingConv CC;
+ 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;
+ default: llvm_unreachable("unexpected attribute kind"); return false;
+ }
+
+ CallingConv CCOld = Fn->getCallConv();
+ if (CC == CCOld) return false;
+
+ if (CCOld != CC_Default) {
+ // Should we diagnose reapplications of the same convention?
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << FunctionType::getNameForCallConv(CC)
+ << FunctionType::getNameForCallConv(CCOld);
+ return false;
+ }
+
+ // Diagnose the use of X86 fastcall on varargs or unprototyped functions.
+ if (CC == CC_X86FastCall) {
+ if (isa<FunctionNoProtoType>(Fn)) {
+ S.Diag(Attr.getLoc(), diag::err_cconv_knr)
+ << FunctionType::getNameForCallConv(CC);
+ return false;
+ }
+
+ const FunctionProtoType *FnP = cast<FunctionProtoType>(Fn);
+ if (FnP->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::err_cconv_varargs)
+ << FunctionType::getNameForCallConv(CC);
+ return false;
+ }
+ }
+
+ Type = S.Context.getCallConvType(Type, CC);
+ return false;
}
/// HandleVectorSizeAttribute - this attribute is only applicable to integral
@@ -1705,10 +1825,12 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
// Success! Instantiate the vector type, the number of elements is > 0, and
// not required to be a power of 2, unlike GCC.
- CurType = S.Context.getVectorType(CurType, vectorSize/typeSize);
+ CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, false, false);
}
-void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
+void ProcessTypeAttributeList(Sema &S, QualType &Result,
+ const AttributeList *AL,
+ DelayedAttributeSet &FnAttrs) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
// type, but others can be present in the type specifiers even though they
@@ -1718,17 +1840,23 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) {
// the LeftOverAttrs list for rechaining.
switch (AL->getKind()) {
default: break;
+
case AttributeList::AT_address_space:
- HandleAddressSpaceTypeAttribute(Result, *AL, *this);
+ HandleAddressSpaceTypeAttribute(Result, *AL, S);
break;
case AttributeList::AT_objc_gc:
- HandleObjCGCTypeAttribute(Result, *AL, *this);
- break;
- case AttributeList::AT_noreturn:
- HandleNoReturnTypeAttribute(Result, *AL, *this);
+ HandleObjCGCTypeAttribute(Result, *AL, S);
break;
case AttributeList::AT_vector_size:
- HandleVectorSizeAttr(Result, *AL, *this);
+ HandleVectorSizeAttr(Result, *AL, S);
+ break;
+
+ case AttributeList::AT_noreturn:
+ case AttributeList::AT_cdecl:
+ case AttributeList::AT_fastcall:
+ case AttributeList::AT_stdcall:
+ if (ProcessFnAttr(S, Result, *AL))
+ FnAttrs.push_back(DelayedAttribute(AL, Result));
break;
}
}
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index 7c19bf6e4fd4..d45d0106ffe6 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -70,6 +70,48 @@ namespace {
};
}
+static void HandleX86ForceAlignArgPointerAttr(Decl *D,
+ const AttributeList& Attr,
+ Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // If we try to apply it to a function pointer, warn. This is a special
+ // instance of the warn_attribute_ignored warning that can be turned
+ // off with -Wno-force-align-arg-pointer.
+ ValueDecl* VD = dyn_cast<ValueDecl>(D);
+ if (VD && VD->getType()->isFunctionPointerType()) {
+ S.Diag(Attr.getLoc(), diag::warn_faap_attribute_ignored);
+ return;
+ }
+ // Attribute can only be applied to function types.
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << /* function */0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr());
+}
+
+namespace {
+ class X86AttributesSema : public TargetAttributesSema {
+ public:
+ X86AttributesSema() { }
+ bool ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const {
+ if (Attr.getName()->getName() == "force_align_arg_pointer") {
+ HandleX86ForceAlignArgPointerAttr(D, Attr, S);
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
const TargetAttributesSema &Sema::getTargetAttributesSema() const {
if (TheTargetAttributesSema)
return *TheTargetAttributesSema;
@@ -81,6 +123,8 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const {
case llvm::Triple::msp430:
return *(TheTargetAttributesSema = new MSP430AttributesSema);
+ case llvm::Triple::x86:
+ return *(TheTargetAttributesSema = new X86AttributesSema);
}
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index b2102afdfc42..fc069f7ba38a 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -428,7 +428,8 @@ public:
///
/// By default, performs semantic analysis when building the vector type.
/// Subclasses may override this routine to provide different behavior.
- QualType RebuildVectorType(QualType ElementType, unsigned NumElements);
+ QualType RebuildVectorType(QualType ElementType, unsigned NumElements,
+ bool IsAltiVec, bool IsPixel);
/// \brief Build a new extended vector type given the element type and
/// number of elements.
@@ -524,9 +525,13 @@ public:
/// and the given type. Subclasses may override this routine to provide
/// different behavior.
QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) {
- if (NNS->isDependent())
- return SemaRef.Context.getTypenameType(NNS,
+ if (NNS->isDependent()) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+ if (!SemaRef.computeDeclContext(SS))
+ return SemaRef.Context.getTypenameType(NNS,
cast<TemplateSpecializationType>(T));
+ }
return SemaRef.Context.getQualifiedNameType(NNS, T);
}
@@ -776,6 +781,28 @@ public:
StartLoc, EndLoc));
}
+ /// \brief Build a new inline asm statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ IdentifierInfo **Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc,
+ bool MSAsm) {
+ return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, move(Constraints),
+ move(Exprs), move(AsmString), move(Clobbers),
+ RParenLoc, MSAsm);
+ }
+
/// \brief Build a new C++ exception declaration.
///
/// By default, performs semantic analysis to build the new decaration.
@@ -1662,6 +1689,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
// Transform expressions by calling TransformExpr.
#define STMT(Node, Parent)
+#define ABSTRACT_EXPR(Node, Parent)
#define EXPR(Node, Parent) case Stmt::Node##Class:
#include "clang/AST/StmtNodes.def"
{
@@ -1685,6 +1713,7 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
switch (E->getStmtClass()) {
case Stmt::NoStmtClass: break;
#define STMT(Node, Parent) case Stmt::Node##Class: break;
+#define ABSTRACT_EXPR(Node, Parent)
#define EXPR(Node, Parent) \
case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E));
#include "clang/AST/StmtNodes.def"
@@ -2448,7 +2477,8 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
ElementType != T->getElementType()) {
- Result = getDerived().RebuildVectorType(ElementType, T->getNumElements());
+ Result = getDerived().RebuildVectorType(ElementType, T->getNumElements(),
+ T->isAltiVec(), T->isPixel());
if (Result.isNull())
return QualType();
}
@@ -3327,9 +3357,74 @@ TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) {
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
- // FIXME: Implement!
- assert(false && "Inline assembly cannot be transformed");
- return SemaRef.Owned(S->Retain());
+
+ ASTOwningVector<&ActionBase::DeleteExpr> Constraints(getSema());
+ ASTOwningVector<&ActionBase::DeleteExpr> Exprs(getSema());
+ llvm::SmallVector<IdentifierInfo *, 4> Names;
+
+ OwningExprResult AsmString(SemaRef);
+ ASTOwningVector<&ActionBase::DeleteExpr> Clobbers(getSema());
+
+ bool ExprsChanged = false;
+
+ // Go through the outputs.
+ for (unsigned I = 0, E = S->getNumOutputs(); I != E; ++I) {
+ Names.push_back(S->getOutputIdentifier(I));
+
+ // No need to transform the constraint literal.
+ Constraints.push_back(S->getOutputConstraintLiteral(I)->Retain());
+
+ // Transform the output expr.
+ Expr *OutputExpr = S->getOutputExpr(I);
+ OwningExprResult Result = getDerived().TransformExpr(OutputExpr);
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+
+ ExprsChanged |= Result.get() != OutputExpr;
+
+ Exprs.push_back(Result.takeAs<Expr>());
+ }
+
+ // Go through the inputs.
+ for (unsigned I = 0, E = S->getNumInputs(); I != E; ++I) {
+ Names.push_back(S->getInputIdentifier(I));
+
+ // No need to transform the constraint literal.
+ Constraints.push_back(S->getInputConstraintLiteral(I)->Retain());
+
+ // Transform the input expr.
+ Expr *InputExpr = S->getInputExpr(I);
+ OwningExprResult Result = getDerived().TransformExpr(InputExpr);
+ if (Result.isInvalid())
+ return SemaRef.StmtError();
+
+ ExprsChanged |= Result.get() != InputExpr;
+
+ Exprs.push_back(Result.takeAs<Expr>());
+ }
+
+ if (!getDerived().AlwaysRebuild() && !ExprsChanged)
+ return SemaRef.Owned(S->Retain());
+
+ // Go through the clobbers.
+ for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I)
+ Clobbers.push_back(S->getClobber(I)->Retain());
+
+ // No need to transform the asm string literal.
+ AsmString = SemaRef.Owned(S->getAsmString());
+
+ return getDerived().RebuildAsmStmt(S->getAsmLoc(),
+ S->isSimple(),
+ S->isVolatile(),
+ S->getNumOutputs(),
+ S->getNumInputs(),
+ Names.data(),
+ move_arg(Constraints),
+ move_arg(Exprs),
+ move(AsmString),
+ move_arg(Clobbers),
+ S->getRParenLoc(),
+ S->isMSAsm());
}
@@ -3742,13 +3837,6 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCastExpr(CastExpr *E) {
- assert(false && "Cannot transform abstract class");
- return SemaRef.Owned(E->Retain());
-}
-
-template<typename Derived>
-Sema::OwningExprResult
TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
OwningExprResult LHS = getDerived().TransformExpr(E->getLHS());
if (LHS.isInvalid())
@@ -3812,13 +3900,6 @@ TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
- assert(false && "Cannot transform abstract class");
- return SemaRef.Owned(E->Retain());
-}
-
-template<typename Derived>
-Sema::OwningExprResult
TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
TypeSourceInfo *OldT;
TypeSourceInfo *NewT;
@@ -4433,7 +4514,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!Param)
return SemaRef.ExprError();
- if (getDerived().AlwaysRebuild() &&
+ if (!getDerived().AlwaysRebuild() &&
Param == E->getParam())
return SemaRef.Owned(E->Retain());
@@ -4733,6 +4814,12 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
+ // CXXConstructExprs are always implicit, so when we have a
+ // 1-argument construction we just transform that argument.
+ if (E->getNumArgs() == 1 ||
+ (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1))))
+ return getDerived().TransformExpr(E->getArg(0));
+
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
QualType T = getDerived().TransformType(E->getType());
@@ -4784,6 +4871,16 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
return getDerived().TransformExpr(E->getSubExpr());
}
+/// \brief Transform a C++ reference-binding expression.
+///
+/// Since CXXBindReferenceExpr nodes are implicitly generated, we just
+/// transform the subexpression and return that.
+template<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXBindReferenceExpr(CXXBindReferenceExpr *E) {
+ return getDerived().TransformExpr(E->getSubExpr());
+}
+
/// \brief Transform a C++ expression that contains temporaries that should
/// be destroyed after the expression is evaluated.
///
@@ -5330,9 +5427,11 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
template<typename Derived>
QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
- unsigned NumElements) {
+ unsigned NumElements,
+ bool IsAltiVec, bool IsPixel) {
// FIXME: semantic checking!
- return SemaRef.Context.getVectorType(ElementType, NumElements);
+ return SemaRef.Context.getVectorType(ElementType, NumElements,
+ IsAltiVec, IsPixel);
}
template<typename Derived>
@@ -5563,28 +5662,21 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Compute the transformed set of functions (and function templates) to be
// used during overload resolution.
- Sema::FunctionSet Functions;
+ UnresolvedSet<16> Functions;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) {
assert(ULE->requiresADL());
// FIXME: Do we have to check
// IsAcceptableNonMemberOperatorCandidate for each of these?
- for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
- E = ULE->decls_end(); I != E; ++I)
- Functions.insert(AnyFunctionDecl::getFromNamedDecl(*I));
+ Functions.append(ULE->decls_begin(), ULE->decls_end());
} else {
- Functions.insert(AnyFunctionDecl::getFromNamedDecl(
- cast<DeclRefExpr>(CalleeExpr)->getDecl()));
+ Functions.addDecl(cast<DeclRefExpr>(CalleeExpr)->getDecl());
}
// Add any functions found via argument-dependent lookup.
Expr *Args[2] = { FirstExpr, SecondExpr };
unsigned NumArgs = 1 + (SecondExpr != 0);
- DeclarationName OpName
- = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
- SemaRef.ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs,
- Functions);
// Create the overloaded operator invocation for unary operators.
if (NumArgs == 1 || isPostIncDec) {
diff --git a/test/ASTMerge/Inputs/enum1.c b/test/ASTMerge/Inputs/enum1.c
new file mode 100644
index 000000000000..f2b9c5c98fde
--- /dev/null
+++ b/test/ASTMerge/Inputs/enum1.c
@@ -0,0 +1,42 @@
+// Matching
+enum E1 {
+ E1Enumerator1,
+ E1Enumerator2 = 3,
+ E1Enumerator3
+} x1;
+
+// Value mismatch
+enum E2 {
+ E2Enumerator1,
+ E2Enumerator2 = 3,
+ E2Enumerator3
+} x2;
+
+// Name mismatch
+enum E3 {
+ E3Enumerator1,
+ E3Enumerator2 = 3,
+ E3Enumerator3
+} x3;
+
+// Missing enumerator
+enum E4 {
+ E4Enumerator1,
+ E4Enumerator2,
+ E4Enumerator3
+} x4;
+
+// Extra enumerator
+enum E5 {
+ E5Enumerator1,
+ E5Enumerator2,
+ E5Enumerator3
+} x5;
+
+// Matching, with typedef
+typedef enum {
+ E6Enumerator1,
+ E6Enumerator2
+} E6;
+
+E6 x6;
diff --git a/test/ASTMerge/Inputs/enum2.c b/test/ASTMerge/Inputs/enum2.c
new file mode 100644
index 000000000000..315b4dcb6ef5
--- /dev/null
+++ b/test/ASTMerge/Inputs/enum2.c
@@ -0,0 +1,42 @@
+// Matching
+enum E1 {
+ E1Enumerator1,
+ E1Enumerator2 = 3,
+ E1Enumerator3
+} x1;
+
+// Value mismatch
+enum E2 {
+ E2Enumerator1,
+ E2Enumerator2 = 4,
+ E2Enumerator3
+} x2;
+
+// Name mismatch
+enum E3 {
+ E3Enumerator1,
+ E3Enumerator = 3,
+ E3Enumerator3
+} x3;
+
+// Missing enumerator
+enum E4 {
+ E4Enumerator1,
+ E4Enumerator2
+} x4;
+
+// Extra enumerator
+enum E5 {
+ E5Enumerator1,
+ E5Enumerator2,
+ E5Enumerator3,
+ E5Enumerator4
+} x5;
+
+// Matching, with typedef
+typedef enum {
+ E6Enumerator1,
+ E6Enumerator2
+} E6;
+
+E6 x6;
diff --git a/test/ASTMerge/Inputs/function1.c b/test/ASTMerge/Inputs/function1.c
new file mode 100644
index 000000000000..4523bd3d79bf
--- /dev/null
+++ b/test/ASTMerge/Inputs/function1.c
@@ -0,0 +1,6 @@
+void f0(int);
+void f1(int, float);
+void f2();
+void f3(void);
+void f4(int, int);
+int f5(int) __attribute__((const));
diff --git a/test/ASTMerge/Inputs/function2.c b/test/ASTMerge/Inputs/function2.c
new file mode 100644
index 000000000000..6ca810a6f20b
--- /dev/null
+++ b/test/ASTMerge/Inputs/function2.c
@@ -0,0 +1,7 @@
+typedef int Int;
+void f0(Int);
+void f1(Int, double);
+void f2(int, int);
+void f3(int);
+static void f4(float, float);
+int f5(int) __attribute__((const));
diff --git a/test/ASTMerge/Inputs/interface1.m b/test/ASTMerge/Inputs/interface1.m
new file mode 100644
index 000000000000..1aa1c3b89413
--- /dev/null
+++ b/test/ASTMerge/Inputs/interface1.m
@@ -0,0 +1,7 @@
+// Matches
+@interface I1
+@end
+
+// Matches
+@interface I2 : I1
+@end
diff --git a/test/ASTMerge/Inputs/interface2.m b/test/ASTMerge/Inputs/interface2.m
new file mode 100644
index 000000000000..1aa1c3b89413
--- /dev/null
+++ b/test/ASTMerge/Inputs/interface2.m
@@ -0,0 +1,7 @@
+// Matches
+@interface I1
+@end
+
+// Matches
+@interface I2 : I1
+@end
diff --git a/test/ASTMerge/Inputs/lit.local.cfg b/test/ASTMerge/Inputs/lit.local.cfg
new file mode 100644
index 000000000000..e6f55eef7af5
--- /dev/null
+++ b/test/ASTMerge/Inputs/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = []
diff --git a/test/ASTMerge/Inputs/struct1.c b/test/ASTMerge/Inputs/struct1.c
new file mode 100644
index 000000000000..af2af8abc42a
--- /dev/null
+++ b/test/ASTMerge/Inputs/struct1.c
@@ -0,0 +1,63 @@
+typedef int Int;
+typedef float Float;
+
+// Matches
+struct S0 {
+ Int field1;
+ Float field2;
+};
+
+struct S0 x0;
+
+// Mismatch in field type
+struct S1 {
+ Int field1;
+ int field2;
+};
+
+struct S1 x1;
+
+// Mismatch in tag kind.
+struct S2 { int i; float f; } x2;
+
+// Missing fields
+struct S3 { int i; float f; double d; } x3;
+
+// Extra fields
+struct S4 { int i; } x4;
+
+// Bit-field matches
+struct S5 { int i : 8; unsigned j : 8; } x5;
+
+// Bit-field mismatch
+struct S6 { int i : 8; unsigned j : 8; } x6;
+
+// Bit-field mismatch
+struct S7 { int i : 8; unsigned j : 8; } x7;
+
+// Incomplete type
+struct S8 *x8;
+
+// Incomplete type
+struct S9 { int i; float f; } *x9;
+
+// Incomplete type
+struct S10 *x10;
+
+// Matches
+struct ListNode {
+ int value;
+ struct ListNode *Next;
+} xList;
+
+// Mismatch due to struct used internally
+struct DeepError {
+ int value;
+ struct DeeperError { int i; int f; } *Deeper;
+} xDeep;
+
+// Matches
+struct {
+ Int i;
+ float f;
+} x11;
diff --git a/test/ASTMerge/Inputs/struct2.c b/test/ASTMerge/Inputs/struct2.c
new file mode 100644
index 000000000000..4b43df71d8d6
--- /dev/null
+++ b/test/ASTMerge/Inputs/struct2.c
@@ -0,0 +1,60 @@
+// Matches
+struct S0 {
+ int field1;
+ float field2;
+};
+
+struct S0 x0;
+
+// Mismatch in field type
+struct S1 {
+ int field1;
+ float field2;
+};
+
+struct S1 x1;
+
+// Mismatch in tag kind.
+union S2 { int i; float f; } x2;
+
+// Missing fields
+struct S3 { int i; float f; } x3;
+
+// Extra fields
+struct S4 { int i; float f; } x4;
+
+// Bit-field matches
+struct S5 { int i : 8; unsigned j : 8; } x5;
+
+// Bit-field mismatch
+struct S6 { int i : 8; unsigned j; } x6;
+
+// Bit-field mismatch
+struct S7 { int i : 8; unsigned j : 16; } x7;
+
+// Incomplete type
+struct S8 { int i; float f; } *x8;
+
+// Incomplete type
+struct S9 *x9;
+
+// Incomplete type
+struct S10 *x10;
+
+// Matches
+struct ListNode {
+ int value;
+ struct ListNode *Next;
+} xList;
+
+// Mismatch due to struct used internally
+struct DeepError {
+ int value;
+ struct DeeperError { int i; float f; } *Deeper;
+} xDeep;
+
+// Matches
+struct {
+ int i;
+ float f;
+} x11;
diff --git a/test/ASTMerge/Inputs/typedef1.c b/test/ASTMerge/Inputs/typedef1.c
new file mode 100644
index 000000000000..56576756856d
--- /dev/null
+++ b/test/ASTMerge/Inputs/typedef1.c
@@ -0,0 +1,4 @@
+typedef int Typedef1;
+typedef int Typedef2;
+Typedef1 x1;
+Typedef2 x2;
diff --git a/test/ASTMerge/Inputs/typedef2.c b/test/ASTMerge/Inputs/typedef2.c
new file mode 100644
index 000000000000..129d7101e91e
--- /dev/null
+++ b/test/ASTMerge/Inputs/typedef2.c
@@ -0,0 +1,4 @@
+typedef int Typedef1;
+typedef double Typedef2;
+Typedef1 x1;
+Typedef2 x2;
diff --git a/test/ASTMerge/Inputs/var1.c b/test/ASTMerge/Inputs/var1.c
new file mode 100644
index 000000000000..4f5cbe16ab6c
--- /dev/null
+++ b/test/ASTMerge/Inputs/var1.c
@@ -0,0 +1,7 @@
+int *x0;
+float **x1;
+#include "var1.h"
+int xarray0[17];
+int xarray1[];
+int xarray2[18];
+int xarray3[18];
diff --git a/test/ASTMerge/Inputs/var1.h b/test/ASTMerge/Inputs/var1.h
new file mode 100644
index 000000000000..1518e17ef0c8
--- /dev/null
+++ b/test/ASTMerge/Inputs/var1.h
@@ -0,0 +1 @@
+double x2;
diff --git a/test/ASTMerge/Inputs/var2.c b/test/ASTMerge/Inputs/var2.c
new file mode 100644
index 000000000000..01986e4208ca
--- /dev/null
+++ b/test/ASTMerge/Inputs/var2.c
@@ -0,0 +1,7 @@
+int *x0;
+double *x1;
+int x2;
+int xarray0[17];
+int xarray1[17];
+int xarray2[];
+int xarray3[17];
diff --git a/test/ASTMerge/enum.c b/test/ASTMerge/enum.c
new file mode 100644
index 000000000000..9b78fd1022e4
--- /dev/null
+++ b/test/ASTMerge/enum.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/enum1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/enum2.c
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: enum1.c:9:6: warning: type 'enum E2' has incompatible definitions in different translation units
+// CHECK: enum1.c:11:3: note: enumerator 'E2Enumerator2' with value 3 here
+// CHECK: enum2.c:11:3: note: enumerator 'E2Enumerator2' with value 4 here
+// CHECK: enum2.c:13:3: error: external variable 'x2' declared with incompatible types in different translation units ('enum E2' vs. 'enum E2')
+// CHECK: enum1.c:13:3: note: declared here with type 'enum E2'
+// CHECK: enum1.c:16:6: warning: type 'enum E3' has incompatible definitions in different translation units
+// CHECK: enum1.c:18:3: note: enumerator 'E3Enumerator2' with value 3 here
+// CHECK: enum2.c:18:3: note: enumerator 'E3Enumerator' with value 3 here
+// CHECK: enum2.c:20:3: error: external variable 'x3' declared with incompatible types in different translation units ('enum E3' vs. 'enum E3')
+// CHECK: enum1.c:20:3: note: declared here with type 'enum E3'
+// CHECK: enum1.c:23:6: warning: type 'enum E4' has incompatible definitions in different translation units
+// CHECK: enum1.c:26:3: note: enumerator 'E4Enumerator3' with value 2 here
+// CHECK: enum2.c:23:6: note: no corresponding enumerator here
+// CHECK: enum2.c:26:3: error: external variable 'x4' declared with incompatible types in different translation units ('enum E4' vs. 'enum E4')
+// CHECK: enum1.c:27:3: note: declared here with type 'enum E4'
+// CHECK: enum1.c:30:6: warning: type 'enum E5' has incompatible definitions in different translation units
+// CHECK: enum2.c:33:3: note: enumerator 'E5Enumerator4' with value 3 here
+// CHECK: enum1.c:30:6: note: no corresponding enumerator here
+// CHECK: enum2.c:34:3: error: external variable 'x5' declared with incompatible types in different translation units ('enum E5' vs. 'enum E5')
+// CHECK: enum1.c:34:3: note: declared here with type 'enum E5'
+// CHECK: 20 diagnostics generated
diff --git a/test/ASTMerge/function.c b/test/ASTMerge/function.c
new file mode 100644
index 000000000000..581b6ec5882c
--- /dev/null
+++ b/test/ASTMerge/function.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/function1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/function2.c
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: function2.c:3:6: error: external function 'f1' declared with incompatible types in different translation units ('void (Int, double)' vs. 'void (int, float)')
+// CHECK: function1.c:2:6: note: declared here with type 'void (int, float)'
+// CHECK: function2.c:5:6: error: external function 'f3' declared with incompatible types in different translation units ('void (int)' vs. 'void (void)')
+// CHECK: function1.c:4:6: note: declared here with type 'void (void)'
+// CHECK: 4 diagnostics generated
diff --git a/test/ASTMerge/interface.m b/test/ASTMerge/interface.m
new file mode 100644
index 000000000000..d6af2f4b1665
--- /dev/null
+++ b/test/ASTMerge/interface.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/interface1.m
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/interface2.m
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1
+
+// FIXME: FileCheck!
+
diff --git a/test/ASTMerge/struct.c b/test/ASTMerge/struct.c
new file mode 100644
index 000000000000..e72b93b249f9
--- /dev/null
+++ b/test/ASTMerge/struct.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/struct1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/struct2.c
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: struct1.c:13:8: warning: type 'struct S1' has incompatible definitions in different translation units
+// CHECK: struct1.c:15:7: note: field 'field2' has type 'int' here
+// CHECK: struct2.c:12:9: note: field 'field2' has type 'float' here
+// CHECK: struct2.c:15:11: error: external variable 'x1' declared with incompatible types in different translation units ('struct S1' vs. 'struct S1')
+// CHECK: struct1.c:18:11: note: declared here with type 'struct S1'
+// CHECK: struct1.c:21:8: warning: type 'struct S2' has incompatible definitions in different translation units
+// CHECK: struct2.c:18:7: note: 'S2' is a union here
+// CHECK: struct2.c:18:30: error: external variable 'x2' declared with incompatible types in different translation units ('union S2' vs. 'struct S2')
+// CHECK: struct1.c:21:31: note: declared here with type 'struct S2'
+// CHECK: struct1.c:24:8: warning: type 'struct S3' has incompatible definitions in different translation units
+// CHECK: struct1.c:24:36: note: field 'd' has type 'double' here
+// CHECK: struct2.c:21:8: note: no corresponding field here
+// CHECK: struct2.c:21:31: error: external variable 'x3' declared with incompatible types in different translation units ('struct S3' vs. 'struct S3')
+// CHECK: struct1.c:24:41: note: declared here with type 'struct S3'
+// CHECK: struct1.c:27:8: warning: type 'struct S4' has incompatible definitions in different translation units
+// CHECK: struct2.c:24:26: note: field 'f' has type 'float' here
+// CHECK: struct1.c:27:8: note: no corresponding field here
+// CHECK: struct2.c:24:31: error: external variable 'x4' declared with incompatible types in different translation units ('struct S4' vs. 'struct S4')
+// CHECK: struct1.c:27:22: note: declared here with type 'struct S4'
+// CHECK: struct1.c:33:8: warning: type 'struct S6' has incompatible definitions in different translation units
+// CHECK: struct1.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 8 here
+// CHECK: struct2.c:30:33: note: field 'j' is not a bit-field
+// CHECK: struct2.c:30:38: error: external variable 'x6' declared with incompatible types in different translation units ('struct S6' vs. 'struct S6')
+// CHECK: struct1.c:33:42: note: declared here with type 'struct S6'
+// CHECK: struct1.c:36:8: warning: type 'struct S7' has incompatible definitions in different translation units
+// CHECK: struct1.c:36:33: note: bit-field 'j' with type 'unsigned int' and length 8 here
+// CHECK: struct2.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 16 here
+// CHECK: struct2.c:33:43: error: external variable 'x7' declared with incompatible types in different translation units ('struct S7' vs. 'struct S7')
+// CHECK: struct1.c:36:42: note: declared here with type 'struct S7'
+// CHECK: struct1.c:56:10: warning: type 'struct DeeperError' has incompatible definitions in different translation units
+// CHECK: struct1.c:56:35: note: field 'f' has type 'int' here
+// CHECK: struct2.c:53:37: note: field 'f' has type 'float' here
+// CHECK: struct1.c:54:8: warning: type 'struct DeepError' has incompatible definitions in different translation units
+// CHECK: struct1.c:56:41: note: field 'Deeper' has type 'struct DeeperError *' here
+// CHECK: struct2.c:53:43: note: field 'Deeper' has type 'struct DeeperError *' here
+// CHECK: struct2.c:54:3: error: external variable 'xDeep' declared with incompatible types in different translation units ('struct DeepError' vs. 'struct DeepError')
+// CHECK: struct1.c:57:3: note: declared here with type 'struct DeepError'
+// CHECK: 37 diagnostics
diff --git a/test/ASTMerge/typedef.c b/test/ASTMerge/typedef.c
new file mode 100644
index 000000000000..4498864b4908
--- /dev/null
+++ b/test/ASTMerge/typedef.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/typedef1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/typedef2.c
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: typedef2.c:4:10: error: external variable 'x2' declared with incompatible types in different translation units ('Typedef2' (aka 'double') vs. 'Typedef2' (aka 'int'))
+// CHECK: typedef1.c:4:10: note: declared here with type 'Typedef2' (aka 'int')
+// CHECK: 2 diagnostics
diff --git a/test/ASTMerge/var.c b/test/ASTMerge/var.c
new file mode 100644
index 000000000000..fd307940aff7
--- /dev/null
+++ b/test/ASTMerge/var.c
@@ -0,0 +1,12 @@
+// 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
+
+// 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 **'
+// CHECK: var2.c:3:5: error: external variable 'x2' declared with incompatible types in different translation units ('int' vs. 'double')
+// CHECK: In file included from{{.*}}var1.c:3:
+// CHECK: var1.h:1:8: note: declared here with type 'double'
+// CHECK: error: external variable 'xarray3' declared with incompatible types in different translation units ('int [17]' vs. 'int [18]')
+// CHECK: var1.c:7:5: note: declared here with type 'int [18]'
+// CHECK: 6 diagnostics
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index 34bc3c0f199b..abcefdec58ed 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -disable-free %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc -disable-free %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 9e6f093c56bf..544644a747dc 100644
--- a/test/Analysis/CFNumber.c
+++ b/test/Analysis/CFNumber.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 e2d1c88b8f79..ce9e6ff1b60b 100644
--- a/test/Analysis/CFRetainRelease_NSAssertionHandler.m
+++ b/test/Analysis/CFRetainRelease_NSAssertionHandler.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=region
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=basic
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -verify %s -analyzer-constraints=range -analyzer-store=basic
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 7390b5a80117..737f1a32b500 100644
--- a/test/Analysis/CGColorSpace.c
+++ b/test/Analysis/CGColorSpace.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 e3b1be0a5bf4..6bf299d6bed5 100644
--- a/test/Analysis/CheckNSError.m
+++ b/test/Analysis/CheckNSError.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 daa6460da81b..bfd968a9a1a6 100644
--- a/test/Analysis/MissingDealloc.m
+++ b/test/Analysis/MissingDealloc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-missing-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 b2863e089a80..7ebe18ff0f2c 100644
--- a/test/Analysis/NSPanel.m
+++ b/test/Analysis/NSPanel.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 515b9f7f3de0..fa81b3d95da9 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,13 +1,13 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s &&
-// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
-// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
-// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
+// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s &&
+// NOTWORK: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s &&
+// NOTWORK: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
diff --git a/test/Analysis/NSWindow.m b/test/Analysis/NSWindow.m
index acd3278c474e..34e6c68b8501 100644
--- a/test/Analysis/NSWindow.m
+++ b/test/Analysis/NSWindow.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -warn-dead-stores -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-check-dead-stores -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-check-dead-stores -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-check-dead-stores -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-check-dead-stores -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 9d3de0f89a43..a02c93cfd350 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
#include <stdarg.h>
diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m
index 1749d71f359d..72f3d3894d8a 100644
--- a/test/Analysis/ObjCProperties.m
+++ b/test/Analysis/ObjCProperties.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 cdc81993b81f..a76d7b979ee0 100644
--- a/test/Analysis/ObjCRetSigs.m
+++ b/test/Analysis/ObjCRetSigs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-objc-methodsigs -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-methodsigs -verify %s
int printf(const char *, ...);
diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m
index d26096129e33..68c8c0622612 100644
--- a/test/Analysis/PR2599.m
+++ b/test/Analysis/PR2599.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -checker-cfref -fobjc-gc -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=region -checker-cfref -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -analyzer-check-objc-mem -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=basic -analyzer-check-objc-mem -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=basic -analyzer-store=basic -analyzer-check-objc-mem -fobjc-gc -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-constraints=range -analyzer-store=region -analyzer-check-objc-mem -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 a70e34ac7800..1ed138e45d13 100644
--- a/test/Analysis/PR2978.m
+++ b/test/Analysis/PR2978.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-missing-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 38566d5f6c18..3fed57e11285 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
//===----------------------------------------------------------------------===//
// Delta-debugging produced forward declarations.
diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c
index 0354c06c7810..3e46a0a62235 100644
--- a/test/Analysis/array-struct.c
+++ b/test/Analysis/array-struct.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
struct s {
int data;
diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m
index ef43751ce1b8..e8e96a22cf9e 100644
--- a/test/Analysis/blocks.m
+++ b/test/Analysis/blocks.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem -analyzer-store=region -fblocks -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
@@ -67,3 +67,19 @@ void test1(NSString *format, ...) {
__builtin_va_end(args);
}
+
+// test2 - Test that captured variables that are uninitialized are flagged
+// as such.
+void test2() {
+ static int y = 0;
+ int x;
+ ^{ y = x + 1; }(); // expected-warning{{Variable 'x' is captured by block with a garbage value}}
+}
+
+void test2_b() {
+ static int y = 0;
+ __block int x;
+ // This is also a bug, but should be found not by checking the value
+ // 'x' is bound at block creation.
+ ^{ y = x + 1; }(); // no-warning
+}
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index ef398bb173be..1cb88e611224 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-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 790f63f244db..c99b4d6c4db0 100644
--- a/test/Analysis/casts.m
+++ b/test/Analysis/casts.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 c673736dcd78..ebf35443c29d 100644
--- a/test/Analysis/cfref_PR2519.c
+++ b/test/Analysis/cfref_PR2519.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 f3027336c4b2..12b08198242e 100644
--- a/test/Analysis/cfref_rdar6080742.c
+++ b/test/Analysis/cfref_rdar6080742.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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/complex.c b/test/Analysis/complex.c
index 2b4f2c41179b..bb2b2fe7292e 100644
--- a/test/Analysis/complex.c
+++ b/test/Analysis/complex.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -Wno-unreachable-code %s
#include <stdint.h>
diff --git a/test/Analysis/concrete-address.c b/test/Analysis/concrete-address.c
index 443e36485307..07ca7136e2f3 100644
--- a/test/Analysis/concrete-address.c
+++ b/test/Analysis/concrete-address.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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
index 7db928438697..86882a5ac4b6 100644
--- a/test/Analysis/conditional-op-missing-lhs.c
+++ b/test/Analysis/conditional-op-missing-lhs.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -warn-uninit-values -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -warn-uninit-values -verify %s
void f1()
{
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 91f2b2afebd2..a00217442053 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-check-dead-stores -fblocks -verify -Wno-unreachable-code %s
void f1() {
int k, y;
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
index 9778a11c921a..22d446e17021 100644
--- a/test/Analysis/dead-stores.cpp
+++ b/test/Analysis/dead-stores.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -analyzer-check-dead-stores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -analyzer-check-dead-stores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -analyzer-check-dead-stores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-check-dead-stores -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 d4a20a81fba6..765a24a3c355 100644
--- a/test/Analysis/dead-stores.m
+++ b/test/Analysis/dead-stores.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -verify %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/delegates.m b/test/Analysis/delegates.m
index 876e3a060686..18b42417eb97 100644
--- a/test/Analysis/delegates.m
+++ b/test/Analysis/delegates.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify %s
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/elementtype.c b/test/Analysis/elementtype.c
index 4f79a31912a1..08ffe32d3c88 100644
--- a/test/Analysis/elementtype.c
+++ b/test/Analysis/elementtype.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 27094c8576c5..0a95b7055601 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 2a71114e39d4..c97d4f82cdc0 100644
--- a/test/Analysis/fields.c
+++ b/test/Analysis/fields.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem %s -analyzer-store=basic -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem %s -analyzer-store=region -verify
unsigned foo();
typedef struct bf { unsigned x:2; } bf;
diff --git a/test/Analysis/func.c b/test/Analysis/func.c
index 8a951f8dcb5e..53c873df55a9 100644
--- a/test/Analysis/func.c
+++ b/test/Analysis/func.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify %s
void f(void) {
void (*p)(void);
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 7d2b71877b91..3cce1b0d2ef4 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-experimental-checks -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-experimental-checks -analyzer-store=region -verify %s
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
@@ -57,3 +57,7 @@ void pr6069() {
char *buf = doit2();
free(buf);
}
+
+void pr6293() {
+ free(0);
+}
diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m
index 3f8836bfca4f..0dbd6cb948b3 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-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 2ae09ad38a59..4f8e4f656f08 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-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 c23efab416e9..a986b8eca62a 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-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
// Delta-reduced header stuff (needed for test cases).
typedef signed char BOOL;
diff --git a/test/Analysis/misc-ps-flat-store.c b/test/Analysis/misc-ps-flat-store.c
new file mode 100644
index 000000000000..8cbcecf51ff0
--- /dev/null
+++ b/test/Analysis/misc-ps-flat-store.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=flat -verify %s
+
+void f1() {
+ int x;
+ int *p;
+ x = 1;
+ p = 0;
+ if (x != 1)
+ *p = 1; // no-warning
+}
diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m
index df7e97c46736..b1afc3d3a21c 100644
--- a/test/Analysis/misc-ps-ranges.m
+++ b/test/Analysis/misc-ps-ranges.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 bb98668bde73..026d4f5476f6 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-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 3f30327e1886..e3c6d47348e9 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-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 8b5813118787..6794d481d68b 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-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -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-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
// Test basic handling of references.
char &test1_aux();
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index a88c26c29ed7..201cbc9b350f 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-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -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-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
typedef struct objc_selector *SEL;
typedef signed char BOOL;
@@ -590,6 +590,55 @@ int blocks_2(int *p, int z) {
return z;
}
+// Test that the value of 'x' is considered invalidated after the block
+// is passed as an argument to the message expression.
+typedef void (^RDar7582031CB)(void);
+@interface RDar7582031
+- rdar7582031:RDar7582031CB;
+- rdar7582031_b:RDar7582031CB;
+@end
+
+// Test with one block.
+unsigned rdar7582031(RDar7582031 *o) {
+ __block unsigned x;
+ [o rdar7582031:^{ x = 1; }];
+ return x; // no-warning
+}
+
+// Test with two blocks.
+unsigned long rdar7582031_b(RDar7582031 *o) {
+ __block unsigned y;
+ __block unsigned long x;
+ [o rdar7582031:^{ y = 1; }];
+ [o rdar7582031_b:^{ x = 1LL; }];
+ return x + (unsigned long) y; // no-warning
+}
+
+// Show we get an error when 'o' is null because the message
+// expression has no effect.
+unsigned long rdar7582031_b2(RDar7582031 *o) {
+ __block unsigned y;
+ __block unsigned long x;
+ if (o)
+ return 1;
+ [o rdar7582031:^{ y = 1; }];
+ [o rdar7582031_b:^{ x = 1LL; }];
+ return x + (unsigned long) y; // expected-warning{{The left operand of '+' is a garbage value}}
+}
+
+// Show that we handle static variables also getting invalidated.
+void rdar7582031_aux(void (^)(void));
+RDar7582031 *rdar7582031_aux_2();
+
+unsigned rdar7582031_static() {
+ static RDar7582031 *o = 0;
+ rdar7582031_aux(^{ o = rdar7582031_aux_2(); });
+
+ __block unsigned x;
+ [o rdar7582031:^{ x = 1; }];
+ return x; // no-warning
+}
+
//===----------------------------------------------------------------------===//
// <rdar://problem/7462324> - Test that variables passed using __blocks
// are not treated as being uninitialized.
@@ -730,3 +779,91 @@ void rdar_7527292() {
}
}
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7515938> - Handle initialization of incomplete arrays
+// in structures using a compound value. Previously this crashed.
+//===----------------------------------------------------------------------===//
+
+struct rdar_7515938 {
+ int x;
+ int y[];
+};
+
+const struct rdar_7515938 *rdar_7515938() {
+ static const struct rdar_7515938 z = { 0, { 1, 2 } };
+ if (z.y[0] != 1) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+ return &z;
+}
+
+struct rdar_7515938_str {
+ int x;
+ char y[];
+};
+
+const struct rdar_7515938_str *rdar_7515938_str() {
+ static const struct rdar_7515938_str z = { 0, "hello" };
+ return &z;
+}
+
+//===----------------------------------------------------------------------===//
+// Assorted test cases from PR 4172.
+//===----------------------------------------------------------------------===//
+
+struct PR4172A_s { int *a; };
+
+void PR4172A_f2(struct PR4172A_s *p);
+
+int PR4172A_f1(void) {
+ struct PR4172A_s m;
+ int b[4];
+ m.a = b;
+ PR4172A_f2(&m);
+ return b[3]; // no-warning
+}
+
+struct PR4172B_s { int *a; };
+
+void PR4172B_f2(struct PR4172B_s *p);
+
+int PR4172B_f1(void) {
+ struct PR4172B_s m;
+ int x;
+ m.a = &x;
+ PR4172B_f2(&m);
+ return x; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// Test invalidation of values in struct literals.
+//===----------------------------------------------------------------------===//
+
+struct s_rev96062 { int *x; int *y; };
+struct s_rev96062_nested { struct s_rev96062 z; };
+
+void test_a_rev96062_aux(struct s_rev96062 *s);
+void test_a_rev96062_aux2(struct s_rev96062_nested *s);
+
+int test_a_rev96062() {
+ int a, b;
+ struct s_rev96062 x = { &a, &b };
+ test_a_rev96062_aux(&x);
+ return a + b; // no-warning
+}
+int test_b_rev96062() {
+ int a, b;
+ struct s_rev96062 x = { &a, &b };
+ struct s_rev96062 z = x;
+ test_a_rev96062_aux(&z);
+ return a + b; // no-warning
+}
+int test_c_rev96062() {
+ int a, b;
+ struct s_rev96062 x = { &a, &b };
+ struct s_rev96062_nested w = { x };
+ struct s_rev96062_nested z = w;
+ test_a_rev96062_aux2(&z);
+ return a + b; // no-warning
+}
diff --git a/test/Analysis/misc-ps-region-store.mm b/test/Analysis/misc-ps-region-store.mm
index fd92759012f4..92addd12f2aa 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-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -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-experimental-internal-checks -analyzer-check-objc-mem -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 ae42dca3b45e..fa05f6f60308 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-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code %s
typedef struct objc_ivar *Ivar;
typedef struct objc_selector *SEL;
@@ -837,3 +837,99 @@ void f(kwset_t *kws, char const *p, char const *q) {
d = delta[c = (end+=d)[-1]]; // no-warning
trie = next[c];
}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7593875> When handling sizeof(VLA) it leads to a hole in
+// the ExplodedGraph (causing a false positive)
+//===----------------------------------------------------------------------===//
+
+int rdar_7593875_aux(int x);
+int rdar_7593875(int n) {
+ int z[n > 10 ? 10 : n]; // VLA.
+ int v;
+ v = rdar_7593875_aux(sizeof(z));
+ // Previously we got a false positive about 'v' being uninitialized.
+ return v; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// Handle casts from symbolic regions (packaged as integers) to doubles.
+// Previously this caused an assertion failure.
+//===----------------------------------------------------------------------===//
+
+void *foo_rev95119();
+void baz_rev95119(double x);
+void bar_rev95119() {
+ // foo_rev95119() returns a symbolic pointer. It is then
+ // cast to an int which is then cast to a double.
+ int value = (int) foo_rev95119();
+ baz_rev95119((double)value);
+}
+
+//===----------------------------------------------------------------------===//
+// Handle loading a symbolic pointer from a symbolic region that was
+// invalidated by a call to an unknown function.
+//===----------------------------------------------------------------------===//
+
+void bar_rev95192(int **x);
+void foo_rev95192(int **x) {
+ *x = 0;
+ bar_rev95192(x);
+ // Not a null dereference.
+ **x = 1; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// Handle casts of a function to a function pointer with a different return
+// value. We don't yet emit an error for such cases, but we now we at least
+// don't crash when the return value gets interpreted in a way that
+// violates our invariants.
+//===----------------------------------------------------------------------===//
+
+void *foo_rev95267();
+int bar_rev95267() {
+ char (*Callback_rev95267)(void) = (char (*)(void)) foo_rev95267;
+ if ((*Callback_rev95267)() == (char) 0)
+ return 1;
+ return 0;
+}
+
+// Same as previous case, but handle casts to 'void'.
+int bar_rev95274() {
+ void (*Callback_rev95274)(void) = (void (*)(void)) foo_rev95267;
+ (*Callback_rev95274)();
+ return 0;
+}
+
+void rdar7582031_test_static_init_zero() {
+ static unsigned x;
+ if (x == 0)
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+void rdar7582031_test_static_init_zero_b() {
+ static void* x;
+ if (x == 0)
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+
+//===----------------------------------------------------------------------===//
+// Test handling of parameters that are structs that contain floats and //
+// nested fields. //
+//===----------------------------------------------------------------------===//
+
+struct s_rev95547_nested { float x, y; };
+struct s_rev95547 {
+ struct s_rev95547_nested z1;
+ struct s_rev95547_nested z2;
+};
+float foo_rev95547(struct s_rev95547 w) {
+ return w.z1.x + 20.0; // no-warning
+}
+void foo_rev95547_b(struct s_rev95547 w) {
+ struct s_rev95547 w2 = w;
+ w2.z1.x += 20.0; // no-warning
+}
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 f4f4e5c32431..5722a04aa2dd 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -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-experimental-internal-checks -analyzer-check-objc-mem -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 d7800f8f030b..659f675efc0b 100644
--- a/test/Analysis/no-exit-cfg.c
+++ b/test/Analysis/no-exit-cfg.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 dc553ccf2f77..f9ac589797a8 100644
--- a/test/Analysis/no-outofbounds.c
+++ b/test/Analysis/no-outofbounds.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -checker-cfref -analyze -analyzer-experimental-internal-checks -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -checker-cfref -analyze -analyzer-experimental-internal-checks -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyzer-check-objc-mem -analyze -analyzer-experimental-internal-checks -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyzer-check-objc-mem -analyze -analyzer-experimental-internal-checks -analyzer-store=region -verify %s
// XFAIL: *
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index dfd76e9dfd86..0199d20fdbb2 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-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -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 6dd50a345298..704ad339e1fc 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-experimental-internal-checks -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=basic -analyzer-store=basic
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -verify %s -analyzer-constraints=range -analyzer-store=basic
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=basic -analyzer-store=basic
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -verify %s -analyzer-constraints=range -analyzer-store=basic
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -std=gnu99 -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
typedef unsigned uintptr_t;
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 68e77caa36bd..45325e92f376 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-experimental-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-experimental-checks -analyzer-check-objc-mem -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 a2a8ec6b87e6..522b9dcb94e7 100644
--- a/test/Analysis/override-werror.c
+++ b/test/Analysis/override-werror.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -Werror %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -Werror %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -Werror %s -analyzer-store=basic -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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.m b/test/Analysis/plist-output.m
index a584de8a47bb..f49fef5d6dbe 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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/pr4209.m b/test/Analysis/pr4209.m
index da288e943b4f..eb010157d661 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 890fa04540dc..feafe2ac8a1f 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-experimental-internal-checks -checker-cfref -pedantic -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -pedantic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -pedantic -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 b21b1dcf787a..e8a410ff1372 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-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify %s
// PR 4164: http://llvm.org/bugs/show_bug.cgi?id=4164
//
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index be504866745d..f6bd61c074a3 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -triple i686-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -triple x86_64-apple-darwin9 %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -triple i686-apple-darwin9 %s
void f1() {
int a[10];
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index b3558a632147..a2af94637d0e 100644
--- a/test/Analysis/rdar-6442306-1.m
+++ b/test/Analysis/rdar-6442306-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem %s -analyzer-store=basic -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem %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 d4c67a1e66bb..dd0181099ee7 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-dead-stores -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 9afffcbe6078..82232c6bb97d 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-experimental-internal-checks -checker-cfref -analyzer-store=region %s
+// RUN: %clang_cc1 -verify -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 423fe4b05a24..844a9367b431 100644
--- a/test/Analysis/rdar-6541136.c
+++ b/test/Analysis/rdar-6541136.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic %s
+// RUN: %clang_cc1 -verify -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 185649f57268..2aa22294172c 100644
--- a/test/Analysis/rdar-6562655.m
+++ b/test/Analysis/rdar-6562655.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 a4229f767190..ff32372f44fc 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-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 225074ba863c..838a98b2b79d 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-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 8a84b4bc239b..bb34713b41f6 100644
--- a/test/Analysis/rdar-7168531.m
+++ b/test/Analysis/rdar-7168531.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -triple i386-apple-darwin10 -analyzer-store=region
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -triple i386-apple-darwin10 -analyzer-store=basic
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=region
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -triple i386-apple-darwin10 -analyzer-store=basic
// 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 66210c312aeb..9defce2735ef 100644
--- a/test/Analysis/refcnt_naming.m
+++ b/test/Analysis/refcnt_naming.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 a641b8e8212f..54d7cf57e0c4 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify %s
void f1() {
int const &i = 3;
diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m
index 1b95ac4b0c29..9274cfc81403 100644
--- a/test/Analysis/region-1.m
+++ b/test/Analysis/region-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -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 2ef061a99885..751dca0ce30b 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 -checker-cfref -analyzer-store=basic -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -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 fcec46edd259..8995d5f364f1 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 -checker-cfref -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -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 3a0142b29550..111d4b92d126 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 -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -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 691e2a2f58a5..1c41d85d23e5 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem -analyzer-store=basic -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem -analyzer-store=region -fblocks -verify %s
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
diff --git a/test/Analysis/security-syntax-checks-no-emit.c b/test/Analysis/security-syntax-checks-no-emit.c
index fbfeb1a40413..7a71235a2c79 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 -warn-security-syntactic %s -verify
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-check-security-syntactic %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 cfdb030746dc..8dd859a4c4f3 100644
--- a/test/Analysis/security-syntax-checks.m
+++ b/test/Analysis/security-syntax-checks.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -warn-security-syntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-check-security-syntactic %s -verify
// <rdar://problem/6336718> rule request: floating point used as loop
// condition (FLP30-C, FLP-30-CPP)
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
index 315b9007d889..f8cadbe281be 100644
--- a/test/Analysis/stack-addr-ps.c
+++ b/test/Analysis/stack-addr-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -fblocks -verify %s
int* f1() {
int x = 0;
diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m
index c8a9e3ccbb22..4061150ec553 100644
--- a/test/Analysis/uninit-msg-expr.m
+++ b/test/Analysis/uninit-msg-expr.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=region -verify %s
+// 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
//===----------------------------------------------------------------------===//
// 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 d4e3b31a2382..1409dbd1df5e 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 -checker-cfref %s
-// RUN: %clang_cc1 -analyze -verify -analyzer-store=region -checker-cfref %s
+// 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
// Delta-Debugging reduced preamble.
typedef signed char BOOL;
diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.c
index 216856e549c7..44f506efadb2 100644
--- a/test/Analysis/uninit-vals-ps-region.c
+++ b/test/Analysis/uninit-vals-ps-region.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
struct s {
int data;
diff --git a/test/Analysis/uninit-vals-ps.c b/test/Analysis/uninit-vals-ps.c
index 12287a2df375..4abd413ae5d5 100644
--- a/test/Analysis/uninit-vals-ps.c
+++ b/test/Analysis/uninit-vals-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=region -verify %s
+// 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
struct FPRec {
void (*my_func)(int * x);
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 037e227be668..2f7f29c5d9e4 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=basic -verify %s
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=region -verify %s
+// 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
typedef unsigned int NSUInteger;
diff --git a/test/Analysis/unions-region.m b/test/Analysis/unions-region.m
index 7fd1b44f05fa..180faf8fd72d 100644
--- a/test/Analysis/unions-region.m
+++ b/test/Analysis/unions-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range %s -verify
//===-- unions-region.m ---------------------------------------------------===//
//
diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m
index 2ad886fdb3a1..600f0e28e036 100644
--- a/test/Analysis/unused-ivars.m
+++ b/test/Analysis/unused-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -warn-objc-unused-ivars %s -verify
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-check-objc-unused-ivars %s -verify
//===--- BEGIN: Delta-debugging reduced headers. --------------------------===//
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6796bbf60f39..245fe1f5f2a3 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -53,7 +53,7 @@ if(PYTHONINTERP_FOUND)
--param build_config=${CMAKE_CFG_INTDIR}
-sv ${CLANG_TEST_EXTRA_ARGS}
${CMAKE_CURRENT_BINARY_DIR}/${testdir}
- DEPENDS clang index-test c-index-test
+ DEPENDS clang c-index-test
COMMENT "Running Clang regression tests in ${testdir}")
endforeach()
@@ -64,7 +64,7 @@ if(PYTHONINTERP_FOUND)
--param build_config=${CMAKE_CFG_INTDIR}
-sv ${CLANG_TEST_EXTRA_ARGS}
${CMAKE_CURRENT_BINARY_DIR}
- DEPENDS clang index-test c-index-test
+ DEPENDS clang c-index-test
COMMENT "Running Clang regression tests")
add_custom_target(clang-c++tests
@@ -74,6 +74,6 @@ if(PYTHONINTERP_FOUND)
--param build_config=${CMAKE_CFG_INTDIR}
-sv ${CLANG_TEST_EXTRA_ARGS}
${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests
- DEPENDS clang index-test c-index-test
+ DEPENDS clang c-index-test
COMMENT "Running Clang regression tests")
endif()
diff --git a/test/CXX/basic/basic.def.odr/p1-var.cpp b/test/CXX/basic/basic.def.odr/p1-var.cpp
new file mode 100644
index 000000000000..892f546ee545
--- /dev/null
+++ b/test/CXX/basic/basic.def.odr/p1-var.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++ [basic.def.odr]p1:
+// No translation unit shall contain more than one definition of any
+// variable, [...].
+
+// Bad: in C++, these are both definitions. None of that C99 tentative stuff.
+int i; // expected-note {{previous}}
+int i; // expected-error {{redefinition}}
+
+// OK: decl + def
+extern int j;
+int j;
+
+// OK: def + decl
+int k;
+extern int k;
+
+// Bad. The important thing here is that we don't emit the diagnostic twice.
+int l = 1; // expected-note {{previous}}
+int l = 2; // expected-error {{redefinition}}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
index 76b6e2b57465..8126d28562ae 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
@@ -15,4 +15,4 @@ namespace A {
}
class Ident<int> GlobalIdent;
-union Ident<int> GlobalIdent; // expected-error {{ tag type that does not match }}
+union Ident<int> GlobalIdent2; // expected-error {{ tag type that does not match }}
diff --git a/test/CXX/class.access/class.access.base/p1.cpp b/test/CXX/class.access/class.access.base/p1.cpp
index fd0d9f68e1e2..1bbcedb9a1e7 100644
--- a/test/CXX/class.access/class.access.base/p1.cpp
+++ b/test/CXX/class.access/class.access.base/p1.cpp
@@ -54,13 +54,13 @@ namespace test0 {
// of the base class are accessible as protected members of the
// derived class.
namespace test1 {
- class Base { // expected-note 6 {{constrained by protected inheritance}}
- public: int pub; static int spub; // expected-note 2 {{constrained by protected inheritance}}
+ class Base {
+ public: int pub; static int spub;
protected: int prot; static int sprot; // expected-note 4 {{declared protected here}}
private: int priv; static int spriv; // expected-note 8 {{declared private here}}
};
- class Test : protected Base {
+ class Test : protected Base { // expected-note 6 {{declared protected here}} expected-note 8 {{constrained by protected inheritance here}}
void test() {
pub++;
spub++;
@@ -79,19 +79,19 @@ namespace test1 {
};
void test(Test *t) {
- t->pub++; // expected-error {{protected member}}
+ t->pub++; // expected-error {{protected member}} expected-error {{protected base class}}
t->spub++; // expected-error {{protected member}}
- t->prot++; // expected-error {{protected member}}
+ t->prot++; // expected-error {{protected member}} expected-error {{protected base class}}
t->sprot++; // expected-error {{protected member}}
- t->priv++; // expected-error {{private member}}
+ t->priv++; // expected-error {{private member}} expected-error {{protected base class}}
t->spriv++; // expected-error {{private member}}
// Two possible errors here: one for Base, one for the member
- t->Base::pub++; // expected-error {{protected member}}
+ t->Base::pub++; // expected-error {{protected member}} expected-error {{protected base class}}
t->Base::spub++; // expected-error {{protected member}}
- t->Base::prot++; // expected-error 2 {{protected member}}
+ t->Base::prot++; // expected-error 2 {{protected member}} expected-error {{protected base class}}
t->Base::sprot++; // expected-error 2 {{protected member}}
- t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}}
+ t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{protected base class}}
t->Base::spriv++; // expected-error {{protected member}} expected-error {{private member}}
}
}
@@ -102,21 +102,20 @@ namespace test1 {
// the base class are accessible as private members of the derived
// class.
namespace test2 {
- class Base { //expected-note 6 {{constrained by private inheritance}}
+ class Base {
public:
- int pub; // expected-note {{constrained by private inheritance}}
- static int spub; // expected-note {{constrained by private inheritance}}
+ int pub;
+ static int spub;
protected:
- int prot; // expected-note {{constrained by private inheritance}} \
- // expected-note {{declared protected here}}
- static int sprot; // expected-note {{constrained by private inheritance}} \
- // expected-note {{declared protected here}}
+ int prot; // expected-note {{declared protected here}}
+ static int sprot; // expected-note {{declared protected here}}
private:
int priv; // expected-note 4 {{declared private here}}
static int spriv; // expected-note 4 {{declared private here}}
};
- class Test : private Base { // expected-note 6 {{'private' inheritance specifier here}}
+ class Test : private Base { // expected-note 6 {{declared private here}} \
+ // expected-note 10 {{constrained by private inheritance here}}
void test() {
pub++;
spub++;
@@ -135,18 +134,18 @@ namespace test2 {
};
void test(Test *t) {
- t->pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->pub++; // expected-error {{private member}} expected-error {{private base class}}
t->spub++; // expected-error {{private member}}
- t->prot++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->prot++; // expected-error {{private member}} expected-error {{private base class}}
t->sprot++; // expected-error {{private member}}
- t->priv++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->priv++; // expected-error {{private member}} expected-error {{private base class}}
t->spriv++; // expected-error {{private member}}
- t->Base::pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->Base::pub++; // expected-error {{private member}} expected-error {{private base class}}
t->Base::spub++; // expected-error {{private member}}
- t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{private base class}}
t->Base::sprot++; // expected-error {{protected member}} expected-error {{private member}}
- t->Base::priv++; // expected-error 2 {{private member}} expected-error {{inaccessible base class}}
+ t->Base::priv++; // expected-error 2 {{private member}} expected-error {{private base class}}
t->Base::spriv++; // expected-error 2 {{private member}}
}
}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
new file mode 100644
index 000000000000..7aa614cd8b1a
--- /dev/null
+++ b/test/CXX/class.access/p4.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+
+// C++0x [class.access]p4:
+
+// Access control is applied uniformly to all names, whether the
+// names are referred to from declarations or expressions. In the
+// case of overloaded function names, access control is applied to
+// the function selected by overload resolution.
+
+class Public {} PublicInst;
+class Protected {} ProtectedInst;
+class Private {} PrivateInst;
+
+namespace test0 {
+ class A {
+ public:
+ void foo(Public&);
+ protected:
+ void foo(Protected&); // expected-note 2 {{declared protected here}}
+ private:
+ void foo(Private&); // expected-note 2 {{declared private here}}
+ };
+
+ void test(A *op) {
+ op->foo(PublicInst);
+ op->foo(ProtectedInst); // expected-error {{'foo' is a protected member}}
+ op->foo(PrivateInst); // expected-error {{'foo' is a private member}}
+
+ void (A::*a)(Public&) = &A::foo;
+ void (A::*b)(Protected&) = &A::foo; // expected-error {{'foo' is a protected member}}
+ void (A::*c)(Private&) = &A::foo; // expected-error {{'foo' is a private member}}
+ }
+}
+
+// Member operators.
+namespace test1 {
+ class A {
+ public:
+ void operator+(Public&);
+ void operator[](Public&);
+ void operator()(Public&);
+ typedef void (*PublicSurrogate)(Public&);
+ operator PublicSurrogate() const;
+ protected:
+ void operator+(Protected&); // expected-note {{declared protected here}}
+ void operator[](Protected&); // expected-note {{declared protected here}}
+ void operator()(Protected&); // expected-note {{declared protected here}}
+ typedef void (*ProtectedSurrogate)(Protected&);
+ operator ProtectedSurrogate() const; // expected-note {{declared protected here}}
+ private:
+ void operator+(Private&); // expected-note {{declared private here}}
+ void operator[](Private&); // expected-note {{declared private here}}
+ void operator()(Private&); // expected-note {{declared private here}}
+ void operator-(); // expected-note {{declared private here}}
+ typedef void (*PrivateSurrogate)(Private&);
+ operator PrivateSurrogate() const; // expected-note {{declared private here}}
+ };
+ void operator+(const A &, Public&);
+ void operator+(const A &, Protected&);
+ void operator+(const A &, Private&);
+ void operator-(const A &);
+
+ void test(A &a, Public &pub, Protected &prot, Private &priv) {
+ a + pub;
+ a + prot; // expected-error {{'operator+' is a protected member}}
+ a + priv; // expected-error {{'operator+' is a private member}}
+ a[pub];
+ a[prot]; // expected-error {{'operator[]' is a protected member}}
+ a[priv]; // expected-error {{'operator[]' is a private member}}
+ a(pub);
+ a(prot); // expected-error {{'operator()' is a protected member}}
+ a(priv); // expected-error {{'operator()' is a private member}}
+ -a; // expected-error {{'operator-' is a private member}}
+
+ const A &ca = a;
+ ca + pub;
+ ca + prot;
+ ca + priv;
+ -ca;
+ // These are all surrogate calls
+ ca(pub);
+ ca(prot); // expected-error {{'operator void (*)(class Protected &)' is a protected member}}
+ ca(priv); // expected-error {{'operator void (*)(class Private &)' is a private member}}
+ }
+}
+
+// Implicit constructor calls.
+namespace test2 {
+ class A {
+ private:
+ A(); // expected-note {{declared private here}}
+
+ static A foo;
+ };
+
+ A a; // expected-error {{calling a private constructor}}
+ A A::foo; // okay
+}
+
+// Implicit destructor calls.
+namespace test3 {
+ class A{
+ private:
+ ~A(); // expected-note 3 {{declared private here}}
+ static A foo;
+ };
+
+ A a; // expected-error {{'~A' is a private member}}
+ A A::foo;
+
+ void foo(A param) { // expected-error {{'~A' is a private member}}
+ A local; // expected-error {{'~A' is a private member}}
+ }
+}
diff --git a/test/CXX/class.access/p6.cpp b/test/CXX/class.access/p6.cpp
new file mode 100644
index 000000000000..aaf510a6d11f
--- /dev/null
+++ b/test/CXX/class.access/p6.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+
+// C++0x [class.access]p6:
+// All access controls in [class.access] affect the ability to
+// access a class member name from a particular scope. For purposes
+// of access control, the base-specifiers of a class and the
+// definitions of class members that appear outside of the class
+// definition are considered to be within the scope of that
+// class. In particular, access controls apply as usual to member
+// names accessed as part of a function return type, even though it
+// is not possible to determine the access privileges of that use
+// without first parsing the rest of the function
+// declarator. Similarly, access control for implicit calls to the
+// constructors, the conversion functions, or the destructor called
+// to create and destroy a static data member is performed as if
+// these calls appeared in the scope of the member's class.
+
+struct Public {}; struct Protected {}; struct Private {};
+
+namespace test0 {
+ class A {
+ typedef int type; // expected-note {{declared private here}}
+ type foo();
+ };
+
+ A::type foo() { } // expected-error {{'type' is a private member}}
+ A::type A::foo() { }
+}
+
+// conversion decls
+namespace test1 {
+ class A {
+ public:
+ A();
+ operator Public ();
+ A(Public);
+ protected:
+ operator Protected (); // expected-note {{declared protected here}}
+ A(Protected); // expected-note {{declared protected here}}
+ private:
+ operator Private (); // expected-note {{declared private here}}
+ A(Private); // expected-note {{declared private here}}
+ };
+
+ void test() {
+ A a;
+ Public pub = a;
+ Protected prot = a; // expected-error {{'operator Protected' is a protected member}}
+ Private priv = a; // expected-error {{'operator Private' is a private member}}
+ A apub = pub;
+ A aprot = prot; // expected-error {{protected constructor}}
+ A apriv = priv; // expected-error {{private constructor}}
+ }
+}
diff --git a/test/CXX/class/class.local/p2.cpp b/test/CXX/class/class.local/p2.cpp
index 56ff1e53a493..8d281a57e137 100644
--- a/test/CXX/class/class.local/p2.cpp
+++ b/test/CXX/class/class.local/p2.cpp
@@ -3,9 +3,9 @@
struct A { };
void f() {
- struct B : private A {}; // expected-note{{'private' inheritance specifier here}}
+ struct B : private A {}; // expected-note{{declared private here}}
B b;
- A *a = &b; // expected-error{{conversion from 'struct B' to inaccessible base class 'struct A'}}
+ A *a = &b; // expected-error{{cannot cast 'struct B' to its private base class 'struct A'}}
}
diff --git a/test/CXX/conv/conv.mem/p4.cpp b/test/CXX/conv/conv.mem/p4.cpp
new file mode 100644
index 000000000000..1ecbc47ffbb8
--- /dev/null
+++ b/test/CXX/conv/conv.mem/p4.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+
+struct Base {
+ int data;
+ int method();
+};
+int (Base::*data_ptr) = &Base::data;
+int (Base::*method_ptr)() = &Base::method;
+
+namespace test0 {
+ struct Derived : Base {};
+ void test() {
+ int (Derived::*d) = data_ptr;
+ int (Derived::*m)() = method_ptr;
+ }
+}
+
+// Can't be inaccessible.
+namespace test1 {
+ struct Derived : private Base {}; // expected-note 2 {{declared private here}}
+ void test() {
+ int (Derived::*d) = data_ptr; // expected-error {{cannot cast private base class 'struct Base' to 'struct test1::Derived'}}
+ int (Derived::*m)() = method_ptr; // expected-error {{cannot cast private base class 'struct Base' to 'struct test1::Derived'}}
+ }
+};
+
+// Can't be ambiguous.
+namespace test2 {
+ struct A : Base {};
+ struct B : Base {};
+ struct Derived : A, B {};
+ void test() {
+ int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test2::Derived'}}
+ int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test2::Derived'}}
+ }
+}
+
+// Can't be virtual.
+namespace test3 {
+ struct Derived : virtual Base {};
+ void test() {
+ int (Derived::*d) = data_ptr; // expected-error {{conversion from pointer to member of class 'struct Base' to pointer to member of class 'struct test3::Derived' via virtual base 'struct Base' is not allowed}}
+ int (Derived::*m)() = method_ptr; // expected-error {{conversion from pointer to member of class 'struct Base' to pointer to member of class 'struct test3::Derived' via virtual base 'struct Base' is not allowed}}
+ }
+}
+
+// Can't be virtual even if there's a non-virtual path.
+namespace test4 {
+ struct A : Base {};
+ struct Derived : Base, virtual A {};
+ void test() {
+ int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test4::Derived'}}
+ int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'struct Base' to pointer to member of derived class 'struct test4::Derived'}}
+ }
+}
+
+// PR6254: don't get thrown off by a virtual base.
+namespace test5 {
+ struct A {};
+ struct Derived : Base, virtual A {};
+ void test() {
+ int (Derived::*d) = data_ptr;
+ int (Derived::*m)() = method_ptr;
+ }
+}
diff --git a/test/CXX/conv/conv.qual/pr6089.cpp b/test/CXX/conv/conv.qual/pr6089.cpp
new file mode 100644
index 000000000000..ae75ec41bd8f
--- /dev/null
+++ b/test/CXX/conv/conv.qual/pr6089.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+bool is_char_ptr( const char* );
+
+template< class T >
+ long is_char_ptr( T /* r */ );
+
+// Note: the const here does not lead to a qualification conversion
+template< class T >
+ void make_range( T* const r, bool );
+
+template< class T >
+ void make_range( T& r, long );
+
+void first_finder( const char*& Search )
+{
+ make_range( Search, is_char_ptr(Search) );
+}
diff --git a/test/CXX/dcl.dcl/dcl.enum/p5.cpp b/test/CXX/dcl.dcl/dcl.enum/p5.cpp
new file mode 100644
index 000000000000..f26062416cbf
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.enum/p5.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fsyntax-only -verify %s
+template<typename T> int force_same(T, T);
+
+// C++ [dcl.enum]p5:
+// [...] If the underlying type is not fixed, the type of each enumerator is
+// the type of its initializing value:
+// - If an initializer is specified for an enumerator, the initializing
+// value has the same type as the expression.
+enum Bullet1 {
+ Bullet1Val1 = 'a',
+ Bullet1Val2 = 10u,
+ Bullet1Val1IsChar = sizeof(force_same(Bullet1Val1, char(0))),
+ Bullet1Val2IsUnsigned = sizeof(force_same(Bullet1Val2, unsigned(0)))
+};
+
+// - If no initializer is specified for the first enumerator, the
+// initializing value has an unspecified integral type.
+enum Bullet2 {
+ Bullet2Val,
+ Bullet2ValIsInt = sizeof(force_same(Bullet2Val, int(0)))
+};
+
+// - Otherwise the type of the initializing value is the same as the type
+// of the initializing value of the preceding enumerator unless the
+// incremented value is not representable in that type, in which case the
+// type is an unspecified integral type sufficient to contain the
+// incremented value. If no such type exists, the program is ill-formed.
+enum Bullet3a {
+ Bullet3aVal1 = 17,
+ Bullet3aVal2,
+ Bullet3aVal2IsInt = sizeof(force_same(Bullet3aVal2, int(0))),
+ Bullet3aVal3 = 2147483647,
+ Bullet3aVal3IsInt = sizeof(force_same(Bullet3aVal3, int(0))),
+ Bullet3aVal4,
+ Bullet3aVal4IsUnsigned = sizeof(force_same(Bullet3aVal4, 0ul))
+};
+
+enum Bullet3b {
+ Bullet3bVal1 = 17u,
+ Bullet3bVal2,
+ Bullet3bVal2IsInt = sizeof(force_same(Bullet3bVal2, 0u)),
+ Bullet3bVal3 = 2147483647u,
+ Bullet3bVal3IsInt = sizeof(force_same(Bullet3bVal3, 0u)),
+ Bullet3bVal4,
+ Bullet3bVal4IsUnsigned = sizeof(force_same(Bullet3bVal4, 0ul))
+};
+
+enum Bullet3c {
+ Bullet3cVal1 = 0xFFFFFFFFFFFFFFFEull,
+ Bullet3cVal2,
+ Bullet3cVal3 // expected-warning{{not representable}}
+};
+
+// Following the closing brace of an enum-specifier, each enumerator has the
+// type of its enumeration.
+int array0[sizeof(force_same(Bullet3bVal3, Bullet3b(0)))? 1 : -1];
diff --git a/test/CXX/dcl.dcl/dcl.link/p7.cpp b/test/CXX/dcl.dcl/dcl.link/p7.cpp
new file mode 100644
index 000000000000..bd9ff3c3665c
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.link/p7.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+struct X { };
+
+// CHECK: @x1 = global %struct.X zeroinitializer
+// CHECK: @x4 = global %struct.X zeroinitializer
+// CHECK: @x2 = external global %struct.X
+// CHECK: @x3 = external global %struct.X
+extern "C" {
+
+
+ X x1;
+}
+
+extern "C" X x2;
+
+extern X x3;
+
+X x4;
+
+X& get(int i) {
+ if (i == 1)
+ return x1;
+ else if (i == 2)
+ return x2;
+ else if (i == 3)
+ return x3;
+ else
+ return x4;
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
index 16a09d836d16..fcc1334b1506 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p6.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -verify %s
-// XFAIL: *
class A {
public:
@@ -7,7 +6,11 @@ public:
explicit operator int(); // expected-warning {{explicit conversion functions are a C++0x extension}}
- explicit void f0(); // expected-error {{'explicit' cannot only be applied to constructor or conversion function}}
+ explicit void f0(); // expected-error {{'explicit' can only be applied to a constructor or conversion function}}
+
+ operator bool();
};
-explicit A::A() { } // expected-error {{'explicit' cannot be specified outside class definition}}
+explicit A::A() { } // expected-error {{'explicit' can only be specified inside the class definition}}
+explicit A::operator bool() { return false; } // expected-warning {{explicit conversion functions are a C++0x extension}}\
+ // expected-error {{'explicit' can only be specified inside the class definition}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
index cf3db5175fa4..d9c5d014014a 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
@@ -68,17 +68,23 @@ void bind_lvalue_quals(volatile Base b, volatile Derived d,
volatile Base &bvr4 = dvc; // expected-error{{binding of reference to type 'struct Base volatile' to a value of type 'struct Derived const volatile' drops qualifiers}}
volatile int &ir = ivc; // expected-error{{binding of reference to type 'int volatile' to a value of type 'int const volatile' drops qualifiers}}
+
+ const volatile Base &bcvr1 = b;
+ const volatile Base &bcvr2 = d;
}
void bind_lvalue_to_rvalue() {
Base &br1 = Base(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Base'}}
Base &br2 = Derived(); // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a temporary of type 'struct Derived'}}
+ const volatile Base &br3 = Base(); // expected-error{{volatile lvalue reference to type 'struct Base const volatile' cannot bind to a temporary of type 'struct Base'}}
+ const volatile Base &br4 = Derived(); // expected-error{{volatile lvalue reference to type 'struct Base const volatile' cannot bind to a temporary of type 'struct Derived'}}
int &ir = 17; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
}
void bind_lvalue_to_unrelated(Unrelated ur) {
Base &br1 = ur; // expected-error{{non-const lvalue reference to type 'struct Base' cannot bind to a value of unrelated type 'struct Unrelated'}}
+ const volatile Base &br2 = ur; // expected-error{{volatile lvalue reference to type 'struct Base const volatile' cannot bind to a value of unrelated type 'struct Unrelated'}}
}
void bind_lvalue_to_conv_lvalue() {
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
new file mode 100644
index 000000000000..cf529098dfe4
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR5909 {
+ struct Foo {
+ int x : 20;
+ };
+
+ bool Test(const int& foo);
+
+ const Foo f = { 0 }; // It compiles without the 'const'.
+ bool z = Test(f.x);
+}
diff --git a/test/CXX/dcl.decl/dcl.init/p6.cpp b/test/CXX/dcl.decl/dcl.init/p6.cpp
new file mode 100644
index 000000000000..f627a199eca6
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/p6.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// FIXME: Very incomplete!
+
+// If a program calls for the default initialization of an object of a
+// const-qualified type T, T shall be a class type with a
+// user-provided default constructor.
+struct NoUserDefault { };
+struct HasUserDefault { HasUserDefault(); };
+
+void test_const_default_init() {
+ const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'struct NoUserDefault const' requires a user-provided default constructor}}
+ const HasUserDefault x2;
+ const int x3; // expected-error{{default initialization of an object of const type 'int const'}}
+}
diff --git a/test/CXX/dcl.decl/dcl.name/p1.cpp b/test/CXX/dcl.decl/dcl.name/p1.cpp
new file mode 100644
index 000000000000..7586007cc7b3
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.name/p1.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace pr6200 {
+ struct v {};
+ struct s {
+ int i;
+ operator struct v() { return v(); };
+ };
+
+ void f()
+ {
+ // Neither of these is a declaration.
+ (void)new struct s;
+ (void)&s::operator struct v;
+ }
+}
diff --git a/test/CXX/expr/p8.cpp b/test/CXX/expr/p8.cpp
index cc834d9dc8d8..2f6c094301ee 100644
--- a/test/CXX/expr/p8.cpp
+++ b/test/CXX/expr/p8.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
int a0;
-const volatile int a1;
+const volatile int a1 = 2;
int a2[16];
int a3();
diff --git a/test/CXX/lex/lex.literal/lex.ccon/p1.cpp b/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
new file mode 100644
index 000000000000..7b65f7ee8320
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ccon/p1.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Check types of char literals
+extern char a;
+extern __typeof('a') a;
+extern int b;
+extern __typeof('asdf') b;
+extern wchar_t c;
+extern __typeof(L'a') c;
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
new file mode 100644
index 000000000000..83365a2a082c
--- /dev/null
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++0x [temp.arg.nontype]p1:
+//
+// A template-argument for a non-type, non-template template-parameter shall
+// be one of:
+// -- an integral constant expression; or
+// -- the name of a non-type template-parameter ; or
+namespace non_type_tmpl_param {
+ template <int N> struct X0 { X0(); };
+ template <int N> X0<N>::X0() { }
+ template <int* N> struct X1 { X1(); };
+ template <int* N> X1<N>::X1() { }
+ template <int& N> struct X3 { X3(); };
+ template <int& N> X3<N>::X3() { }
+ template <int (*F)(int)> struct X4 { X4(); };
+ template <int (*F)(int)> X4<F>::X4() { }
+ template <typename T, int (T::* M)(int)> struct X5 { X5(); };
+ template <typename T, int (T::* M)(int)> X5<T, M>::X5() { }
+}
+
+// -- the address of an object or function with external linkage, including
+// function templates and function template-ids but excluding non-static
+// class members, expressed as & id-expression where the & is optional if
+// the name refers to a function or array, or if the corresponding
+// template-parameter is a reference; or
+namespace addr_of_obj_or_func {
+ template <int* p> struct X0 { };
+ template <int (*fp)(int)> struct X1 { };
+ // FIXME: Add reference template parameter tests.
+
+ int i = 42;
+ int iarr[10];
+ int f(int i);
+ template <typename T> T f_tmpl(T t);
+ void test() {
+ X0<&i> x0a;
+ X0<iarr> x0b;
+ X1<&f> x1a;
+ X1<f> x1b;
+ X1<f_tmpl> x1c;
+ X1<f_tmpl<int> > x1d;
+ }
+}
+
+// -- a constant expression that evaluates to a null pointer value (4.10); or
+// -- a constant expression that evaluates to a null member pointer value
+// (4.11); or
+// -- a pointer to member expressed as described in 5.3.1.
+
+namespace bad_args {
+ template <int* N> struct X0 { };
+ int i = 42;
+ X0<&i + 2> x0a; // expected-error{{non-type template argument does not refer to any declaration}}
+ int* iptr = &i;
+ X0<iptr> x0b; // FIXME: This should not be accepted.
+}
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
new file mode 100644
index 000000000000..458aff2f0232
--- /dev/null
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++0x [temp.arg.nontype] p5:
+// The following conversions are performed on each expression used as
+// a non-type template-argument. If a non-type template-argument cannot be
+// converted to the type of the corresponding template-parameter then the
+// program is ill-formed.
+// -- for a non-type template-parameter of integral or enumeration type,
+// integral promotions (4.5) and integral conversions (4.7) are applied.
+// -- for a non-type template-parameter of type pointer to object,
+// qualification conversions (4.4) and the array-to-pointer conversion
+// (4.2) are applied; if the template-argument is of type
+// std::nullptr_t, the null pointer conversion (4.10) is applied.
+namespace pointer_to_object_parameters {
+ // PR6226
+ struct Str {
+ Str(const char *);
+ };
+
+ template<const char *s>
+ struct A {
+ Str get() { return s; }
+ };
+
+ char hello[6] = "Hello";
+ extern const char world[6];
+ const char world[6] = "world";
+ void test() {
+ (void)A<hello>().get();
+ (void)A<world>().get();
+ }
+
+ class X {
+ public:
+ X();
+ X(int, int);
+ operator int() const;
+ };
+
+ template<X const *Ptr> struct A2;
+
+ X *X_ptr;
+ X an_X;
+ X array_of_Xs[10];
+ A2<X_ptr> *a12;
+ A2<array_of_Xs> *a13;
+ A2<&an_X> *a13_2;
+ A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
+
+ // PR6244
+ struct X1 {} X1v;
+ template <X1*> struct X2 { };
+ template <X1* Value> struct X3 : X2<Value> { };
+ struct X4 : X3<&X1v> { };
+}
+
+// -- For a non-type template-parameter of type reference to object, no
+// conversions apply. The type referred to by the reference may be more
+// cv-qualified than the (otherwise identical) type of the
+// template-argument. The template-parameter is bound directly to the
+// template-argument, which shall be an lvalue.
+namespace reference_parameters {
+ template <int& N> struct S0 { }; // expected-note 3 {{template parameter is declared here}}
+ template <const int& N> struct S1 { }; // expected-note 2 {{template parameter is declared here}}
+ template <volatile int& N> struct S2 { }; // expected-note 2 {{template parameter is declared here}}
+ template <const volatile int& N> struct S3 { };
+ int i;
+ extern const int ci;
+ volatile int vi;
+ extern const volatile int cvi;
+ void test() {
+ S0<i> s0;
+ S0<ci> s0c; // expected-error{{reference binding of non-type template parameter of type 'int &' to template argument of type 'int const' ignores qualifiers}}
+ S0<vi> s0v; // expected-error{{reference binding of non-type template parameter of type 'int &' to template argument of type 'int volatile' ignores qualifiers}}
+ S0<cvi> s0cv; // expected-error{{reference binding of non-type template parameter of type 'int &' to template argument of type 'int const volatile' ignores qualifiers}}
+
+ S1<i> s1;
+ S1<ci> s1c;
+ S1<vi> s1v; // expected-error{{reference binding of non-type template parameter of type 'int const &' to template argument of type 'int volatile' ignores qualifiers}}
+ S1<cvi> s1cv; // expected-error{{reference binding of non-type template parameter of type 'int const &' to template argument of type 'int const volatile' ignores qualifiers}}
+
+ S2<i> s2;
+ S2<ci> s2c; // expected-error{{reference binding of non-type template parameter of type 'int volatile &' to template argument of type 'int const' ignores qualifiers}}
+ S2<vi> s2v;
+ S2<cvi> s2cv; // expected-error{{reference binding of non-type template parameter of type 'int volatile &' to template argument of type 'int const volatile' ignores qualifiers}}
+
+ S3<i> s3;
+ S3<ci> s3c;
+ S3<vi> s3v;
+ S3<cvi> s3cv;
+ }
+
+ namespace PR6250 {
+ template <typename T, const T &ref> void inc() {
+ ref++; // expected-error{{read-only variable is not assignable}}
+ }
+
+ template<typename T, const T &ref> void bind() {
+ T &ref2 = ref; // expected-error{{drops qualifiers}}
+ }
+
+ int counter;
+ void test() {
+ inc<int, counter>(); // expected-note{{instantiation of}}
+ bind<int, counter>(); // expected-note{{instantiation of}}
+ }
+ }
+}
+
+// -- For a non-type template-parameter of type pointer to function, the
+// function-to-pointer conversion (4.3) is applied; if the
+// template-argument is of type std::nullptr_t, the null pointer
+// conversion (4.10) is applied. If the template-argument represents
+// a set of overloaded functions (or a pointer to such), the matching
+// function is selected from the set (13.4).
+// -- For a non-type template-parameter of type reference to function, no
+// conversions apply. If the template-argument represents a set of
+// overloaded functions, the matching function is selected from the set
+// (13.4).
+// -- For a non-type template-parameter of type pointer to member function,
+// if the template-argument is of type std::nullptr_t, the null member
+// pointer conversion (4.11) is applied; otherwise, no conversions
+// apply. If the template-argument represents a set of overloaded member
+// functions, the matching member function is selected from the set
+// (13.4).
+// -- For a non-type template-parameter of type pointer to data member,
+// qualification conversions (4.4) are applied; if the template-argument
+// is of type std::nullptr_t, the null member pointer conversion (4.11)
+// is applied.
diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
index 098ffa4dec75..b0078d4bdb6d 100644
--- a/test/CXX/temp/temp.decls/temp.mem/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
@@ -55,7 +55,7 @@ template double Foo::As2();
// Partial ordering with conversion function templates.
struct X0 {
template<typename T> operator T*() {
- T x;
+ T x = 1;
x = 17; // expected-error{{read-only variable is not assignable}}
}
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
index 8fb736ca0313..95f9640a0b43 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template<class X, class Y, class Z> X f(Y,Z); // expected-note {{candidate function}}
+template<class X, class Y, class Z> X f(Y,Z); // expected-note {{candidate template ignored: couldn't infer template argument 'X'}}
void g() {
f<int,char*,double>("aa",3.0);
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
index bcfb71c987eb..1b7310f00055 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
@@ -15,7 +15,8 @@ void test_f1(int *ip, float fv) {
f1(ip, fv);
}
-template<typename T> void f2(T*, T*); // expected-note 2 {{candidate function}}
+// TODO: this diagnostic can and should improve
+template<typename T> void f2(T*, T*); // expected-note 2 {{candidate template ignored: failed template argument deduction}}
struct ConvToIntPtr {
operator int*() const;
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
new file mode 100644
index 000000000000..6edf079b3524
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test0 {
+ template<class T> void apply(T x, void (*f)(T)) { f(x); } // expected-note 2 {{failed template argument deduction}}\
+ // expected-note {{no overload of 'temp2' matching 'void (*)(int)'}}
+
+ template<class A> void temp(A);
+ void test0() {
+ // okay: deduce T=int from first argument, A=int during overload
+ apply(0, &temp);
+ apply(0, &temp<>);
+
+ // okay: deduce T=int from first and second arguments
+ apply(0, &temp<int>);
+
+ // deduction failure: T=int from first, T=long from second
+ apply(0, &temp<long>); // expected-error {{no matching function for call to 'apply'}}
+ }
+
+ void over(int);
+ int over(long);
+
+ void test1() {
+ // okay: deductions match
+ apply(0, &over);
+
+ // deduction failure: deduced T=long from first argument, T=int from second
+ apply(0L, &over); // expected-error {{no matching function for call to 'apply'}}
+ }
+
+ void over(short);
+
+ void test2() {
+ // deduce T=int from first arg, second arg is undeduced context,
+ // pick correct overload of 'over' during overload resolution for 'apply'
+ apply(0, &over);
+ }
+
+ template<class A, class B> B temp2(A);
+ void test3() {
+ // deduce T=int from first arg, A=int B=void during overload resolution
+ apply(0, &temp2);
+ apply(0, &temp2<>);
+ apply(0, &temp2<int>);
+
+ // overload failure
+ apply(0, &temp2<long>); // expected-error {{no matching function for call to 'apply'}}
+ }
+}
+
+namespace test1 {
+ template<class T> void invoke(void (*f)(T)) { f(T()); } // expected-note 6 {{couldn't infer template argument}} \
+ // expected-note {{failed template argument deduction}}
+
+ template<class T> void temp(T);
+ void test0() {
+ // deduction failure: overload has template => undeduced context
+ invoke(&temp); // expected-error {{no matching function for call to 'invoke'}}
+ invoke(&temp<>); // expected-error {{no matching function for call to 'invoke'}}
+
+ // okay: full template-id
+ invoke(&temp<int>);
+ }
+
+ void over(int);
+ int over(long);
+
+ void test1() {
+ // okay: only one overload matches
+ invoke(&over);
+ }
+
+ void over(short);
+
+ void test2() {
+ // deduction failure: overload has multiple matches => undeduced context
+ invoke(&over); // expected-error {{no matching function for call to 'invoke'}}
+ }
+
+ template<class A, class B> B temp2(A);
+ void test3() {
+ // deduction failure: overload has template => undeduced context
+ // (even though partial application temp2<int> could in theory
+ // let us infer T=int)
+ invoke(&temp2); // expected-error {{no matching function for call to 'invoke'}}
+ invoke(&temp2<>); // expected-error {{no matching function for call to 'invoke'}}
+ invoke(&temp2<int>); // expected-error {{no matching function for call to 'invoke'}}
+
+ // okay: full template-id
+ invoke(&temp2<int, void>);
+
+ // overload failure
+ invoke(&temp2<int, int>); // expected-error {{no matching function for call to 'invoke'}}
+ }
+}
diff --git a/test/CXX/temp/temp.names/p4.cpp b/test/CXX/temp/temp.names/p4.cpp
new file mode 100644
index 000000000000..103a1bd537f8
--- /dev/null
+++ b/test/CXX/temp/temp.names/p4.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct meta {
+ template<typename U>
+ struct apply {
+ typedef U* type;
+ };
+};
+
+template<typename T, typename U>
+void f(typename T::template apply<U>::type);
+
+void test_f(int *ip) {
+ f<meta, int>(ip);
+}
diff --git a/test/CXX/temp/temp.res/temp.local/p1.cpp b/test/CXX/temp/temp.res/temp.local/p1.cpp
new file mode 100644
index 000000000000..ed534a462767
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.local/p1.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++0x [temp.local]p1:
+// Like normal (non-template) classes, class templates have an
+// injected-class-name (Clause 9). The injected-class-name can be used with
+// or without a template-argument-list. When it is used without
+// a template-argument-list, it is equivalent to the injected-class-name
+// followed by the template-parameters of the class template enclosed in <>.
+
+template <typename T> struct X0 {
+ X0();
+ ~X0();
+ X0 f(const X0&);
+};
+
+// Test non-type template parameters.
+template <int N1, const int& N2, const int* N3> struct X1 {
+ X1();
+ ~X1();
+ X1 f(const X1& x1a) { X1 x1b(x1a); return x1b; }
+};
+
+// When it is used with a template-argument-list, it refers to the specified
+// class template specialization, which could be the current specialization
+// or another specialization.
+// FIXME: Test this clause.
+
+int i = 42;
+int* iptr = &i;
+void test() {
+ X0<int> x0; (void)x0;
+ X1<42, i, iptr> x1; (void)x1;
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
index 3b5b5afa8ed9..88cfc5d7c397 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
@@ -18,7 +18,18 @@ namespace test1 {
};
typedef A<int> AA;
- template <> int AA::foo = 0; // expected-error {{cannot use typedef}}
- int AA::bar = 1; // expected-error {{cannot use typedef}} expected-error {{template specialization requires 'template<>'}}
+ template <> int AA::foo = 0;
+ int AA::bar = 1; // expected-error {{template specialization requires 'template<>'}}
int A<float>::bar = 2; // expected-error {{template specialization requires 'template<>'}}
+
+ template <> class A<double> {
+ public:
+ static int foo; // expected-note{{attempt to specialize}}
+ static int bar;
+ };
+
+ typedef A<double> AB;
+ template <> int AB::foo = 0; // expected-error{{extraneous 'template<>'}} \
+ // expected-error{{does not specialize}}
+ int AB::bar = 1;
}
diff --git a/test/CodeGen/2010-02-09-DbgSelf.m b/test/CodeGen/2010-02-09-DbgSelf.m
new file mode 100644
index 000000000000..e09adac161ec
--- /dev/null
+++ b/test/CodeGen/2010-02-09-DbgSelf.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -x objective-c -emit-llvm -g < %s | grep "\"self\", metadata"
+// Test to check that "self" argument is assigned a location.
+
+@interface Foo
+-(void) Bar: (int)x ;
+@end
+
+
+@implementation Foo
+-(void) Bar: (int)x
+{
+}
+@end
+
diff --git a/test/CodeGen/2010-02-15-Dbg-MethodStart.m b/test/CodeGen/2010-02-15-Dbg-MethodStart.m
new file mode 100644
index 000000000000..5186b20310a6
--- /dev/null
+++ b/test/CodeGen/2010-02-15-Dbg-MethodStart.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x objective-c -emit-llvm -g < %s | grep subprogram | grep "i32 9"
+// Test to check that subprogram start location.
+
+@interface Foo
+-(int) barMethod;
+@end
+
+@implementation Foo
+-(int) barMethod {
+ int i = 0;
+ int j = 1;
+ int k = 1;
+ return i + j + k;
+}
+@end
diff --git a/test/CodeGen/address-space-field1.c b/test/CodeGen/address-space-field1.c
index 61d88f9e7565..a81e08ebcaea 100644
--- a/test/CodeGen/address-space-field1.c
+++ b/test/CodeGen/address-space-field1.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -emit-llvm < %s -o - | FileCheck %s
// CHECK:%struct.S = type { i32, i32 }
// CHECK:define void @test_addrspace(%struct.S addrspace(1)* %p1, %struct.S addrspace(2)* %p2) nounwind
-// CHECK: [[p1addr:%.*]] = alloca %struct.S addrspace(1)* ; <%struct.S addrspace(1)**> [#uses=3]
-// CHECK: [[p2addr:%.*]] = alloca %struct.S addrspace(2)* ; <%struct.S addrspace(2)**> [#uses=3]
+// CHECK: [[p1addr:%.*]] = alloca %struct.S addrspace(1)*
+// CHECK: [[p2addr:%.*]] = alloca %struct.S addrspace(2)*
// CHECK: store %struct.S addrspace(1)* %p1, %struct.S addrspace(1)** [[p1addr]]
// CHECK: store %struct.S addrspace(2)* %p2, %struct.S addrspace(2)** [[p2addr]]
// CHECK: [[t0:%.*]] = load %struct.S addrspace(2)** [[p2addr]] ; <%struct.S addrspace(2)*> [#uses=1]
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index fb61b0f78497..d313a9b3310f 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -92,3 +92,64 @@ void f15(struct s7 a0) {}
// APCS-GNU: define arm_apcscc void @f16()
// AAPCS: define arm_aapcscc void @f16()
void f16(struct s8 a0) {}
+
+// APCS-GNU: define arm_apcscc i32 @f17()
+// AAPCS: define arm_aapcscc i32 @f17()
+struct s17 { short f0 : 13; char f1 : 4; };
+struct s17 f17(void) {}
+
+// APCS-GNU: define arm_apcscc i32 @f18()
+// AAPCS: define arm_aapcscc i32 @f18()
+struct s18 { short f0; char f1 : 4; };
+struct s18 f18(void) {}
+
+// APCS-GNU: define arm_apcscc void @f19(
+// APCS-GNU: struct.s19* noalias sret
+// AAPCS: define arm_aapcscc i32 @f19()
+struct s19 { int f0; struct s8 f1; };
+struct s19 f19(void) {}
+
+// APCS-GNU: define arm_apcscc void @f20(
+// APCS-GNU: struct.s20* noalias sret
+// AAPCS: define arm_aapcscc i32 @f20()
+struct s20 { struct s8 f1; int f0; };
+struct s20 f20(void) {}
+
+// APCS-GNU: define arm_apcscc i32 @f21()
+// AAPCS: define arm_aapcscc i32 @f21()
+struct s21 { struct {} f1; int f0 : 4; };
+struct s21 f21(void) {}
+
+// APCS-GNU: define arm_apcscc i16 @f22()
+// APCS-GNU: define arm_apcscc i32 @f23()
+// APCS-GNU: define arm_apcscc i64 @f24()
+// APCS-GNU: define arm_apcscc i128 @f25()
+// APCS-GNU: define arm_apcscc i64 @f26()
+// APCS-GNU: define arm_apcscc i128 @f27()
+// AAPCS: define arm_aapcscc i16 @f22()
+// AAPCS: define arm_aapcscc i32 @f23()
+// AAPCS: define arm_aapcscc void @f24({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f25({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f26({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f27({{.*}} noalias sret
+_Complex char f22(void) {}
+_Complex short f23(void) {}
+_Complex int f24(void) {}
+_Complex long long f25(void) {}
+_Complex float f26(void) {}
+_Complex double f27(void) {}
+
+// APCS-GNU: define arm_apcscc i16 @f28()
+// AAPCS: define arm_aapcscc i16 @f28()
+struct s28 { _Complex char f0; };
+struct s28 f28() {}
+
+// APCS-GNU: define arm_apcscc i32 @f29()
+// AAPCS: define arm_aapcscc i32 @f29()
+struct s29 { _Complex short f0; };
+struct s29 f29() {}
+
+// APCS-GNU: define arm_apcscc void @f30({{.*}} noalias sret
+// AAPCS: define arm_aapcscc void @f30({{.*}} noalias sret
+struct s30 { _Complex int f0; };
+struct s30 f30() {}
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
index 68bc73daec97..770ce766dfba 100644
--- a/test/CodeGen/attributes.c
+++ b/test/CodeGen/attributes.c
@@ -74,3 +74,10 @@ int t19(void) {
void t20(void) {
__builtin_abort();
}
+
+void (__attribute__((fastcall)) *fptr)(int);
+void t21(void) {
+ fptr(10);
+}
+// CHECK: [[FPTRVAR:%[a-z0-9]+]] = load void (i32)** @fptr
+// CHECK-NEXT: call x86_fastcallcc void [[FPTRVAR]](i32 10)
diff --git a/test/CodeGen/darwin-string-literals.c b/test/CodeGen/darwin-string-literals.c
index b665321730f2..87342956378b 100644
--- a/test/CodeGen/darwin-string-literals.c
+++ b/test/CodeGen/darwin-string-literals.c
@@ -2,13 +2,13 @@
// CHECK-LSB: @.str = private constant [8 x i8] c"string0\00"
// CHECK-LSB: @.str1 = private constant [8 x i8] c"string1\00"
-// CHECK-LSB: @.str2 = internal 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", section "__TEXT,__ustring", align 2
+// CHECK-LSB: @.str2 = internal 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 constant [8 x i8] c"string0\00"
// CHECK-MSB: @.str1 = private constant [8 x i8] c"string1\00"
-// CHECK-MSB: @.str2 = internal constant [36 x i8] c"\00h\00e\00l\00l\00o\00 !\92\00 &\03\00 !\90\00 \00w\00o\00r\00l\00d\00\00", section "__TEXT,__ustring", align 2
+// CHECK-MSB: @.str2 = internal 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";
const void *g1 = __builtin___CFStringMakeConstantString("string1");
diff --git a/test/CodeGen/debug-info-crash.c b/test/CodeGen/debug-info-crash.c
new file mode 100644
index 000000000000..e0c9dd415bbe
--- /dev/null
+++ b/test/CodeGen/debug-info-crash.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -g -S %s -o -
+
+// rdar://7590323
+typedef struct dispatch_queue_s *dispatch_queue_t;
+__attribute__((visibility("default")))
+extern struct dispatch_queue_s _dispatch_main_q;
+typedef struct dispatch_item_s *dispatch_item_t;
+typedef void (^dispatch_legacy_block_t)(dispatch_item_t);
+dispatch_item_t LEGACY_dispatch_call(dispatch_queue_t dq,
+ dispatch_legacy_block_t dispatch_block,
+ dispatch_legacy_block_t callback_block) {
+ dispatch_queue_t lq = _dispatch_queue_get_current() ?: (&_dispatch_main_q);
+ dispatch_async(dq, ^{
+ if (callback_block) {
+ dispatch_async(lq, ^{
+ }
+ );
+ }
+ }
+ );
+}
diff --git a/test/CodeGen/enum.c b/test/CodeGen/enum.c
index 771fc6b182e3..eab32c102518 100644
--- a/test/CodeGen/enum.c
+++ b/test/CodeGen/enum.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm-bc -o - | opt -std-compile-opts | llvm-dis | grep 'ret i32 6'
+// RUN: %clang_cc1 -triple i386-unknown-unknown -x c++ %s -emit-llvm-bc -o - | opt -std-compile-opts | llvm-dis | grep 'ret i32 7'
static enum { foo, bar = 1U } z;
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 8ddaa28eed03..3a1030a61b90 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -81,3 +81,11 @@ void f14(int a) {
// CHECK: {
void f15(void) {
}
+
+// PR5254
+// CHECK: define void @f16
+// CHECK: alignstack(16)
+// CHECK: {
+void __attribute__((force_align_arg_pointer)) f16(void) {
+}
+
diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c
index 838ccfb48c56..bea6df39f965 100644
--- a/test/CodeGen/stdcall-fastcall.c
+++ b/test/CodeGen/stdcall-fastcall.c
@@ -1,17 +1,33 @@
-// RUN: %clang_cc1 -emit-llvm < %s | grep 'fastcallcc' | count 4
-// RUN: %clang_cc1 -emit-llvm < %s | grep 'stdcallcc' | count 4
+// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s
void __attribute__((fastcall)) f1(void);
void __attribute__((stdcall)) f2(void);
void __attribute__((fastcall)) f3(void) {
+// CHECK: define x86_fastcallcc void @f3()
f1();
+// CHECK: call x86_fastcallcc void @f1()
}
void __attribute__((stdcall)) f4(void) {
+// CHECK: define x86_stdcallcc void @f4()
f2();
+// CHECK: call x86_stdcallcc void @f2()
}
+// PR5280
+void (__attribute__((fastcall)) *pf1)(void) = f1;
+void (__attribute__((stdcall)) *pf2)(void) = f2;
+void (__attribute__((fastcall)) *pf3)(void) = f3;
+void (__attribute__((stdcall)) *pf4)(void) = f4;
+
int main(void) {
f3(); f4();
+ // CHECK: call x86_fastcallcc void @f3()
+ // CHECK: call x86_stdcallcc void @f4()
+ pf1(); pf2(); pf3(); pf4();
+ // CHECK: call x86_fastcallcc void %{{.*}}()
+ // CHECK: call x86_stdcallcc void %{{.*}}()
+ // CHECK: call x86_fastcallcc void %{{.*}}()
+ // CHECK: call x86_stdcallcc void %{{.*}}()
return 0;
}
diff --git a/test/CodeGen/union.c b/test/CodeGen/union.c
index b40a405597ac..1883ca639b7e 100644
--- a/test/CodeGen/union.c
+++ b/test/CodeGen/union.c
@@ -39,3 +39,6 @@ int qfunc() {q buf; unsigned char* x = buf.x;}
union RR {_Bool a : 1;} RRU;
int RRF(void) {return RRU.a;}
+// PR6164
+typedef union T0 { unsigned int : 0; } T0;
+T0 t0;
diff --git a/test/CodeGenCXX/PR4890-debug-info-dtor.cpp b/test/CodeGenCXX/PR4890-debug-info-dtor.cpp
deleted file mode 100644
index bcaf1b96274e..000000000000
--- a/test/CodeGenCXX/PR4890-debug-info-dtor.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm-only -g %s
-struct X {
- ~X();
-};
-
-X::~X() { }
diff --git a/test/CodeGenCXX/alloca-align.cpp b/test/CodeGenCXX/alloca-align.cpp
new file mode 100644
index 000000000000..de6b34d06072
--- /dev/null
+++ b/test/CodeGenCXX/alloca-align.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+//
+// CHECK: alloca %struct.MemsetRange, align 16
+
+struct MemsetRange {
+ int Start, End;
+ unsigned Alignment;
+ int TheStores __attribute__((aligned(16)));
+};
+void foobar() {
+ (void) MemsetRange();
+}
diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp
index 7689c941e103..695f8f59defc 100644
--- a/test/CodeGenCXX/anonymous-namespaces.cpp
+++ b/test/CodeGenCXX/anonymous-namespaces.cpp
@@ -1,9 +1,25 @@
// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+int f();
+
namespace {
+ // CHECK: @_ZN12_GLOBAL__N_11bE = internal global i32 0
+ // CHECK: @_ZN12_GLOBAL__N_1L1cE = internal global i32 0
+ // CHECK: @_ZN12_GLOBAL__N_11D1dE = internal global i32 0
// CHECK: @_ZN12_GLOBAL__N_11aE = internal global i32 0
int a = 0;
+ int b = f();
+
+ static int c = f();
+
+ class D {
+ static int d;
+ };
+
+ int D::d = f();
+
// CHECK: define internal i32 @_ZN12_GLOBAL__N_13fooEv()
int foo() {
return 32;
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
index 1b214b77bee7..4c781c62b29f 100644
--- a/test/CodeGenCXX/attr.cpp
+++ b/test/CodeGenCXX/attr.cpp
@@ -1,39 +1,20 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -O0 -S %s -o %t.s
-// RUN: FileCheck --input-file=%t.s %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// CHECK: define i32 @_Z3foov() nounwind align 1024
int foo() __attribute__((aligned(1024)));
int foo() { }
-// CHECK:.align 10, 0x90
-// CHECK:.globl __Z3foov
-// CHECK:__Z3foov:
-
-
class C {
virtual void bar1() __attribute__((aligned(1)));
virtual void bar2() __attribute__((aligned(2)));
virtual void bar3() __attribute__((aligned(1024)));
} c;
-// CHECK:.align 1, 0x90
-// CHECK-NEXT:.globl __ZN1CC1Ev
-
+// CHECK: define void @_ZN1C4bar1Ev(%class.C* %this) nounwind align 2
void C::bar1() { }
-// CHECK:.align 1, 0x90
-// CHECK-NEXT:.globl __ZN1C4bar1Ev
-// CHECK-NEXT:__ZN1C4bar1Ev:
-
-
+// CHECK: define void @_ZN1C4bar2Ev(%class.C* %this) nounwind align 2
void C::bar2() { }
-// CHECK:.align 1, 0x90
-// CHECK-NEXT:.globl __ZN1C4bar2Ev
-// CHECK-NEXT:__ZN1C4bar2Ev:
-
-
+// CHECK: define void @_ZN1C4bar3Ev(%class.C* %this) nounwind align 1024
void C::bar3() { }
-
-// CHECK:.align 10, 0x90
-// CHECK-NEXT:.globl __ZN1C4bar3Ev
-// CHECK-NEXT:__ZN1C4bar3Ev:
diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp
index a1b7a09aa347..e435408aa840 100644
--- a/test/CodeGenCXX/condition.cpp
+++ b/test/CodeGenCXX/condition.cpp
@@ -64,7 +64,7 @@ void switch_destruct(int z) {
z = 19;
break;
}
- // CHECK: {{sw.epilog:|:4}}
+ // CHECK: {{sw.epilog:|:5}}
// CHECK: call void @_ZN16ConvertibleToIntD1Ev
// CHECK: store i32 20
z = 20;
@@ -74,18 +74,18 @@ int foo();
void while_destruct(int z) {
// CHECK: define void @_Z14while_destructi
- // CHECK: {{while.cond:|:1}}
+ // CHECK: {{while.cond:|:2}}
while (X x = X()) {
// CHECK: call void @_ZN1XC1Ev
- // CHECK: {{while.body:|:3}}
+ // CHECK: {{while.body:|:4}}
// CHECK: store i32 21
z = 21;
- // CHECK: {{while.cleanup:|:4}}
+ // CHECK: {{while.cleanup:|:5}}
// CHECK: call void @_ZN1XD1Ev
}
- // CHECK: {{while.end|:6}}
+ // CHECK: {{while.end|:7}}
// CHECK: store i32 22
z = 22;
}
@@ -94,16 +94,16 @@ void for_destruct(int z) {
// CHECK: define void @_Z12for_destruct
// CHECK: call void @_ZN1YC1Ev
for(Y y = Y(); X x = X(); ++z)
- // CHECK: {{for.cond:|:1}}
+ // CHECK: {{for.cond:|:2}}
// CHECK: call void @_ZN1XC1Ev
- // CHECK: {{for.body:|:3}}
+ // CHECK: {{for.body:|:4}}
// CHECK: store i32 23
z = 23;
- // CHECK: {{for.inc:|:4}}
- // CHECK: br label %{{for.cond.cleanup|7}}
- // CHECK: {{for.cond.cleanup:|:7}}
+ // CHECK: {{for.inc:|:5}}
+ // CHECK: br label %{{for.cond.cleanup|8}}
+ // CHECK: {{for.cond.cleanup:|:8}}
// CHECK: call void @_ZN1XD1Ev
- // CHECK: {{for.end:|:9}}
+ // CHECK: {{for.end:|:10}}
// CHECK: call void @_ZN1YD1Ev
// CHECK: store i32 24
z = 24;
diff --git a/test/CodeGenCXX/conditional-temporaries.cpp b/test/CodeGenCXX/conditional-temporaries.cpp
index 0eac10b43cfd..d5382872f9d9 100644
--- a/test/CodeGenCXX/conditional-temporaries.cpp
+++ b/test/CodeGenCXX/conditional-temporaries.cpp
@@ -1,28 +1,55 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -O3 | FileCheck %s
-struct I {
+namespace {
+
+static int ctorcalls;
+static int dtorcalls;
+
+struct A {
+ A() : i(0) { ctorcalls++; }
+ ~A() { dtorcalls++; }
int i;
- I();
- ~I();
+
+ friend const A& operator<<(const A& a, int n) {
+ return a;
+ }
};
-void g(int);
+void g(int) { }
+void g(const A&) { }
-volatile int i;
+void f1(bool b) {
+ g(b ? A().i : 0);
+ g(b || A().i);
+ g(b && A().i);
+ g(b ? A() << 1 : A() << 2);
+}
-void f1() {
- // CHECK: call void @_ZN1IC1Ev
- g(i ? I().i : 0);
- // CHECK: call void @_Z1gi
- // CHECK: call void @_ZN1ID1Ev
+struct Checker {
+ Checker() {
+ f1(true);
+ f1(false);
+ }
+};
- // CHECK: call void @_ZN1IC1Ev
- g(i || I().i);
- // CHECK: call void @_Z1gi
- // CHECK: call void @_ZN1ID1Ev
+Checker c;
+
+}
+
+// CHECK: define i32 @_Z12getCtorCallsv()
+int getCtorCalls() {
+ // CHECK: ret i32 5
+ return ctorcalls;
+}
+
+// CHECK: define i32 @_Z12getDtorCallsv()
+int getDtorCalls() {
+ // CHECK: ret i32 5
+ return dtorcalls;
+}
- // CHECK: call void @_ZN1IC1Ev
- g(i && I().i);
- // CHECK: call void @_Z1gi
- // CHECK: call void @_ZN1ID1Ev
+// CHECK: define zeroext i1 @_Z7successv()
+bool success() {
+ // CHECK: ret i1 true
+ return ctorcalls == dtorcalls;
}
diff --git a/test/CodeGenCXX/const-global-linkage.cpp b/test/CodeGenCXX/const-global-linkage.cpp
index f88bc808a7c6..d0a055b49495 100644
--- a/test/CodeGenCXX/const-global-linkage.cpp
+++ b/test/CodeGenCXX/const-global-linkage.cpp
@@ -3,11 +3,11 @@
const int x = 10;
const int y = 20;
// CHECK-NOT: @x
-// CHECK: @y = internal constant i32 20
+// CHECK: @_ZL1y = internal constant i32 20
const int& b() { return y; }
const char z1[] = "asdf";
const char z2[] = "zxcv";
// CHECK-NOT: @z1
-// CHECK: @z2 = internal constant
+// CHECK: @_ZL2z2 = internal constant
const char* b2() { return z2; }
diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp
index 874b5f64e2ba..9cfce7ace86b 100644
--- a/test/CodeGenCXX/const-init.cpp
+++ b/test/CodeGenCXX/const-init.cpp
@@ -2,11 +2,11 @@
// CHECK: @a = global i32 10
int a = 10;
-// CHECK: @ar = global i32* @a
+// CHECK: @ar = constant i32* @a
int &ar = a;
void f();
-// CHECK: @fr = global void ()* @_Z1fv
+// CHECK: @fr = constant void ()* @_Z1fv
void (&fr)() = f;
struct S { int& a; };
diff --git a/test/CodeGenCXX/conversion-function.cpp b/test/CodeGenCXX/conversion-function.cpp
index fccb6f094e07..e2f8f7e17b93 100644
--- a/test/CodeGenCXX/conversion-function.cpp
+++ b/test/CodeGenCXX/conversion-function.cpp
@@ -2,7 +2,7 @@
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
-
+// XFAIL: *
extern "C" int printf(...);
struct S {
operator int();
diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp
index cb6e830a49e0..6bb9533a477e 100644
--- a/test/CodeGenCXX/debug-info.cpp
+++ b/test/CodeGenCXX/debug-info.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm-only -g
+// RUN: %clang_cc1 -emit-llvm-only -g %s
template<typename T> struct Identity {
typedef T Type;
};
@@ -24,3 +24,29 @@ namespace EmptyNameCrash {
typedef struct { A x; } B;
B x;
}
+
+// PR4890
+namespace PR4890 {
+ struct X {
+ ~X();
+ };
+
+ X::~X() { }
+}
+
+namespace VirtualDtor {
+ struct Y {
+ virtual ~Y();
+ };
+
+ Y::~Y() { }
+}
+
+namespace VirtualBase {
+ struct A { };
+ struct B : virtual A { };
+
+ void f() {
+ B b;
+ }
+}
diff --git a/test/CodeGenCXX/default-destructor-synthesis.cpp b/test/CodeGenCXX/default-destructor-synthesis.cpp
index 71167a204fbb..fac5cc01f6b7 100644
--- a/test/CodeGenCXX/default-destructor-synthesis.cpp
+++ b/test/CodeGenCXX/default-destructor-synthesis.cpp
@@ -1,58 +1,36 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -O0 -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -O0 -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 -input-file=%t-32.s %s
-
-extern "C" int printf(...);
-
-int count = 1;
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -O2 -o - | FileCheck %s
+static int count = 0;
struct S {
- S() : iS(count++), fS(1.23) {};
- ~S(){printf("S::~S(%d, %f)\n", iS, fS); };
- int iS;
- float fS;
+ S() { count++; }
+ ~S() { count--; }
};
-struct Q {
- Q() : iQ(count++), dQ(2.34) {};
- ~Q(){printf("Q::~Q(%d, %f)\n", iQ, dQ); };
- int iQ;
- double dQ;
+struct P {
+ P() { count++; }
+ ~P() { count--; }
};
-struct P {
- P() : fP(3.45) , iP(count++) {};
- ~P(){printf("P::~P(%d, %f)\n", iP, fP); };
- float fP;
- int iP;
+struct Q {
+ Q() { count++; }
+ ~Q() { count--; }
};
-struct M : Q, P {
+struct M : Q, P {
S s;
-
Q q;
-
- P p;
-
- P p_arr[3];
-
- Q q_arr[2][3];
-
+ P p;
+ P p_arr[3];
+ Q q_arr[2][3];
};
-
-M gm;
-
-int main() {M m1;}
-
-// CHECK-LP64: .globl __ZN1MD1Ev
-// CHECK-LP64-NEXT: .weak_definition __ZN1MD1Ev
-// CHECK-LP64-NEXT: __ZN1MD1Ev:
-// CHECK-LP64: callq __ZN1MC1Ev
-// CHECK-LP64: callq __ZN1MD1Ev
-
-// CHECK-LP32: .globl __ZN1MD1Ev
-// CHECK-LP32-NEXT: .weak_definition __ZN1MD1Ev
-// CHECK-LP32-NEXT:__ZN1MD1Ev:
-// CHECK-LP32: call L__ZN1MC1Ev
-// CHECK-LP32: call L__ZN1MD1Ev
+
+// CHECK: define i32 @_Z1fv() nounwind
+int f() {
+ {
+ count = 1;
+ M a;
+ }
+
+ // CHECK: ret i32 1
+ return count;
+}
diff --git a/test/CodeGenCXX/deferred-global-init.cpp b/test/CodeGenCXX/deferred-global-init.cpp
index 570147905548..802042dd8b90 100644
--- a/test/CodeGenCXX/deferred-global-init.cpp
+++ b/test/CodeGenCXX/deferred-global-init.cpp
@@ -5,7 +5,7 @@ extern void* foo;
static void* const a = foo;
void* bar() { return a; }
-// CHECK: @a = internal global i8* null
+// CHECK: @_ZL1a = internal global i8* null
// CHECK: define internal void @__cxx_global_var_init
// CHECK: load i8** @foo
diff --git a/test/CodeGenCXX/derived-to-base.cpp b/test/CodeGenCXX/derived-to-base.cpp
index 45728b7c0122..e44fdc5ed2de 100644
--- a/test/CodeGenCXX/derived-to-base.cpp
+++ b/test/CodeGenCXX/derived-to-base.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o -
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
struct A {
void f();
@@ -14,3 +14,23 @@ void f() {
b.f();
}
+
+// CHECK: define %struct.B* @_Z1fP1A(%struct.A* %a) nounwind
+B *f(A *a) {
+ // CHECK-NOT: br label
+ // CHECK: ret %struct.B*
+ return static_cast<B*>(a);
+}
+
+// PR5965
+namespace PR5965 {
+
+// CHECK: define %struct.A* @_ZN6PR59651fEP1B(%struct.B* %b) nounwind
+A *f(B* b) {
+ // CHECK-NOT: br label
+ // CHECK: ret %struct.A*
+ return b;
+}
+
+}
+
diff --git a/test/CodeGenCXX/dyncast.cpp b/test/CodeGenCXX/dyncast.cpp
index 054b972bb158..127cdd89683d 100644
--- a/test/CodeGenCXX/dyncast.cpp
+++ b/test/CodeGenCXX/dyncast.cpp
@@ -1,5 +1,6 @@
// 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
+// XFAIL: win32
#include <typeinfo>
@@ -69,14 +70,7 @@ void test1() {
// 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: br i1 false, label %[[castnull:.*]], label %[[castnotnull:.*]]
-// CHECK-LL: [[castnotnull]]
-// CHECK-LL-NEXT: br label %[[castend:.*]]
-// CHECK-LL: [[castnull]]
-// CHECK-LL-NEXT: br label %[[castend]]
-// CHECK-LL: [[castend]]
-// CHECK-LL-NEXT: [[v0:%.*]] = phi %class.test1_A* [ bitcast (%class.test1_D* @test1_d to %class.test1_A*), %[[castnotnull]] ], [ null, %[[castnull]] ]
-// CHECK-LL-NEXT: store %class.test1_A* [[v0]], %class.test1_A** [[bp]]
+// 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**)
@@ -333,23 +327,10 @@ void test1() {
// 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: br i1 false, label %[[castnull116:.*]], label %[[castnotnull115:.*]]
-// CHECK-LL: [[castnotnull115]]
-// CHECK-LL-NEXT: br label %[[castend117:.*]]
-// CHECK-LL: [[castnull116]]
-// CHECK-LL-NEXT: br label %[[castend117]]
-// CHECK-LL: [[castend117]]
-// CHECK-LL-NEXT: [[v62:%.*]] = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %[[castnotnull115]] ], [ null, %[[castnull116]] ]
-// CHECK-LL-NEXT: store %class.test1_E* [[v62]], %class.test1_E** [[ep]]
+// 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: br i1 false, label %[[castnull120:.*]], label %[[castnotnull119:.*]]
-// CHECK-LL: [[castnotnull119]]
-// CHECK-LL-NEXT: br label %[[castend121:.*]]
-// CHECK-LL: [[castnull120]]
-// CHECK-LL-NEXT: br label %[[castend121]]
-// CHECK-LL: [[castend121]]
-// CHECK-LL-NEXT: [[v63:%.*]] = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %[[castnotnull119]] ], [ null, %[[castnull120]] ]
-// CHECK-LL-NEXT: [[cmp122:%.*]] = icmp eq %class.test1_E* [[tmp118]], [[v63]]
+// CHECK-LL-NEXT: [[cmp122:%.*]] = icmp eq %class.test1_E* [[tmp118]], bitcast (%class.test1_F* @test1_f to %class.test1_E*) ; <i1> [#uses=1]
+
// 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)
diff --git a/test/CodeGenCXX/extern-c.cpp b/test/CodeGenCXX/extern-c.cpp
index 427a45aebb1e..ca5cd7372cad 100644
--- a/test/CodeGenCXX/extern-c.cpp
+++ b/test/CodeGenCXX/extern-c.cpp
@@ -10,4 +10,7 @@ extern int b;
// RUN: grep "@_ZN3foo1cE = global i32" %t | count 1
int c = 5;
+// RUN: not grep "@_ZN3foo1dE" %t
+extern "C" struct d;
+
}
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index b375aef4c8e0..b60e056d708f 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -7,6 +7,12 @@ struct A {
struct B { B(); ~B(); };
+struct C { void *field; };
+
+struct D { ~D(); };
+
+// CHECK: @c = global %struct.C zeroinitializer, align 8
+
// CHECK: call void @_ZN1AC1Ev(%struct.A* @a)
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
A a;
@@ -14,3 +20,12 @@ A a;
// CHECK: call void @_ZN1BC1Ev(%struct.A* @b)
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @b, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
B b;
+
+// PR6205: this should not require a global initializer
+// CHECK-NOT: call void @_ZN1CC1Ev(%struct.C* @c)
+C c;
+
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+D d;
+
+// CHECK: define internal void @__cxx_global_initialization() {
diff --git a/test/CodeGenCXX/global-llvm-constant.cpp b/test/CodeGenCXX/global-llvm-constant.cpp
index e799231ab744..ef1dcf0c59bf 100644
--- a/test/CodeGenCXX/global-llvm-constant.cpp
+++ b/test/CodeGenCXX/global-llvm-constant.cpp
@@ -7,4 +7,4 @@ struct A {
const A x;
-// CHECK: @x = internal global
+// CHECK: @_ZL1x = internal global
diff --git a/test/CodeGenCXX/internal-linkage.cpp b/test/CodeGenCXX/internal-linkage.cpp
new file mode 100644
index 000000000000..1ae0f08f86ee
--- /dev/null
+++ b/test/CodeGenCXX/internal-linkage.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+struct Global { };
+template<typename T> struct X { };
+
+
+namespace {
+ struct Anon { };
+
+ // CHECK: @_ZN12_GLOBAL__N_15anon0E = internal global
+ Global anon0;
+}
+
+// CHECK: @anon1 = internal global
+Anon anon1;
+
+// CHECK: @anon2 = internal global
+X<Anon> anon2;
+
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
new file mode 100644
index 000000000000..cdad39852c9f
--- /dev/null
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+template < bool condition, typename T = void >
+struct enable_if { typedef T type; };
+
+template< typename T >
+struct enable_if< false, T > {};
+
+// PR5876
+namespace Casts {
+ template< unsigned O >
+ void implicit(typename enable_if< O <= 4 >::type* = 0) {
+ }
+
+ template< unsigned O >
+ void cstyle(typename enable_if< O <= (unsigned)4 >::type* = 0) {
+ }
+
+ template< unsigned O >
+ void functional(typename enable_if< O <= unsigned(4) >::type* = 0) {
+ }
+
+ template< unsigned O >
+ void static_(typename enable_if< O <= static_cast<unsigned>(4) >::type* = 0) {
+ }
+
+ // FIXME: Test const_cast, reinterpret_cast, dynamic_cast, which are
+ // a bit harder to use in template arguments.
+ template <unsigned N> struct T {};
+
+ template <int N> T<N> f() { return T<N>(); }
+
+ // CHECK: define void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE
+ template void implicit<4>(void*);
+ // CHECK: define void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ template void cstyle<4>(void*);
+ // CHECK: define void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ template void functional<4>(void*);
+ // CHECK: define void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE
+ template void static_<4>(void*);
+
+ // CHECK: define i64 @_ZN5Casts1fILi6EEENS_1TIXT_EEEv
+ template T<6> f<6>();
+}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 5947587eec32..07183782e75e 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -fblocks | FileCheck %s
-
struct X { };
struct Y { };
@@ -9,6 +8,9 @@ struct Y { };
// CHECK: @_ZZN1N1gEvE1a = internal global
// CHECK: @_ZGVZN1N1gEvE1a = internal global
+//CHECK: @pr5966_i = external global
+//CHECK: @_ZL8pr5966_i = internal global
+
// CHECK: define zeroext i1 @_ZplRK1YRA100_P1X
bool operator+(const Y&, X* (&xs)[100]) { return false; }
@@ -310,7 +312,67 @@ template class Alloc<char>;
// CHECK: define void @_Z1fU13block_pointerFiiiE
void f(int (^)(int, int)) { }
-// PR5869
-// CHECK: define internal void @_ZL2f2v
-static void f2() {}
-void f3() { f2(); }
+void pr5966_foo() {
+ extern int pr5966_i;
+ pr5966_i = 0;
+}
+
+static int pr5966_i;
+
+void pr5966_bar() {
+ pr5966_i = 0;
+}
+
+namespace test0 {
+ int ovl(int x);
+ char ovl(double x);
+
+ template <class T> void f(T, char (&buffer)[sizeof(ovl(T()))]) {}
+
+ void test0() {
+ char buffer[1];
+ f(0.0, buffer);
+ }
+ // CHECK: define void @_ZN5test05test0Ev()
+ // CHECK: define linkonce_odr void @_ZN5test01fIdEEvT_RAszcl3ovlcvS1__EE_c(
+
+ void test1() {
+ char buffer[sizeof(int)];
+ f(1, buffer);
+ }
+ // CHECK: define void @_ZN5test05test1Ev()
+ // CHECK: define linkonce_odr void @_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c(
+
+ template <class T> void g(char (&buffer)[sizeof(T() + 5.0f)]) {}
+ void test2() {
+ char buffer[sizeof(float)];
+ g<float>(buffer);
+ }
+ // CHECK: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40A00000E_c(
+
+ template <class T> void h(char (&buffer)[sizeof(T() + 5.0)]) {}
+ void test3() {
+ char buffer[sizeof(double)];
+ h<float>(buffer);
+ }
+ // CHECK: define linkonce_odr void @_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c(
+
+ template <class T> void j(char (&buffer)[sizeof(T().buffer)]) {}
+ struct A { double buffer[128]; };
+ void test4() {
+ char buffer[1024];
+ j<A>(buffer);
+ }
+ // CHECK: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszmecvT__E6buffer_c(
+}
+
+namespace test1 {
+ template<typename T> struct X { };
+ template<template<class> class Y, typename T> void f(Y<T>) { }
+ // CHECK: define void @_ZN5test11fINS_1XEiEEvT_IT0_E
+ template void f(X<int>);
+}
+
+// CHECK: define internal void @_Z27functionWithInternalLinkagev()
+static void functionWithInternalLinkage() { }
+void g() { functionWithInternalLinkage(); }
diff --git a/test/CodeGenCXX/member-function-pointer-calls.cpp b/test/CodeGenCXX/member-function-pointer-calls.cpp
new file mode 100644
index 000000000000..e1f2eb78d414
--- /dev/null
+++ b/test/CodeGenCXX/member-function-pointer-calls.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s
+struct A {
+ virtual int vf1() { return 1; }
+ virtual int vf2() { return 2; }
+};
+
+int f(A* a, int (A::*fp)()) {
+ return (a->*fp)();
+}
+
+// CHECK: define i32 @_Z2g1v()
+int g1() {
+ A a;
+
+ // CHECK: call i32 @_ZN1A3vf1Ev
+ // CHECK-NEXT: ret i32
+ return f(&a, &A::vf1);
+}
+
+int g2() {
+ A a;
+
+ // CHECK: call i32 @_ZN1A3vf2Ev
+ // CHECK-NEXT: ret i32
+ return f(&a, &A::vf2);
+}
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index e1353a72b396..f7c445b1cb10 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s
-struct A { int a; void f(); virtual void vf(); };
+struct A { int a; void f(); virtual void vf1(); virtual void vf2(); };
struct B { int b; virtual void g(); };
struct C : B, A { };
@@ -9,17 +9,20 @@ void (A::*volatile vpa)();
void (B::*pb)();
void (C::*pc)();
-// CHECK: @pa2 = global %0 { i64 ptrtoint (void ()* @_ZN1A1fEv to i64), i64 0 }, align 8
+// CHECK: @pa2 = global %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8
void (A::*pa2)() = &A::f;
// CHECK: @pa3 = global %0 { i64 1, i64 0 }, align 8
-void (A::*pa3)() = &A::vf;
+void (A::*pa3)() = &A::vf1;
-// CHECK: @pc2 = global %0 { i64 ptrtoint (void ()* @_ZN1A1fEv to i64), i64 16 }, align 8
+// CHECK: @pa4 = global %0 { i64 9, i64 0 }, align 8
+void (A::*pa4)() = &A::vf2;
+
+// CHECK: @pc2 = global %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8
void (C::*pc2)() = &C::f;
// CHECK: @pc3 = global %0 { i64 1, i64 0 }, align 8
-void (A::*pc3)() = &A::vf;
+void (A::*pc3)() = &A::vf1;
void f() {
// CHECK: store i64 0, i64* getelementptr inbounds (%0* @pa, i32 0, i32 0)
@@ -43,7 +46,7 @@ void f() {
void f2() {
// CHECK: [[pa2ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa2, i32 0, i32 0
- // CHECK: store i64 ptrtoint (void ()* @_ZN1A1fEv to i64), i64* [[pa2ptr]]
+ // CHECK: store i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64* [[pa2ptr]]
// CHECK: [[pa2adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa2, i32 0, i32 1
// CHECK: store i64 0, i64* [[pa2adj]]
void (A::*pa2)() = &A::f;
@@ -52,7 +55,13 @@ void f2() {
// CHECK: store i64 1, i64* [[pa3ptr]]
// CHECK: [[pa3adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 1
// CHECK: store i64 0, i64* [[pa3adj]]
- void (A::*pa3)() = &A::vf;
+ void (A::*pa3)() = &A::vf1;
+
+ // CHECK: [[pa4ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 0
+ // CHECK: store i64 9, i64* [[pa4ptr]]
+ // CHECK: [[pa4adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 1
+ // CHECK: store i64 0, i64* [[pa4adj]]
+ void (A::*pa4)() = &A::vf2;
}
void f3(A *a, A &ar) {
@@ -150,3 +159,17 @@ namespace MemberPointerImpCast {
(obj->*method)();
}
}
+
+// PR6258
+namespace PR6258 {
+
+ struct A {
+ void f(bool);
+ };
+
+ void (A::*pf)(bool) = &A::f;
+
+ void f() {
+ void (A::*pf)(bool) = &A::f;
+ }
+}
diff --git a/test/CodeGenCXX/member-initializers.cpp b/test/CodeGenCXX/member-initializers.cpp
new file mode 100644
index 000000000000..81dcee7e407a
--- /dev/null
+++ b/test/CodeGenCXX/member-initializers.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck %s
+
+struct A {
+ virtual int f() { return 1; }
+};
+
+struct B : A {
+ B() : i(f()) { }
+
+ virtual int f() { return 2; }
+
+ int i;
+};
+
+// CHECK: define i32 @_Z1fv() nounwind
+int f() {
+ B b;
+
+ // CHECK: call i32 @_ZN1B1fEv
+ return b.i;
+}
+
+// Test that we don't try to fold the default value of j when initializing i.
+// CHECK: define i32 @_Z9test_foldv() nounwind
+int test_fold() {
+ struct A {
+ A(const int j = 1) : i(j) { }
+ int i;
+ };
+
+ // CHECK: ret i32 2
+ return A(2).i;
+}
+
diff --git a/test/CodeGenCXX/member-pointer-cast.cpp b/test/CodeGenCXX/member-pointer-cast.cpp
deleted file mode 100644
index 4937b037de53..000000000000
--- a/test/CodeGenCXX/member-pointer-cast.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s
-
-struct A { int a; };
-struct B { int b; };
-struct C : B, A { };
-
-int A::*pa;
-int C::*pc;
-
-void f() {
- // CHECK: store i64 -1, i64* @pa
- pa = 0;
-
- // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = add i64 {{.*}}, 4
- // CHECK: store i64 [[ADJ]], i64* @pc
- pc = pa;
-
- // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = sub i64 {{.*}}, 4
- // CHECK: store i64 [[ADJ]], i64* @pa
- pa = static_cast<int A::*>(pc);
-}
diff --git a/test/CodeGenCXX/member-pointers-zero-init.cpp b/test/CodeGenCXX/member-pointers-zero-init.cpp
deleted file mode 100644
index 18a2ead1ede5..000000000000
--- a/test/CodeGenCXX/member-pointers-zero-init.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o %t -triple=x86_64-apple-darwin9
-
-struct A {
- int i;
-};
-
-// RUN: grep "@a = global i64 -1" %t
-int A::* a;
-
-// RUN: grep "@aa = global \[2 x i64\] \[i64 -1, i64 -1\]" %t
-int A::* aa[2];
-
-// RUN: grep "@aaa = global \[2 x \[2 x i64\]\] \[\[2 x i64\] \[i64 -1, i64 -1\], \[2 x i64\] \[i64 -1, i64 -1\]\]" %t
-int A::* aaa[2][2];
-
-// RUN: grep "@b = global i64 -1" %t
-int A::* b = 0;
-
-void f() {
- // RUN: grep "%.* = icmp ne i64 %.*, -1" %t | count 2
- if (a) { }
- if (a != 0) { }
-
- // RUN: grep "%.* = icmp ne i64 -1, %.*" %t | count 1
- if (0 != a) { }
-
- // RUN: grep "%.* = icmp eq i64 %.*, -1" %t | count 1
- if (a == 0) { }
-
- // RUN: grep "%.* = icmp eq i64 -1, %.*" %t | count 1
- if (0 == a) { }
-
-}
-
diff --git a/test/CodeGenCXX/no-exceptions.cpp b/test/CodeGenCXX/no-exceptions.cpp
new file mode 100644
index 000000000000..da672c43f8d4
--- /dev/null
+++ b/test/CodeGenCXX/no-exceptions.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+void g();
+
+// CHECK: define void @_Z1fv() nounwind
+void f() throw (int) {
+
+ // CHECK-NOT: invoke void @_Z1gv
+ g();
+ // CHECK: call void @_Z1gv()
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
new file mode 100644
index 000000000000..d96eb03b8d82
--- /dev/null
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s
+
+struct A { int a; int b; };
+struct B { int b; };
+struct C : B, A { };
+
+// Zero init.
+namespace ZeroInit {
+ // CHECK: @_ZN8ZeroInit1aE = global i64 -1
+ int A::* a;
+
+ // CHECK: @_ZN8ZeroInit2aaE = global [2 x i64] [i64 -1, i64 -1]
+ int A::* aa[2];
+
+ // CHECK: @_ZN8ZeroInit3aaaE = global [2 x [2 x i64]] {{\[}}[2 x i64] [i64 -1, i64 -1], [2 x i64] [i64 -1, i64 -1]]
+ int A::* aaa[2][2];
+
+ // CHECK: @_ZN8ZeroInit1bE = global i64 -1,
+ int A::* b = 0;
+
+ // CHECK: @_ZN8ZeroInit2saE = global %struct.anon { i64 -1 }
+ struct {
+ int A::*a;
+ } sa;
+
+ // CHECK: @_ZN8ZeroInit3ssaE =
+ // CHECK: [2 x i64] [i64 -1, i64 -1]
+ struct {
+ int A::*aa[2];
+ } ssa[2];
+
+ // CHECK: @_ZN8ZeroInit2ssE = global %1 { %struct.anon { i64 -1 } }
+ struct {
+ struct {
+ int A::*pa;
+ } s;
+ } ss;
+}
+
+// PR5674
+namespace PR5674 {
+ // CHECK: @_ZN6PR56742pbE = global i64 4
+ int A::*pb = &A::b;
+}
+
+// Casts.
+namespace Casts {
+
+int A::*pa;
+int C::*pc;
+
+void f() {
+ // CHECK: store i64 -1, i64* @_ZN5Casts2paE
+ pa = 0;
+
+ // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = add i64 {{.*}}, 4
+ // CHECK: store i64 [[ADJ]], i64* @_ZN5Casts2pcE
+ pc = pa;
+
+ // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = sub i64 {{.*}}, 4
+ // CHECK: store i64 [[ADJ]], i64* @_ZN5Casts2paE
+ pa = static_cast<int A::*>(pc);
+}
+
+}
+
+// Comparisons
+namespace Comparisons {
+ void f() {
+ int A::*a;
+
+ // CHECK: icmp ne i64 {{.*}}, -1
+ if (a) { }
+
+ // CHECK: icmp ne i64 {{.*}}, -1
+ if (a != 0) { }
+
+ // CHECK: icmp ne i64 -1, {{.*}}
+ if (0 != a) { }
+
+ // CHECK: icmp eq i64 {{.*}}, -1
+ if (a == 0) { }
+
+ // CHECK: icmp eq i64 -1, {{.*}}
+ if (0 == a) { }
+ }
+}
diff --git a/test/CodeGenCXX/reference-init.cpp b/test/CodeGenCXX/reference-init.cpp
index 6c2c6a301681..9469c84eb5d0 100644
--- a/test/CodeGenCXX/reference-init.cpp
+++ b/test/CodeGenCXX/reference-init.cpp
@@ -14,3 +14,11 @@ namespace PR5911 {
int iarr[] = { 1 };
int test() { return f(iarr); }
}
+
+// radar 7574896
+struct Foo { int foo; };
+Foo& ignoreSetMutex = *(new Foo);
+
+// Binding to a bit-field that requires a temporary.
+struct { int bitfield : 3; } s = { 3 };
+const int &s2 = s.bitfield;
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 6bec8bd8c384..39b5909fb9a4 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -38,6 +38,8 @@ void test_bool() {
bool_reference_return() = true;
a = bool_reference_return();
+
+ struct { const bool& b; } b = { true };
}
void test_scalar() {
@@ -54,6 +56,8 @@ void test_scalar() {
int_reference_return() = 10;
a = int_reference_return();
+
+ struct { const int& a; } agg = { 10 };
}
void test_complex() {
@@ -64,6 +68,8 @@ void test_complex() {
complex_int_reference_return() = 10i;
a = complex_int_reference_return();
+
+ struct { const _Complex int &a; } agg = { 10i };
}
void test_aggregate() {
@@ -74,6 +80,8 @@ void test_aggregate() {
aggregate_reference_return().a = 10;
c = aggregate_reference_return();
+
+ struct { const C& a; } agg = { C() };
}
int& reference_return() {
diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp
index 53a1d5e4c450..b3a2af2aafe3 100644
--- a/test/CodeGenCXX/static-data-member.cpp
+++ b/test/CodeGenCXX/static-data-member.cpp
@@ -1,4 +1,14 @@
// RUN: %clang_cc1 -emit-llvm -o - %s
+
+// CHECK: @_ZN1A1aE = constant i32 10
+
+// PR5564.
+struct A {
+ static const int a = 10;
+};
+
+const int A::a;
+
struct S {
static int i;
};
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index cbd90e789406..a67d137d6a1d 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -1,4 +1,10 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
+
+// CHECK: @_ZZ2h2vE1i = weak global i32 0
+// CHECK: @_ZGVZ2h2vE1i = weak global i64 0
+
struct A {
A();
~A();
@@ -15,3 +21,16 @@ void g() {
// CHECK: call void @_ZN1AC1Ev(
static A& a = *new A;
}
+
+int a();
+void h() {
+ static const int i = a();
+}
+
+inline void h2() {
+ static int i = a();
+}
+
+void h3() {
+ h2();
+}
diff --git a/test/CodeGenCXX/temp-order.cpp b/test/CodeGenCXX/temp-order.cpp
index 05a9aed2defa..341cd0ca134a 100644
--- a/test/CodeGenCXX/temp-order.cpp
+++ b/test/CodeGenCXX/temp-order.cpp
@@ -129,10 +129,30 @@ static unsigned f6() {
return tt.Product;
}
+// 5, 2
+static unsigned f7() {
+ TempTracker tt;
+ {
+ (void)((A(tt, 2, false) && A(tt, 3, false)) || A(tt, 5, false));
+ }
+ return tt.Product;
+}
+
+// 5, 2
+static unsigned f8() {
+ TempTracker tt;
+
+ {
+ (void)((A(tt, 2) || A(tt, 3)) && A(tt, 5));
+ }
+ return tt.Product;
+}
+
extern "C" void error();
extern "C" void print(const char *Name, unsigned N);
-#define ORDER3(a, b, c) (pow(a, 1) * pow(b, 2) * pow(c, 3))
+#define ORDER2(a, b) (pow(a, 1) * pow(b, 2))
+#define ORDER3(a, b, c) (ORDER2(a, b) * pow(c, 3))
#define ORDER4(a, b, c, d) (ORDER3(a, b, c) * pow(d, 4))
#define ORDER5(a, b, c, d, e) (ORDER4(a, b, c, d) * pow(e, 5))
#define ORDER6(a, b, c, d, e, f) (ORDER5(a, b, c, d, e) * pow(f, 6))
@@ -171,6 +191,16 @@ void test() {
print("f6", f6());
if (f6() != ORDER6(3, 7, 11, 5, 13, 2))
error();
+
+// CHECK: call void @print(i8* {{.*}}, i32 20)
+ print("f7", f7());
+ if (f7() != ORDER2(5, 2))
+ error();
+
+// CHECK: call void @print(i8* {{.*}}, i32 20)
+ print("f8", f8());
+ if (f8() != ORDER2(5, 2))
+ error();
}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 611781886b3e..3b624afd0ad1 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -249,3 +249,42 @@ namespace PR5867 {
g2(17);
}
}
+
+// PR6199
+namespace PR6199 {
+ struct A { ~A(); };
+
+ struct B { operator A(); };
+
+ // CHECK: define void @_ZN6PR61992f2IiEENS_1AET_
+ template<typename T> A f2(T) {
+ B b;
+ // CHECK: call void @_ZN6PR61991BcvNS_1AEEv
+ // CHECK-NEXT: ret void
+ return b;
+ }
+
+ template A f2<int>(int);
+
+}
+
+namespace T12 {
+
+struct A {
+ A();
+ ~A();
+ int f();
+};
+
+int& f(int);
+
+// CHECK: define void @_ZN3T121gEv
+void g() {
+ // CHECK: call void @_ZN3T121AC1Ev
+ // CHECK-NEXT: call i32 @_ZN3T121A1fEv(
+ // CHECK-NEXT: call i32* @_ZN3T121fEi(
+ // CHECK-NEXT: call void @_ZN3T121AD1Ev(
+ int& i = f(A().f());
+}
+
+}
diff --git a/test/CodeGenCXX/threadsafe-statics.cpp b/test/CodeGenCXX/threadsafe-statics.cpp
new file mode 100644
index 000000000000..65ebc43c5d25
--- /dev/null
+++ b/test/CodeGenCXX/threadsafe-statics.cpp
@@ -0,0 +1,17 @@
+// 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
+
+int f();
+
+// WITH-TSS: define void @_Z1gv() nounwind
+// WITH-TSS: call i32 @__cxa_guard_acquire
+// WITH-TSS: call void @__cxa_guard_release
+// WITH-TSS: ret void
+void g() {
+ static int a = f();
+}
+
+// NO-TSS: define void @_Z1gv() nounwind
+// NO-TSS-NOT: call i32 @__cxa_guard_acquire
+// NO-TSS-NOT: call void @__cxa_guard_release
+// NO-TSS: ret void
diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp
index 9449618f2f2c..1670e4450237 100644
--- a/test/CodeGenCXX/throw-expressions.cpp
+++ b/test/CodeGenCXX/throw-expressions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm-only -verify %s
+// RUN: %clang_cc1 -emit-llvm-only -verify %s -Wno-unreachable-code
int val = 42;
int& test1() {
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
index 22e11fd76e31..9d671c4e5f0e 100644
--- a/test/CodeGenCXX/virt.cpp
+++ b/test/CodeGenCXX/virt.cpp
@@ -384,11 +384,11 @@ struct test16_D : test16_NV1, virtual test16_B2 {
// CHECK-LP64-NEXT: .quad __ZTcv0_n48_v0_n24_N8test16_D4foo1Ev
// CHECK-LP64-NEXT: .quad __ZN9test16_B24foo2Ev
// CHECK-LP64-NEXT: .quad __ZN9test16_B26foo_B2Ev
-// CHECK-LP64-NEXT .quad 16
-// CHECK-LP64-NEXT .quad 16
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .quad 16
// CHECK-LP64-NEXT: .quad 0
// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64: .quad -16
+// CHECK-LP64-NEXT: .quad -16
// CHECK-LP64-NEXT: .quad -32
// CHECK-LP64-NEXT: .quad 0
// CHECK-LP64-NEXT: .quad 0
@@ -402,8 +402,8 @@ struct test16_D : test16_NV1, virtual test16_B2 {
// CHECK-LP64-NEXT: .quad __ZN8test16_B5foo_BEv
// CHECK-LP64-NEXT: .quad -48
// CHECK-LP64-NEXT: .quad __ZTI8test16_D
-// CHECK-LP64-NEXT .quad __ZTcvn16_n40_v16_n32_N8test16_D4foo1Ev
-// CHECK-LP64: .quad __ZN10test16_NV27foo_NV2Ev
+// CHECK-LP64-NEXT: .quad __ZTcvn16_n40_v16_n32_N8test16_D4foo1Ev
+// CHECK-LP64-NEXT: .quad __ZN10test16_NV27foo_NV2Ev
// CHECK-LP64-NEXT: .quad __ZN10test16_NV28foo_NV2bEv
@@ -696,32 +696,32 @@ void test12_foo() {
// FIXME: This is the wrong thunk, but until these issues are fixed, better
// than nothing.
-// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*)
-// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D*
-// CHECK-LPLL64: %.addr = alloca %class.test8_D*
-// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr
-// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr
-// CHECK-LPLL64: %{{1|4}} = bitcast %class.test8_D* %{{this|3}} to i8*
-// CHECK-LPLL64: %{{2|5}} = getelementptr inbounds i8* %{{1|4}}, i64 -16
-// CHECK-LPLL64: %{{3|6}} = bitcast i8* %{{2|5}} to %class.test8_D*
-// CHECK-LPLL64: %{{4|7}} = bitcast %class.test8_D* %{{3|6}} to i8*
-// CHECK-LPLL64: %{{5|8}} = bitcast %class.test8_D* %3 to i64**
-// CHECK-LPLL64: %{{vtable|9}} = load i64** %{{5|8}}
-// CHECK-LPLL64: %{{6|10}} = getelementptr inbounds i64* %{{vtable|9}}, i64 -9
-// CHECK-LPLL64: %{{7|11}} = load i64* %{{6|10}}
-// CHECK-LPLL64: %{{8|12}} = getelementptr i8* %{{4|7}}, i64 %{{7|11}}
-// CHECK-LPLL64: %{{9|13}} = bitcast i8* %{{8|12}} to %class.test8_D*
-// CHECK-LPLL64: %{{call|14}} = call %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D* %{{9|13}})
-// CHECK-LPLL64: store %class.test8_D* %{{call|14}}, %class.test8_D** %{{retval|2}}
-// CHECK-LPLL64: %{{10|15}} = load %class.test8_D** %{{retval|2}}
-// CHECK-LPLL64: ret %class.test8_D* %{{10|15}}
-// CHECK-LPLL64:}
+// CHECK-LPLL64define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*)
+// CHECK-LPLL64 %{{retval|2}} = alloca %class.test8_D*
+// CHECK-LPLL64 %.addr = alloca %class.test8_D*
+// CHECK-LPLL64 store %class.test8_D* %0, %class.test8_D** %.addr
+// CHECK-LPLL64 %{{this|3}} = load %class.test8_D** %.addr
+// CHECK-LPLL64 %{{1|4}} = bitcast %class.test8_D* %{{this|3}} to i8*
+// CHECK-LPLL64 %{{2|5}} = getelementptr inbounds i8* %{{1|4}}, i64 -16
+// CHECK-LPLL64 %{{3|6}} = bitcast i8* %{{2|5}} to %class.test8_D*
+// CHECK-LPLL64 %{{4|7}} = bitcast %class.test8_D* %{{3|6}} to i8*
+// CHECK-LPLL64 %{{5|8}} = bitcast %class.test8_D* %3 to i64**
+// CHECK-LPLL64 %{{vtable|9}} = load i64** %{{5|8}}
+// CHECK-LPLL64 %{{6|10}} = getelementptr inbounds i64* %{{vtable|9}}, i64 -9
+// CHECK-LPLL64 %{{7|11}} = load i64* %{{6|10}}
+// CHECK-LPLL64 %{{8|12}} = getelementptr i8* %{{4|7}}, i64 %{{7|11}}
+// CHECK-LPLL64 %{{9|13}} = bitcast i8* %{{8|12}} to %class.test8_D*
+// CHECK-LPLL64 %{{call|14}} = call %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D* %{{9|13}})
+// CHECK-LPLL64 store %class.test8_D* %{{call|14}}, %class.test8_D** %{{retval|2}}
+// CHECK-LPLL64 %{{10|15}} = load %class.test8_D** %{{retval|2}}
+// CHECK-LPLL64 ret %class.test8_D* %{{10|15}}
+// CHECK-LPLL64}
// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%{{class.test8_D|.*}}*)
-// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D*
-// CHECK-LPLL64: %.addr = alloca %class.test8_D*
-// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr
-// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr
+// CHECK-LPLL64: %{{retval|1}} = alloca %class.test8_D*
+// CHECK-LPLL64: %{{.addr|2}} = alloca %class.test8_D*
+// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %{{.addr|2}}
+// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %{{.addr|2}}
// CHECK-LPLL64: %{{call|4}} = call %class.test8_D* @_ZN8test16_D4foo1Ev(%class.test8_D* %{{this|3}})
// CHECK-LPLL64: %{{1|5}} = icmp ne %class.test8_D* %{{call|4}}, null
// CHECK-LPLL64: br i1 %{{1|5}}, label %{{2|6}}, label %{{12|17}}
diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp
index 1eaef3fa3af4..200f21a5da72 100644
--- a/test/CodeGenCXX/virtual-bases.cpp
+++ b/test/CodeGenCXX/virtual-bases.cpp
@@ -15,3 +15,11 @@ struct B : virtual A {
// CHECK: define void @_ZN1BC1Ev(%struct.B* %this)
// CHECK: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt)
B::B() { }
+
+struct C : virtual A {
+ C(bool);
+};
+
+// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext)
+// CHECK: define void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext)
+C::C(bool) { }
diff --git a/test/CodeGenCXX/virtual-function-calls.cpp b/test/CodeGenCXX/virtual-function-calls.cpp
index 0b3a684301eb..46e7b2d37f77 100644
--- a/test/CodeGenCXX/virtual-function-calls.cpp
+++ b/test/CodeGenCXX/virtual-function-calls.cpp
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
// PR5021
+namespace PR5021 {
+
struct A {
virtual void f(char);
};
@@ -16,4 +18,21 @@ struct B : virtual A {
void f(B * b) {
b->f();
-} \ No newline at end of file
+}
+
+}
+
+namespace Test1 {
+ struct A {
+ virtual ~A();
+ };
+
+ struct B : A {
+ virtual ~B();
+ virtual void f();
+ };
+
+ void f(B *b) {
+ b->f();
+ }
+}
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
new file mode 100644
index 000000000000..5edd27b8b279
--- /dev/null
+++ b/test/CodeGenCXX/visibility.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+#define HIDDEN __attribute__((visibility("hidden")))
+#define PROTECTED __attribute__((visibility("protected")))
+#define DEFAULT __attribute__((visibility("default")))
+
+// CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10
+
+namespace Test1 {
+ // CHECK: define hidden void @_ZN5Test11fEv
+ void HIDDEN f() { }
+
+}
+
+namespace Test2 {
+ struct HIDDEN A {
+ void f();
+ };
+
+ // A::f is a member function of a hidden class.
+ // CHECK: define hidden void @_ZN5Test21A1fEv
+ void A::f() { }
+}
+
+namespace Test3 {
+ struct HIDDEN A {
+ struct B {
+ void f();
+ };
+ };
+
+ // B is a nested class where its parent class is hidden.
+ // CHECK: define hidden void @_ZN5Test31A1B1fEv
+ void A::B::f() { }
+}
+
+namespace Test4 HIDDEN {
+ int VariableInHiddenNamespace = 10;
+
+ // Test4::g is in a hidden namespace.
+ // CHECK: define hidden void @_ZN5Test41gEv
+ void g() { }
+
+ struct DEFAULT A {
+ void f();
+ };
+
+ // A has default visibility.
+ // CHECK: define void @_ZN5Test41A1fEv
+ void A::f() { }
+}
+
+namespace Test5 {
+
+ namespace NS HIDDEN {
+ // f is in NS which is hidden.
+ // CHECK: define hidden void @_ZN5Test52NS1fEv()
+ void f() { }
+ }
+
+ namespace NS {
+ // g is in NS, but this NS decl is not hidden.
+ // CHECK: define void @_ZN5Test52NS1gEv
+ void g() { }
+ }
+}
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
new file mode 100644
index 000000000000..8fbe486faa47
--- /dev/null
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -0,0 +1,367 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s
+
+// For now, just verify this doesn't crash.
+namespace test0 {
+ struct Obj {};
+
+ struct Base { virtual const Obj *foo() = 0; };
+ struct Derived : Base { virtual Obj *foo() { return new Obj(); } };
+
+ void test(Derived *D) { D->foo(); }
+}
+
+namespace Test1 {
+// CHECK: Vtable for 'Test1::A' (3 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test1::A RTTI
+// CHECK-NEXT: -- (Test1::A, 0) vtable address --
+// CHECK-NEXT: 2 | void Test1::A::f()
+struct A {
+ virtual void f();
+};
+void A::f() { }
+
+}
+
+namespace Test2 {
+
+// This is a smoke test of the vtable dumper.
+// CHECK: Vtable for 'Test2::A' (9 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test2::A RTTI
+// CHECK-NEXT: -- (Test2::A, 0) vtable address --
+// CHECK-NEXT: 2 | void Test2::A::f()
+// CHECK-NEXT: 3 | void Test2::A::f() const
+// CHECK-NEXT: 4 | Test2::A *Test2::A::g(int)
+// CHECK-NEXT: 5 | Test2::A::~A() [complete]
+// CHECK-NEXT: 6 | Test2::A::~A() [deleting]
+// CHECK-NEXT: 7 | void Test2::A::h()
+// CHECK-NEXT: 8 | Test2::A &Test2::A::operator=(Test2::A const &)
+struct A {
+ virtual void f();
+ virtual void f() const;
+
+ virtual A* g(int a);
+ virtual ~A();
+ virtual void h();
+ virtual A& operator=(const A&);
+};
+void A::f() { }
+
+// Another simple vtable dumper test.
+
+// CHECK: Vtable for 'Test2::B' (6 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test2::B RTTI
+// CHECK-NEXT: -- (Test2::B, 0) vtable address --
+// CHECK-NEXT: 2 | void Test2::B::f()
+// CHECK-NEXT: 3 | void Test2::B::g() [pure]
+// CHECK-NEXT: 4 | Test2::B::~B() [complete] [pure]
+// CHECK-NEXT: 5 | Test2::B::~B() [deleting] [pure]
+struct B {
+ virtual void f();
+ virtual void g() = 0;
+ virtual ~B() = 0;
+};
+void B::f() { }
+
+}
+
+namespace Test3 {
+
+// If a function in a derived class overrides a function in a primary base,
+// then the function should not have an entry in the derived class (unless the return
+// value requires adjusting).
+
+// CHECK: Vtable for 'Test3::A' (3 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::A RTTI
+// CHECK-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::A::f()
+struct A {
+ virtual void f();
+};
+void A::f() { }
+
+// CHECK: Vtable for 'Test3::B' (4 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::B RTTI
+// CHECK-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-NEXT: -- (Test3::B, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::B::f()
+// CHECK-NEXT: 3 | void Test3::B::g()
+struct B : A {
+ virtual void f();
+ virtual void g();
+};
+void B::f() { }
+
+// CHECK: Vtable for 'Test3::C' (5 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::C RTTI
+// CHECK-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-NEXT: -- (Test3::C, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::A::f()
+// CHECK-NEXT: 3 | void Test3::C::g()
+// CHECK-NEXT: 4 | void Test3::C::h()
+struct C : A {
+ virtual void g();
+ virtual void h();
+};
+void C::g() { }
+
+// CHECK: Vtable for 'Test3::D' (5 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::D RTTI
+// CHECK-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-NEXT: -- (Test3::B, 0) vtable address --
+// CHECK-NEXT: -- (Test3::D, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::D::f()
+// CHECK-NEXT: 3 | void Test3::D::g()
+// CHECK-NEXT: 4 | void Test3::D::h()
+struct D : B {
+ virtual void f();
+ virtual void g();
+ virtual void h();
+};
+
+void D::f() { }
+}
+
+namespace Test4 {
+
+// Test non-virtual result adjustments.
+
+struct R1 { int r1; };
+struct R2 { int r2; };
+struct R3 : R1, R2 { int r3; };
+
+struct A {
+ virtual R2 *f();
+};
+
+// CHECK: Vtable for 'Test4::B' (4 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test4::B RTTI
+// CHECK-NEXT: -- (Test4::A, 0) vtable address --
+// CHECK-NEXT: -- (Test4::B, 0) vtable address --
+// CHECK-NEXT: 2 | Test4::R3 *Test4::B::f()
+// CHECK-NEXT: [return adjustment: 4 non-virtual]
+// CHECK-NEXT: 3 | Test4::R3 *Test4::B::f()
+
+struct B : A {
+ virtual R3 *f();
+};
+R3 *B::f() { return 0; }
+
+// Test virtual result adjustments.
+struct V1 { int v1; };
+struct V2 : virtual V1 { int v1; };
+
+struct C {
+ virtual V1 *f();
+};
+
+// CHECK: Vtable for 'Test4::D' (4 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test4::D RTTI
+// CHECK-NEXT: -- (Test4::C, 0) vtable address --
+// CHECK-NEXT: -- (Test4::D, 0) vtable address --
+// CHECK-NEXT: 2 | Test4::V2 *Test4::D::f()
+// CHECK-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
+// CHECK-NEXT: 3 | Test4::V2 *Test4::D::f()
+struct D : C {
+ virtual V2 *f();
+};
+V2 *D::f() { return 0; };
+
+// Virtual result adjustments with an additional non-virtual adjustment.
+struct V3 : virtual R3 { int r3; };
+
+// CHECK: Vtable for 'Test4::E' (4 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test4::E RTTI
+// CHECK-NEXT: -- (Test4::A, 0) vtable address --
+// CHECK-NEXT: -- (Test4::E, 0) vtable address --
+// CHECK-NEXT: 2 | Test4::V3 *Test4::E::f()
+// CHECK-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset]
+// CHECK-NEXT: 3 | Test4::V3 *Test4::E::f()
+
+struct E : A {
+ virtual V3 *f();
+};
+V3 *E::f() { return 0;}
+
+// Test that a pure virtual member doesn't get a thunk.
+
+// CHECK: Vtable for 'Test4::F' (5 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test4::F RTTI
+// CHECK-NEXT: -- (Test4::A, 0) vtable address --
+// CHECK-NEXT: -- (Test4::F, 0) vtable address --
+// CHECK-NEXT: 2 | Test4::R3 *Test4::F::f() [pure]
+// CHECK-NEXT: 3 | void Test4::F::g()
+// CHECK-NEXT: 4 | Test4::R3 *Test4::F::f() [pure]
+struct F : A {
+ virtual void g();
+ virtual R3 *f() = 0;
+};
+void F::g() { }
+
+}
+
+namespace Test5 {
+
+// Simple secondary vtables without 'this' pointer adjustments.
+struct A {
+ virtual void f();
+ virtual void g();
+ int a;
+};
+
+struct B1 : A {
+ virtual void f();
+ int b1;
+};
+
+struct B2 : A {
+ virtual void g();
+ int b2;
+};
+
+// CHECK: Vtable for 'Test5::C' (9 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test5::C RTTI
+// CHECK-NEXT: -- (Test5::A, 0) vtable address --
+// CHECK-NEXT: -- (Test5::B1, 0) vtable address --
+// CHECK-NEXT: -- (Test5::C, 0) vtable address --
+// CHECK-NEXT: 2 | void Test5::B1::f()
+// CHECK-NEXT: 3 | void Test5::A::g()
+// CHECK-NEXT: 4 | void Test5::C::h()
+// CHECK-NEXT: 5 | offset_to_top (-16)
+// CHECK-NEXT: 6 | Test5::C RTTI
+// CHECK-NEXT: -- (Test5::A, 16) vtable address --
+// CHECK-NEXT: -- (Test5::B2, 16) vtable address --
+// CHECK-NEXT: 7 | void Test5::A::f()
+// CHECK-NEXT: 8 | void Test5::B2::g()
+struct C : B1, B2 {
+ virtual void h();
+};
+void C::h() { }
+}
+
+namespace Test6 {
+
+// Simple non-virtual 'this' pointer adjustments.
+struct A1 {
+ virtual void f();
+ int a;
+};
+
+struct A2 {
+ virtual void f();
+ int a;
+};
+
+// CHECK: Vtable for 'Test6::C' (6 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test6::C RTTI
+// CHECK-NEXT: -- (Test6::A1, 0) vtable address --
+// CHECK-NEXT: -- (Test6::C, 0) vtable address --
+// CHECK-NEXT: 2 | void Test6::C::f()
+// CHECK-NEXT: 3 | offset_to_top (-16)
+// CHECK-NEXT: 4 | Test6::C RTTI
+// CHECK-NEXT: -- (Test6::A2, 16) vtable address --
+// CHECK-NEXT: 5 | void Test6::C::f()
+// CHECK-NEXT: [this adjustment: -16 non-virtual]
+struct C : A1, A2 {
+ virtual void f();
+};
+void C::f() { }
+
+}
+
+namespace Test7 {
+
+// Test that the D::f overrider for A::f have different 'this' pointer
+// adjustments in the two A base subobjects.
+
+struct A {
+ virtual void f();
+ int a;
+};
+
+struct B1 : A { };
+struct B2 : A { };
+
+struct C { virtual void c(); };
+
+// CHECK: Vtable for 'Test7::D' (10 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test7::D RTTI
+// CHECK-NEXT: -- (Test7::C, 0) vtable address --
+// CHECK-NEXT: -- (Test7::D, 0) vtable address --
+// CHECK-NEXT: 2 | void Test7::C::c()
+// CHECK-NEXT: 3 | void Test7::D::f()
+// CHECK-NEXT: 4 | offset_to_top (-8)
+// CHECK-NEXT: 5 | Test7::D RTTI
+// CHECK-NEXT: -- (Test7::A, 8) vtable address --
+// CHECK-NEXT: -- (Test7::B1, 8) vtable address --
+// CHECK-NEXT: 6 | void Test7::D::f()
+// CHECK-NEXT: [this adjustment: -8 non-virtual]
+// CHECK-NEXT: 7 | offset_to_top (-24)
+// CHECK-NEXT: 8 | Test7::D RTTI
+// CHECK-NEXT: -- (Test7::A, 24) vtable address --
+// CHECK-NEXT: -- (Test7::B2, 24) vtable address --
+// CHECK-NEXT: 9 | void Test7::D::f()
+// CHECK-NEXT: [this adjustment: -24 non-virtual]
+struct D : C, B1, B2 {
+ virtual void f();
+};
+void D::f() { }
+
+}
+
+namespace Test8 {
+
+// Test that we don't try to layout vtables for classes that don't have
+// virtual bases or virtual member functions.
+
+struct A { };
+
+// CHECK: Vtable for 'Test8::B' (3 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test8::B RTTI
+// CHECK-NEXT: -- (Test8::B, 0) vtable address --
+// CHECK-NEXT: 2 | void Test8::B::f()
+struct B : A {
+ virtual void f();
+};
+void B::f() { }
+
+}
+
+namespace Test9 {
+
+// Simple test of vbase offsets.
+
+struct A1 { int a1; };
+struct A2 { int a2; };
+
+// CHECK: Vtable for 'Test9::B' (5 entries).
+// CHECK-NEXT: 0 | vbase_offset (16)
+// CHECK-NEXT: 1 | vbase_offset (12)
+// CHECK-NEXT: 2 | offset_to_top (0)
+// CHECK-NEXT: 3 | Test9::B RTTI
+// CHECK-NEXT: -- (Test9::B, 0) vtable address --
+// CHECK-NEXT: 4 | void Test9::B::f()
+struct B : virtual A1, virtual A2 {
+ int b;
+
+ virtual void f();
+};
+
+
+void B::f() { }
+
+}
diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp
new file mode 100644
index 000000000000..92e011752f3f
--- /dev/null
+++ b/test/CodeGenCXX/vtable-pointer-initialization.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+struct Field {
+ Field();
+ ~Field();
+};
+
+struct Base {
+ Base();
+ ~Base();
+};
+
+struct A : Base {
+ A();
+ ~A();
+
+ virtual void f();
+
+ Field field;
+};
+
+// CHECK: define void @_ZN1AC1Ev(
+// CHECK: call void @_ZN4BaseC2Ev(
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: call void @_ZN5FieldC1Ev(
+// CHECK: ret void
+A::A() { }
+
+// CHECK: define void @_ZN1AD1Ev(
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
+// CHECK: call void @_ZN5FieldD1Ev(
+// CHECK: call void @_ZN4BaseD2Ev(
+// CHECK: ret void
+A::~A() { }
+
+struct B : Base {
+ virtual void f();
+
+ Field field;
+};
+
+void f() { B b; }
+
+// CHECK: define linkonce_odr void @_ZN1BC1Ev(
+// CHECK: call void @_ZN4BaseC2Ev(
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
+// CHECK: call void @_ZN5FieldC1Ev
+// CHECK: ret void
+
+// CHECK: define linkonce_odr void @_ZN1BD1Ev(
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2)
+// CHECK: call void @_ZN5FieldD1Ev(
+// CHECK: call void @_ZN4BaseD2Ev(
+// CHECK: ret void
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
new file mode 100644
index 000000000000..d13c0e4888fd
--- /dev/null
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// Non-trivial dtors, should both be passed indirectly.
+struct S {
+ ~S();
+ int s;
+};
+
+// CHECK: define void @_Z1fv(%struct.S* noalias sret %
+S f() { return S(); }
+// CHECK: define void @_Z1f1S(%struct.S*)
+void f(S) { }
+
+// Non-trivial dtors, should both be passed indirectly.
+class C {
+ ~C();
+ double c;
+};
+
+// CHECK: define void @_Z1gv(%class.C* noalias sret %
+C g() { return C(); }
+
+// CHECK: define void @_Z1f1C(%class.C*)
+void f(C) { }
diff --git a/test/CodeGenObjC/PR4894-recursive-debug-crash.m b/test/CodeGenObjC/PR4894-recursive-debug-crash.m
deleted file mode 100644
index 5d2327ad274b..000000000000
--- a/test/CodeGenObjC/PR4894-recursive-debug-crash.m
+++ /dev/null
@@ -1,40 +0,0 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -g -emit-llvm %s -o - | FileCheck %s
-// PR4894
-//
-// This test is actually just making sure we can generate the debug info for the
-// return type from im0 without crashing.
-// XFAIL: *
-
-@interface I0 {
- I0 *_iv0;
-}
-@end
-@protocol P0 @end
-
-@interface I1 @end
-@implementation I1
-- (I0<P0> *) im0 {
-// CHECK: @"\01-[I1 im0]"
-// CHECK: llvm.dbg.func.start
- return 0;
-}
-@end
-
-// FIXME: This was another PR4894 test case, which is crashing somewhere
-// else. PR5025.
-#if 0
-typedef const struct objc_selector {
- void *sel_id;
- const char *sel_types;
-} *SEL;
-
-@interface I2
-+(id) dictionary;
-@end
-
-@implementation I3;
-+(void) initialize {
- I2 *a0 = [I2 dictionary];
-}
-@end
-#endif
diff --git a/test/CodeGenObjC/blocks-4.m b/test/CodeGenObjC/blocks-4.m
new file mode 100644
index 000000000000..d945ed44fac0
--- /dev/null
+++ b/test/CodeGenObjC/blocks-4.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -fblocks -o %t %s
+// rdar://7590273
+
+void EXIT(id e);
+
+@interface NSBlockOperation {
+}
++(id)blockOperationWithBlock:(void (^)(void))block ;
+@end
+
+void FUNC() {
+ [NSBlockOperation blockOperationWithBlock:^{
+ @try {
+
+ }
+ @catch (id exception) {
+ EXIT(exception);
+ }
+ }];
+
+}
diff --git a/test/CodeGenObjC/PR4541.m b/test/CodeGenObjC/debug-info-crash.m
index 84218a968cc8..92f9c0eda316 100644
--- a/test/CodeGenObjC/PR4541.m
+++ b/test/CodeGenObjC/debug-info-crash.m
@@ -1,6 +1,29 @@
-// RUN: %clang_cc1 -o %t -w -g %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -g -S %s -o -
+// rdar://7556129
+@implementation test
+- (void)wait {
+ ^{};
+}
+@end
+
+// PR4894
+@interface I0 {
+ I0 *_iv0;
+}
+@end
+@protocol P0 @end
+@interface I1 @end
+@implementation I1
+- (I0<P0> *) im0 {
+ // CHECK: @"\01-[I1 im0]"
+ // CHECK: llvm.dbg.func.start
+ return 0;
+}
+@end
+
+// PR4541
@class NSString;
@interface NSAttributedString
- (NSString *)string;
@@ -15,5 +38,3 @@
NSMutableAttributedString *attrStr;
}
@end
-
-
diff --git a/test/CodeGenObjC/id-isa-codegen.m b/test/CodeGenObjC/id-isa-codegen.m
index 89e992209071..3179e11b7f39 100644
--- a/test/CodeGenObjC/id-isa-codegen.m
+++ b/test/CodeGenObjC/id-isa-codegen.m
@@ -34,3 +34,17 @@ Class Test(const void *inObject1) {
return ((id)inObject1)->isa;
return (id)0;
}
+
+// rdar 7609722
+@interface Foo {
+@public
+ id isa;
+}
++(id)method;
+@end
+
+id Test2() {
+ if([Foo method]->isa)
+ return (*[Foo method]).isa;
+ return [Foo method]->isa;
+}
diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m
index 17f75319a0da..8916d0053fed 100644
--- a/test/CodeGenObjC/image-info.m
+++ b/test/CodeGenObjC/image-info.m
@@ -1,2 +1,2 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin-10 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// RUN: grep -F '@"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__OBJC, __image_info,regular"' %t
diff --git a/test/CodeGenObjC/objc2-legacy-dispatch.m b/test/CodeGenObjC/objc2-legacy-dispatch.m
new file mode 100644
index 000000000000..4c37573ad564
--- /dev/null
+++ b/test/CodeGenObjC/objc2-legacy-dispatch.m
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_NEW_DISPATCH %s
+//
+// CHECK_NEW_DISPATCH: define void @f0
+// CHECK_NEW_DISPATCH: bitcast {{.*}}objc_msgSend_fixup_alloc
+// CHECK_NEW_DISPATCH: define void @f1
+// CHECK_NEW_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
+//
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-legacy-dispatch -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_OLD_DISPATCH %s
+//
+// CHECK_OLD_DISPATCH: define void @f0
+// CHECK_OLD_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
+// CHECK_OLD_DISPATCH: define void @f1
+// CHECK_OLD_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
+
+@interface A
++(id) alloc;
+-(int) im0;
+@end
+
+void f0(void) {
+ [A alloc];
+}
+
+void f1(A *a) {
+ [a im0];
+}
diff --git a/test/CodeGenObjC/objc2-weak-block-call.m b/test/CodeGenObjC/objc2-weak-block-call.m
new file mode 100644
index 000000000000..a3514b0caa0c
--- /dev/null
+++ b/test/CodeGenObjC/objc2-weak-block-call.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -S %s -o %t-32.s
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+
+@interface MyView
+- (void)MyView_sharedInit;
+@end
+
+void foo(MyView *(^obj)(void)) ;
+
+@implementation MyView
+- (void)MyView_sharedInit {
+
+ __block __weak MyView *weakSelf = self;
+ foo(
+ ^{
+ return weakSelf;
+ });
+
+}
+@end
+
+// CHECK-LP64: callq _objc_read_weak
+// CHECK-LP64: callq _objc_read_weak
+
+// CHECK-LP32: call L_objc_read_weak
+// CHECK-LP32: call L_objc_read_weak
+
diff --git a/test/CodeGenObjC/unwind-fn.m b/test/CodeGenObjC/unwind-fn.m
new file mode 100644
index 000000000000..0aa8cde024da
--- /dev/null
+++ b/test/CodeGenObjC/unwind-fn.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck --check-prefix=DEFAULT_EH %s
+// RUN: %clang_cc1 -fsjlj-exceptions -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck --check-prefix=SJLJ_EH %s
+
+// DEFAULT_EH: declare void @_Unwind_Resume_or_Rethrow(i8*)
+// SJLJ_EH: declare void @_Unwind_SjLj_Resume(i8*)
+
+void f1(), f2();
+void f0() {
+ @try {
+ f1();
+ } @catch (...) {
+ f2();
+ }
+}
diff --git a/test/Coverage/html-diagnostics.c b/test/Coverage/html-diagnostics.c
index 6971f58f6aa4..81b2cfa588e3 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 -checker-cfref -o %t %s
+// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-check-objc-mem -o %t %s
// RUN: cat %t/*.html | FileCheck %s
// CHECK: <h3>Annotated Source Code</h3>
diff --git a/test/Driver/darwin-iphone-defaults.m b/test/Driver/darwin-iphone-defaults.m
new file mode 100644
index 000000000000..97ac4a42a54b
--- /dev/null
+++ b/test/Driver/darwin-iphone-defaults.m
@@ -0,0 +1,30 @@
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -arch armv7 -flto -S -o - %s | FileCheck %s
+
+// CHECK: @f0
+// CHECK-NOT: ssp
+// CHECK: ) {
+// CHECK: @__f0_block_invoke
+// CHECK: void @f1
+// CHECK-NOT: msgSend_fixup_alloc
+// CHECK: OBJC_SELECTOR_REFERENCES
+
+int f0() {
+ return ^(){ return 0; }();
+}
+
+@interface I0
+@property (assign) int p0;
+@end
+
+@implementation I0
+@synthesize p0 = __sythesized_p0;
+@end
+
+@interface I1
++(id) alloc;
+@end
+
+void f1() {
+ [I1 alloc];
+}
+
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index de751a67d965..d34d566d1878 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -39,5 +39,38 @@
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch i386 -arch x86_64 -g %s 2> %t.log
// RUN: grep dsymutil %t.log | count 0
+// Check linker changes that came with new linkedit format.
+// RUN: touch %t.o
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 %t.o 2> %t.log
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 -dynamiclib %t.o 2>> %t.log
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 -bundle %t.o 2>> %t.log
+// RUN: FileCheck -check-prefix=LINK_IPHONE_3_0 %s < %t.log
+// LINK_IPHONE_3_0: ld"
+// LINK_IPHONE_3_0-NOT: -lcrt1.3.1.o
+// LINK_IPHONE_3_0: -lcrt1.o
+// LINK_IPHONE_3_0: -lSystem
+// LINK_IPHONE_3_0: ld"
+// LINK_IPHONE_3_0: -dylib
+// LINK_IPHONE_3_0: -ldylib1.o
+// LINK_IPHONE_3_0: -lSystem
+// LINK_IPHONE_3_0: ld"
+// LINK_IPHONE_3_0: -lbundle1.o
+// LINK_IPHONE_3_0: -lSystem
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 %t.o 2> %t.log
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 -dynamiclib %t.o 2>> %t.log
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 -bundle %t.o 2>> %t.log
+// RUN: FileCheck -check-prefix=LINK_IPHONE_3_1 %s < %t.log
+
+// LINK_IPHONE_3_1: ld"
+// LINK_IPHONE_3_1-NOT: -lcrt1.o
+// LINK_IPHONE_3_1: -lcrt1.3.1.o
+// LINK_IPHONE_3_1: -lSystem
+// LINK_IPHONE_3_1: ld"
+// LINK_IPHONE_3_1: -dylib
+// LINK_IPHONE_3_1-NOT: -ldylib1.o
+// LINK_IPHONE_3_1: -lSystem
+// LINK_IPHONE_3_1: ld"
+// LINK_IPHONE_3_1-NOT: -lbundle1.o
+// LINK_IPHONE_3_1: -lSystem
diff --git a/test/Driver/darwin-version.c b/test/Driver/darwin-version.c
index e69a8447c4a7..84533a625246 100644
--- a/test/Driver/darwin-version.c
+++ b/test/Driver/darwin-version.c
@@ -1,6 +1,23 @@
-// RUN: env MACOSX_DEPLOYMENT_TARGET=10.1 %clang -ccc-host-triple i386-apple-darwin9 -E %s
-
+// RUN: env MACOSX_DEPLOYMENT_TARGET=10.1 \
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST0 -E %s
+#ifdef TEST0
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1010
#error Invalid version
#endif
+#endif
+// RUN: env IPHONEOS_DEPLOYMENT_TARGET=2.0 \
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST1 -E %s
+#ifdef TEST1
+#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ != 20000
+#error Invalid version
+#endif
+#endif
+
+// RUN: env IPHONEOS_DEPLOYMENT_TARGET=2.3.1 \
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST2 -E %s
+#ifdef TEST2
+#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ != 20301
+#error Invalid version
+#endif
+#endif
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
new file mode 100644
index 000000000000..38993fc8978c
--- /dev/null
+++ b/test/Driver/rewrite-objc.m
@@ -0,0 +1,11 @@
+// RUN: %clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST0 %s
+// TEST0: clang{{.*}}" "-rewrite-objc"
+
+// RUN: not %clang -ccc-no-clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST1 %s
+// TEST1: invalid output type 'rewritten-objc' for use with gcc
+
+// RUN: not %clang -ccc-no-clang -ccc-host-triple i386-apple-darwin10 -rewrite-objc %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST2 %s
+// TEST2: invalid output type 'rewritten-objc' for use with gcc
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 04b99c941654..ee93755775e5 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -pedantic -fixit %s -o - | %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ -
+// RUN: %clang_cc1 -pedantic -Wall -fixit %s -o - | %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x c++ -
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -28,11 +28,12 @@ struct CT<0> { }; // expected-error{{'template<>'}}
template<> class CT<1> { }; // expected-error{{tag type}}
-// PR5444
-namespace PR5444 {
- void foo(int x, int y = 0);
- void foo(int x, int y = 0) { }
+// Access declarations
+class A {
+protected:
+ int foo();
+};
- void foo(int = 0);
- void foo(int = 0) { }
-}
+class B : public A {
+ A::foo; // expected-warning{{access declarations are deprecated}}
+};
diff --git a/test/FixIt/typo-crash.m b/test/FixIt/typo-crash.m
new file mode 100644
index 000000000000..f10fe61ae78e
--- /dev/null
+++ b/test/FixIt/typo-crash.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/7605289>
+@implementation Unknown (Blarg) // expected-error{{cannot find interface declaration for 'Unknown'}}
+- (int)method { return ivar; } // expected-error{{use of undeclared identifier 'ivar'}}
+@end
diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m
index c2069dd4169d..86dd383c904e 100644
--- a/test/FixIt/typo.m
+++ b/test/FixIt/typo.m
@@ -86,5 +86,5 @@ void test2(Collide *a) {
- (int)send:(void*)buffer bytes:(int)bytes;
@end
-@interface IPv8 <Network_Socket> // expected-error{{cannot find protocol declaration for 'Network_Socket'; did you mean 'NetworkSocket'?}}
+@interface IPv6 <Network_Socket> // expected-error{{cannot find protocol declaration for 'Network_Socket'; did you mean 'NetworkSocket'?}}
@end
diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m
index f9627123a0de..b55c8623a514 100644
--- a/test/Index/TestClassDecl.m
+++ b/test/Index/TestClassDecl.m
@@ -15,19 +15,19 @@ void function(Foo * arg)
// nothing here.
}
-// CHECK-scan: {start_line=1 start_col=1 end_line=7 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK-scan: {start_line=8 start_col=1 end_line=8 end_col=7} UnexposedDecl=:8:1
-// CHECK-scan: {start_line=8 start_col=8 end_line=8 end_col=10} ObjCClassRef=Foo:10:12
-// CHECK-scan: {start_line=8 start_col=11 end_line=9 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK-scan: {start_line=10 start_col=1 end_line=11 end_col=4} ObjCInterfaceDecl=Foo:10:12
-// CHECK-scan: {start_line=11 start_col=5 end_line=13 end_col=5} Invalid Cursor => NoDeclFound
-// CHECK-scan: {start_line=13 start_col=6 end_line=13 end_col=14} FunctionDecl=function:13:6 (Definition)
-// CHECK-scan: {start_line=13 start_col=15 end_line=13 end_col=17} ObjCClassRef=Foo:10:12
-// CHECK-scan: {start_line=13 start_col=18 end_line=13 end_col=23} ParmDecl=arg:13:21 (Definition)
-// CHECK-scan: {start_line=13 start_col=24 end_line=13 end_col=25} FunctionDecl=function:13:6 (Definition)
-// CHECK-scan: {start_line=14 start_col=1 end_line=16 end_col=1} UnexposedStmt=function
+// CHECK-scan: [1:1 - 8:1] Invalid Cursor => NoDeclFound
+// CHECK-scan: [8:1 - 8:8] UnexposedDecl=:8:1
+// CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:10:12
+// CHECK-scan: [8:11 - 10:1] Invalid Cursor => NoDeclFound
+// CHECK-scan: [10:1 - 11:5] ObjCInterfaceDecl=Foo:10:12
+// CHECK-scan: [11:5 - 13:6] Invalid Cursor => NoDeclFound
+// CHECK-scan: [13:6 - 13:15] FunctionDecl=function:13:6 (Definition)
+// CHECK-scan: [13:15 - 13:18] ObjCClassRef=Foo:10:12
+// CHECK-scan: [13:18 - 13:24] ParmDecl=arg:13:21 (Definition)
+// CHECK-scan: [13:24 - 14:1] FunctionDecl=function:13:6 (Definition)
+// CHECK-scan: [14:1 - 16:2] UnexposedStmt=
-// CHECK-load: TestClassDecl.m:10:12: ObjCInterfaceDecl=Foo:10:12 [Extent=10:1:11:4]
-// CHECK-load: TestClassDecl.m:13:6: FunctionDecl=function:13:6 (Definition) [Extent=13:6:16:1]
-// CHECK-load: TestClassDecl.m:13:21: ParmDecl=arg:13:21 (Definition) [Extent=13:15:13:23]
+// 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:21: ParmDecl=arg:13:21 (Definition) Extent=[13:15 - 13:24]
diff --git a/test/Index/TestClassForwardDecl.m b/test/Index/TestClassForwardDecl.m
index c53453b0ba89..325a4236a511 100644
--- a/test/Index/TestClassForwardDecl.m
+++ b/test/Index/TestClassForwardDecl.m
@@ -12,15 +12,15 @@ void function(Foo * arg)
// nothing here.
}
-// CHECK-scan: {start_line=1 start_col=1 end_line=7 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK-scan: {start_line=8 start_col=1 end_line=8 end_col=7} UnexposedDecl=:8:1
-// CHECK-scan: {start_line=8 start_col=8 end_line=8 end_col=10} ObjCClassRef=Foo:8:8
-// CHECK-scan: {start_line=8 start_col=11 end_line=10 end_col=5} Invalid Cursor => NoDeclFound
-// CHECK-scan: {start_line=10 start_col=6 end_line=10 end_col=14} FunctionDecl=function:10:6 (Definition)
-// CHECK-scan: {start_line=10 start_col=15 end_line=10 end_col=17} ObjCClassRef=Foo:8:8
-// CHECK-scan: {start_line=10 start_col=18 end_line=10 end_col=23} ParmDecl=arg:10:21 (Definition)
-// CHECK-scan: {start_line=10 start_col=24 end_line=10 end_col=25} FunctionDecl=function:10:6 (Definition)
-// CHECK-scan: {start_line=11 start_col=1 end_line=13 end_col=1} UnexposedStmt=function
+// CHECK-scan: [1:1 - 8:1] Invalid Cursor => NoDeclFound
+// CHECK-scan: [8:1 - 8:8] UnexposedDecl=:8:1
+// CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:8:8
+// CHECK-scan: [8:11 - 10:6] Invalid Cursor => NoDeclFound
+// CHECK-scan: [10:6 - 10:15] FunctionDecl=function:10:6 (Definition)
+// CHECK-scan: [10:15 - 10:18] ObjCClassRef=Foo:8:8
+// CHECK-scan: [10:18 - 10:24] ParmDecl=arg:10:21 (Definition)
+// CHECK-scan: [10:24 - 11:1] FunctionDecl=function:10:6 (Definition)
+// CHECK-scan: [11:1 - 13:2] UnexposedStmt=
diff --git a/test/Index/annotate-tokens.c b/test/Index/annotate-tokens.c
new file mode 100644
index 000000000000..ef0069c8879a
--- /dev/null
+++ b/test/Index/annotate-tokens.c
@@ -0,0 +1,64 @@
+typedef int T;
+struct X { int a, b; };
+void f(void *ptr) {
+ T* t_ptr = (T *)ptr;
+ (void)sizeof(T);
+ /* A comment */
+ struct X x = (struct X){1, 2};
+ void *xx = ptr ? : &x;
+ const char * hello = "Hello";
+}
+
+// RUN: c-index-test -test-annotate-tokens=%s:4:1:9:32 %s | FileCheck %s
+// CHECK: Identifier: "T" [4:3 - 4:4] TypeRef=T:1:13
+// CHECK: Punctuation: "*" [4:4 - 4:5]
+// CHECK: Identifier: "t_ptr" [4:6 - 4:11] VarDecl=t_ptr:4:6 (Definition)
+// CHECK: Punctuation: "=" [4:12 - 4:13]
+// CHECK: Punctuation: "(" [4:14 - 4:15]
+// CHECK: Identifier: "T" [4:15 - 4:16] TypeRef=T:1:13
+// CHECK: Punctuation: "*" [4:17 - 4:18]
+// CHECK: Punctuation: ")" [4:18 - 4:19]
+// CHECK: Identifier: "ptr" [4:19 - 4:22] DeclRefExpr=ptr:3:14
+// CHECK: Punctuation: ";" [4:22 - 4:23]
+// CHECK: Punctuation: "(" [5:3 - 5:4]
+// CHECK: Keyword: "void" [5:4 - 5:8]
+// CHECK: Punctuation: ")" [5:8 - 5:9]
+// CHECK: Keyword: "sizeof" [5:9 - 5:15]
+// CHECK: Punctuation: "(" [5:15 - 5:16]
+// CHECK: Identifier: "T" [5:16 - 5:17] TypeRef=T:1:13
+// CHECK: Punctuation: ")" [5:17 - 5:18]
+// CHECK: Punctuation: ";" [5:18 - 5:19]
+// CHECK: Comment: "/* A comment */" [6:3 - 6:18]
+// CHECK: Keyword: "struct" [7:3 - 7:9]
+// 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]
+// CHECK: Punctuation: "(" [7:16 - 7:17]
+// CHECK: Keyword: "struct" [7:17 - 7:23]
+// CHECK: Identifier: "X" [7:24 - 7:25] TypeRef=struct X:2:8
+// CHECK: Punctuation: ")" [7:25 - 7:26]
+// CHECK: Punctuation: "{" [7:26 - 7:27]
+// CHECK: Literal: "1" [7:27 - 7:28]
+// CHECK: Punctuation: "," [7:28 - 7:29]
+// CHECK: Literal: "2" [7:30 - 7:31]
+// CHECK: Punctuation: "}" [7:31 - 7:32]
+// CHECK: Punctuation: ";" [7:32 - 7:33]
+// CHECK: Keyword: "void" [8:3 - 8:7]
+// CHECK: Punctuation: "*" [8:8 - 8:9]
+// CHECK: Identifier: "xx" [8:9 - 8:11] VarDecl=xx:8:9 (Definition)
+// CHECK: Punctuation: "=" [8:12 - 8:13]
+// CHECK: Identifier: "ptr" [8:14 - 8:17] DeclRefExpr=ptr:3:14
+// CHECK: Punctuation: "?" [8:18 - 8:19]
+// CHECK: Punctuation: ":" [8:20 - 8:21]
+// CHECK: Punctuation: "&" [8:22 - 8:23]
+// CHECK: Identifier: "x" [8:23 - 8:24] DeclRefExpr=x:7:12
+// CHECK: Punctuation: ";" [8:24 - 8:25]
+// CHECK: Keyword: "const" [9:3 - 9:8]
+// CHECK: Keyword: "char" [9:9 - 9:13]
+// CHECK: Punctuation: "*" [9:14 - 9:15]
+// CHECK: Identifier: "hello" [9:16 - 9:21] VarDecl=hello:9:16 (Definition)
+// CHECK: Punctuation: "=" [9:22 - 9:23]
+// CHECK: Literal: ""Hello"" [9:24 - 9:31]
+// CHECK: Punctuation: ";" [9:31 - 9:32]
+// CHECK: Punctuation: "}" [10:1 - 10:2]
+
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index cf0dbff457a1..cd0c8687aa20 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -65,67 +65,67 @@ int main (int argc, const char * argv[]) {
// CHECK: <invalid loc>:87:81: FieldDecl=overflow_arg_area:87:81 (Definition)
// CHECK: <invalid loc>:87:107: FieldDecl=reg_save_area:87:107 (Definition)
// CHECK: <invalid loc>:87:123: TypedefDecl=__va_list_tag:87:123 (Definition)
-// CHECK: <invalid loc>:87:9: TypeRef=struct __va_list_tag:87:16
+// CHECK: <invalid loc>:87:16: TypeRef=struct __va_list_tag:87:16
// CHECK: <invalid loc>:87:159: TypedefDecl=__builtin_va_list:87:159 (Definition)
// CHECK: <invalid loc>:87:145: TypeRef=__va_list_tag:87:123
// CHECK: <invalid loc>:87:177: UnexposedExpr=
-// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 [Extent=4:1:11:4]
-// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=foo:8:1 [Extent=8:1:8:6]
-// CHECK: c-index-api-loadTU-test.m:9:1: ObjCClassMethodDecl=fooC:9:1 [Extent=9:1:9:7]
-// CHECK: c-index-api-loadTU-test.m:13:12: ObjCInterfaceDecl=Bar:13:12 [Extent=13:1:17:4]
-// CHECK: c-index-api-loadTU-test.m:13:18: ObjCSuperClassRef=Foo:4:12 [Extent=13:18:13:20]
-// CHECK: c-index-api-loadTU-test.m:19:12: ObjCCategoryDecl=FooCat:19:12 [Extent=19:1:22:4]
-// CHECK: c-index-api-loadTU-test.m:19:12: ObjCClassRef=Foo:4:12 [Extent=19:12:19:14]
-// CHECK: c-index-api-loadTU-test.m:20:1: ObjCInstanceMethodDecl=catMethodWithFloat::20:1 [Extent=20:1:20:40]
-// CHECK: c-index-api-loadTU-test.m:20:36: ParmDecl=fArg:20:36 (Definition) [Extent=20:29:20:39]
-// CHECK: c-index-api-loadTU-test.m:21:1: ObjCInstanceMethodDecl=floatMethod:21:1 [Extent=21:1:21:22]
-// CHECK: c-index-api-loadTU-test.m:24:1: ObjCProtocolDecl=Proto:24:1 (Definition) [Extent=24:1:26:4]
-// CHECK: c-index-api-loadTU-test.m:25:1: ObjCInstanceMethodDecl=pMethod:25:1 [Extent=25:1:25:10]
-// CHECK: c-index-api-loadTU-test.m:28:1: ObjCProtocolDecl=SubP:28:1 (Definition) [Extent=28:1:30:4]
-// CHECK: c-index-api-loadTU-test.m:28:17: ObjCProtocolRef=Proto:24:1 [Extent=28:17:28:21]
-// CHECK: c-index-api-loadTU-test.m:29:1: ObjCInstanceMethodDecl=spMethod:29:1 [Extent=29:1:29:11]
-// CHECK: c-index-api-loadTU-test.m:32:12: ObjCInterfaceDecl=Baz:32:12 [Extent=32:1:39:4]
-// CHECK: c-index-api-loadTU-test.m:32:18: ObjCSuperClassRef=Bar:13:12 [Extent=32:18:32:20]
-// CHECK: c-index-api-loadTU-test.m:32:23: ObjCProtocolRef=SubP:28:1 [Extent=32:23:32:26]
-// CHECK: c-index-api-loadTU-test.m:34:9: ObjCIvarDecl=_anIVar:34:9 (Definition) [Extent=34:9:34:15]
-// CHECK: c-index-api-loadTU-test.m:37:1: ObjCInstanceMethodDecl=bazMethod:37:1 [Extent=37:1:37:20]
-// CHECK: c-index-api-loadTU-test.m:41:1: EnumDecl=:41:1 (Definition) [Extent=41:1:43:1]
-// CHECK: c-index-api-loadTU-test.m:42:3: EnumConstantDecl=someEnum:42:3 (Definition) [Extent=42:3:42:10]
-// CHECK: c-index-api-loadTU-test.m:45:5: FunctionDecl=main:45:5 (Definition) [Extent=45:5:54:1]
-// CHECK: c-index-api-loadTU-test.m:45:15: ParmDecl=argc:45:15 (Definition) [Extent=45:11:45:18]
-// CHECK: c-index-api-loadTU-test.m:45:34: ParmDecl=argv:45:34 (Definition) [Extent=45:27:45:37]
-// CHECK: c-index-api-loadTU-test.m:45:5: UnexposedStmt=main [Extent=45:42:54:1]
-// CHECK: c-index-api-loadTU-test.m:45:5: UnexposedStmt=main [Extent=46:2:46:11]
-// CHECK: c-index-api-loadTU-test.m:46:8: VarDecl=bee:46:8 (Definition) [Extent=46:2:46:10]
-// CHECK: c-index-api-loadTU-test.m:46:2: ObjCClassRef=Baz:32:12 [Extent=46:2:46:4]
-// CHECK: c-index-api-loadTU-test.m:46:8: UnexposedStmt=bee [Extent=47:2:47:18]
-// CHECK: c-index-api-loadTU-test.m:47:5: VarDecl=a:47:5 (Definition) [Extent=47:2:47:17]
-// CHECK: c-index-api-loadTU-test.m:47:2: TypeRef=id:0:0 [Extent=47:2:47:3]
-// CHECK: c-index-api-loadTU-test.m:47:9: ObjCMessageExpr=foo:8:1 [Extent=47:9:47:17]
-// CHECK: c-index-api-loadTU-test.m:47:10: DeclRefExpr=bee:46:8 [Extent=47:10:47:12]
-// CHECK: c-index-api-loadTU-test.m:47:5: UnexposedStmt=a [Extent=48:2:48:26]
-// CHECK: c-index-api-loadTU-test.m:48:12: VarDecl=c:48:12 (Definition) [Extent=48:2:48:25]
-// CHECK: c-index-api-loadTU-test.m:48:2: TypeRef=id:0:0 [Extent=48:2:48:3]
-// CHECK: c-index-api-loadTU-test.m:48:6: ObjCProtocolRef=SubP:28:1 [Extent=48:6:48:9]
-// CHECK: c-index-api-loadTU-test.m:48:16: UnexposedExpr=fooC:9:1 [Extent=48:16:48:25]
-// CHECK: c-index-api-loadTU-test.m:48:16: ObjCMessageExpr=fooC:9:1 [Extent=48:16:48:25]
-// CHECK: c-index-api-loadTU-test.m:48:12: UnexposedStmt=c [Extent=49:2:49:14]
-// CHECK: c-index-api-loadTU-test.m:49:13: VarDecl=d:49:13 (Definition) [Extent=49:2:49:13]
-// CHECK: c-index-api-loadTU-test.m:49:2: TypeRef=id:0:0 [Extent=49:2:49:3]
-// CHECK: c-index-api-loadTU-test.m:49:6: ObjCProtocolRef=Proto:24:1 [Extent=49:6:49:10]
-// CHECK: c-index-api-loadTU-test.m:50:2: UnexposedExpr= [Extent=50:2:50:6]
-// CHECK: c-index-api-loadTU-test.m:50:2: DeclRefExpr=d:49:13 [Extent=50:2:50:2]
-// CHECK: c-index-api-loadTU-test.m:50:6: UnexposedExpr=c:48:12 [Extent=50:6:50:6]
-// CHECK: c-index-api-loadTU-test.m:50:6: DeclRefExpr=c:48:12 [Extent=50:6:50:6]
-// CHECK: c-index-api-loadTU-test.m:51:2: ObjCMessageExpr=pMethod:25:1 [Extent=51:2:51:12]
-// CHECK: c-index-api-loadTU-test.m:51:3: DeclRefExpr=d:49:13 [Extent=51:3:51:3]
-// CHECK: c-index-api-loadTU-test.m:52:2: ObjCMessageExpr=catMethodWithFloat::20:1 [Extent=52:2:52:43]
-// CHECK: c-index-api-loadTU-test.m:52:3: DeclRefExpr=bee:46:8 [Extent=52:3:52:5]
-// CHECK: c-index-api-loadTU-test.m:52:26: ObjCMessageExpr=floatMethod:21:1 [Extent=52:26:52:42]
-// CHECK: c-index-api-loadTU-test.m:52:27: DeclRefExpr=bee:46:8 [Extent=52:27:52:29]
-// CHECK: c-index-api-loadTU-test.m:53:3: CallExpr=main:45:5 [Extent=53:3:53:36]
-// CHECK: c-index-api-loadTU-test.m:53:3: UnexposedExpr=main:45:5 [Extent=53:3:53:6]
-// CHECK: c-index-api-loadTU-test.m:53:3: DeclRefExpr=main:45:5 [Extent=53:3:53:6]
-// CHECK: c-index-api-loadTU-test.m:53:8: DeclRefExpr=someEnum:42:3 [Extent=53:8:53:15]
-// CHECK: c-index-api-loadTU-test.m:53:18: UnexposedExpr=bee:46:8 [Extent=53:18:53:35]
-// CHECK: c-index-api-loadTU-test.m:53:33: DeclRefExpr=bee:46:8 [Extent=53:33:53:35]
+// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 11:5]
+// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=foo:8:1 Extent=[8:1 - 8:7]
+// CHECK: c-index-api-loadTU-test.m:9:1: ObjCClassMethodDecl=fooC:9:1 Extent=[9:1 - 9:8]
+// CHECK: c-index-api-loadTU-test.m:13:12: ObjCInterfaceDecl=Bar:13:12 Extent=[13:1 - 17:5]
+// CHECK: c-index-api-loadTU-test.m:13:18: ObjCSuperClassRef=Foo:4:12 Extent=[13:18 - 13:21]
+// CHECK: c-index-api-loadTU-test.m:19:12: ObjCCategoryDecl=FooCat:19:12 Extent=[19:1 - 22:5]
+// CHECK: c-index-api-loadTU-test.m:19:12: ObjCClassRef=Foo:4:12 Extent=[19:12 - 19:15]
+// CHECK: c-index-api-loadTU-test.m:20:1: ObjCInstanceMethodDecl=catMethodWithFloat::20:1 Extent=[20:1 - 20:41]
+// CHECK: c-index-api-loadTU-test.m:20:36: ParmDecl=fArg:20:36 (Definition) Extent=[20:29 - 20:40]
+// CHECK: c-index-api-loadTU-test.m:21:1: ObjCInstanceMethodDecl=floatMethod:21:1 Extent=[21:1 - 21:23]
+// CHECK: c-index-api-loadTU-test.m:24:1: ObjCProtocolDecl=Proto:24:1 (Definition) Extent=[24:1 - 26:5]
+// CHECK: c-index-api-loadTU-test.m:25:1: ObjCInstanceMethodDecl=pMethod:25:1 Extent=[25:1 - 25:11]
+// CHECK: c-index-api-loadTU-test.m:28:1: ObjCProtocolDecl=SubP:28:1 (Definition) Extent=[28:1 - 30:5]
+// CHECK: c-index-api-loadTU-test.m:28:17: ObjCProtocolRef=Proto:24:1 Extent=[28:17 - 28:22]
+// CHECK: c-index-api-loadTU-test.m:29:1: ObjCInstanceMethodDecl=spMethod:29:1 Extent=[29:1 - 29:12]
+// CHECK: c-index-api-loadTU-test.m:32:12: ObjCInterfaceDecl=Baz:32:12 Extent=[32:1 - 39:5]
+// CHECK: c-index-api-loadTU-test.m:32:18: ObjCSuperClassRef=Bar:13:12 Extent=[32:18 - 32:21]
+// CHECK: c-index-api-loadTU-test.m:32:23: ObjCProtocolRef=SubP:28:1 Extent=[32:23 - 32:27]
+// CHECK: c-index-api-loadTU-test.m:34:9: ObjCIvarDecl=_anIVar:34:9 (Definition) Extent=[34:9 - 34:16]
+// CHECK: c-index-api-loadTU-test.m:37:1: ObjCInstanceMethodDecl=bazMethod:37:1 Extent=[37:1 - 37:21]
+// CHECK: c-index-api-loadTU-test.m:41:1: EnumDecl=:41:1 (Definition) Extent=[41:1 - 43:2]
+// CHECK: c-index-api-loadTU-test.m:42:3: EnumConstantDecl=someEnum:42:3 (Definition) Extent=[42:3 - 42:11]
+// CHECK: c-index-api-loadTU-test.m:45:5: FunctionDecl=main:45:5 (Definition) Extent=[45:5 - 54:2]
+// CHECK: c-index-api-loadTU-test.m:45:15: ParmDecl=argc:45:15 (Definition) Extent=[45:11 - 45:19]
+// CHECK: c-index-api-loadTU-test.m:45:34: ParmDecl=argv:45:34 (Definition) Extent=[45:27 - 45:38]
+// CHECK: c-index-api-loadTU-test.m:45:5: UnexposedStmt= Extent=[45:42 - 54:2]
+// CHECK: c-index-api-loadTU-test.m:45:5: UnexposedStmt= Extent=[46:2 - 46:12]
+// CHECK: c-index-api-loadTU-test.m:46:8: VarDecl=bee:46:8 (Definition) Extent=[46:2 - 46:11]
+// CHECK: c-index-api-loadTU-test.m:46:2: ObjCClassRef=Baz:32:12 Extent=[46:2 - 46:5]
+// CHECK: c-index-api-loadTU-test.m:46:8: UnexposedStmt= Extent=[47:2 - 47:19]
+// CHECK: c-index-api-loadTU-test.m:47:5: VarDecl=a:47:5 (Definition) Extent=[47:2 - 47:18]
+// CHECK: c-index-api-loadTU-test.m:47:2: TypeRef=id:0:0 Extent=[47:2 - 47:4]
+// CHECK: c-index-api-loadTU-test.m:47:9: ObjCMessageExpr=foo:8:1 Extent=[47:9 - 47:18]
+// CHECK: c-index-api-loadTU-test.m:47:10: DeclRefExpr=bee:46:8 Extent=[47:10 - 47:13]
+// CHECK: c-index-api-loadTU-test.m:47:5: UnexposedStmt= Extent=[48:2 - 48:27]
+// CHECK: c-index-api-loadTU-test.m:48:12: VarDecl=c:48:12 (Definition) Extent=[48:2 - 48:26]
+// CHECK: c-index-api-loadTU-test.m:48:2: TypeRef=id:0:0 Extent=[48:2 - 48:4]
+// CHECK: c-index-api-loadTU-test.m:48:6: ObjCProtocolRef=SubP:28:1 Extent=[48:6 - 48:10]
+// CHECK: c-index-api-loadTU-test.m:48:16: UnexposedExpr=fooC:9:1 Extent=[48:16 - 48:26]
+// CHECK: c-index-api-loadTU-test.m:48:16: ObjCMessageExpr=fooC:9:1 Extent=[48:16 - 48:26]
+// CHECK: c-index-api-loadTU-test.m:48:12: UnexposedStmt= Extent=[49:2 - 49:15]
+// CHECK: c-index-api-loadTU-test.m:49:13: VarDecl=d:49:13 (Definition) Extent=[49:2 - 49:14]
+// CHECK: c-index-api-loadTU-test.m:49:2: TypeRef=id:0:0 Extent=[49:2 - 49:4]
+// CHECK: c-index-api-loadTU-test.m:49:6: ObjCProtocolRef=Proto:24:1 Extent=[49:6 - 49:11]
+// CHECK: c-index-api-loadTU-test.m:50:2: UnexposedExpr= Extent=[50:2 - 50:7]
+// CHECK: c-index-api-loadTU-test.m:50:2: DeclRefExpr=d:49:13 Extent=[50:2 - 50:3]
+// CHECK: c-index-api-loadTU-test.m:50:6: UnexposedExpr=c:48:12 Extent=[50:6 - 50:7]
+// CHECK: c-index-api-loadTU-test.m:50:6: DeclRefExpr=c:48:12 Extent=[50:6 - 50:7]
+// CHECK: c-index-api-loadTU-test.m:51:2: ObjCMessageExpr=pMethod:25:1 Extent=[51:2 - 51:13]
+// CHECK: c-index-api-loadTU-test.m:51:3: DeclRefExpr=d:49:13 Extent=[51:3 - 51:4]
+// CHECK: c-index-api-loadTU-test.m:52:2: ObjCMessageExpr=catMethodWithFloat::20:1 Extent=[52:2 - 52:44]
+// CHECK: c-index-api-loadTU-test.m:52:3: DeclRefExpr=bee:46:8 Extent=[52:3 - 52:6]
+// CHECK: c-index-api-loadTU-test.m:52:26: ObjCMessageExpr=floatMethod:21:1 Extent=[52:26 - 52:43]
+// CHECK: c-index-api-loadTU-test.m:52:27: DeclRefExpr=bee:46:8 Extent=[52:27 - 52:30]
+// CHECK: c-index-api-loadTU-test.m:53:3: CallExpr=main:45:5 Extent=[53:3 - 53:37]
+// CHECK: c-index-api-loadTU-test.m:53:3: UnexposedExpr=main:45:5 Extent=[53:3 - 53:7]
+// CHECK: c-index-api-loadTU-test.m:53:3: DeclRefExpr=main:45:5 Extent=[53:3 - 53:7]
+// CHECK: c-index-api-loadTU-test.m:53:8: DeclRefExpr=someEnum:42:3 Extent=[53:8 - 53:16]
+// CHECK: c-index-api-loadTU-test.m:53:18: UnexposedExpr=bee:46:8 Extent=[53:18 - 53:36]
+// CHECK: c-index-api-loadTU-test.m:53:33: DeclRefExpr=bee:46:8 Extent=[53:33 - 53:36]
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index 8fb7ffc5ff94..6a17e1c8417a 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -52,102 +52,102 @@ int main (int argc, const char * argv[]) {
main(someEnum, (const char **)bee);
}
-// CHECK: {start_line=1 start_col=1 end_line=2 end_col=62} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=3 start_col=1 end_line=6 end_col=1} ObjCInterfaceDecl=Foo:3:12
-// CHECK: {start_line=7 start_col=1 end_line=7 end_col=6} ObjCInstanceMethodDecl=foo:7:1
-// CHECK: {start_line=7 start_col=7 end_line=7 end_col=7} ObjCInterfaceDecl=Foo:3:12
-// CHECK: {start_line=8 start_col=1 end_line=8 end_col=7} ObjCClassMethodDecl=fooC:8:1
-// CHECK: {start_line=8 start_col=8 end_line=10 end_col=4} ObjCInterfaceDecl=Foo:3:12
-// CHECK: {start_line=10 start_col=5 end_line=11 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=12 start_col=1 end_line=12 end_col=17} ObjCInterfaceDecl=Bar:12:12
-// CHECK: {start_line=12 start_col=18 end_line=12 end_col=20} ObjCSuperClassRef=Foo:3:12
-// CHECK: {start_line=12 start_col=21 end_line=16 end_col=4} ObjCInterfaceDecl=Bar:12:12
-// CHECK: {start_line=16 start_col=5 end_line=17 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=18 start_col=1 end_line=18 end_col=11} ObjCCategoryDecl=FooCat:18:12
-// CHECK: {start_line=18 start_col=12 end_line=18 end_col=14} ObjCClassRef=Foo:3:12
-// CHECK: {start_line=18 start_col=15 end_line=18 end_col=24} ObjCCategoryDecl=FooCat:18:12
-// CHECK: {start_line=19 start_col=1 end_line=19 end_col=28} ObjCInstanceMethodDecl=catMethodWithFloat::19:1
-// CHECK: {start_line=19 start_col=29 end_line=19 end_col=39} ParmDecl=fArg:19:36 (Definition)
-// CHECK: {start_line=19 start_col=40 end_line=19 end_col=40} ObjCInstanceMethodDecl=catMethodWithFloat::19:1
-// CHECK: {start_line=19 start_col=41 end_line=19 end_col=41} ObjCCategoryDecl=FooCat:18:12
-// CHECK: {start_line=20 start_col=1 end_line=20 end_col=22} ObjCInstanceMethodDecl=floatMethod:20:1
-// CHECK: {start_line=20 start_col=23 end_line=21 end_col=4} ObjCCategoryDecl=FooCat:18:12
-// CHECK: {start_line=21 start_col=5 end_line=22 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=23 start_col=1 end_line=23 end_col=16} ObjCProtocolDecl=Proto:23:1 (Definition)
-// CHECK: {start_line=24 start_col=1 end_line=24 end_col=10} ObjCInstanceMethodDecl=pMethod:24:1
-// CHECK: {start_line=24 start_col=11 end_line=25 end_col=4} ObjCProtocolDecl=Proto:23:1 (Definition)
-// CHECK: {start_line=25 start_col=5 end_line=26 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=27 start_col=1 end_line=27 end_col=16} ObjCProtocolDecl=SubP:27:1 (Definition)
-// CHECK: {start_line=27 start_col=17 end_line=27 end_col=21} ObjCProtocolRef=Proto:23:1
-// CHECK: {start_line=27 start_col=22 end_line=27 end_col=23} ObjCProtocolDecl=SubP:27:1 (Definition)
-// CHECK: {start_line=28 start_col=1 end_line=28 end_col=11} ObjCInstanceMethodDecl=spMethod:28:1
-// CHECK: {start_line=28 start_col=12 end_line=29 end_col=4} ObjCProtocolDecl=SubP:27:1 (Definition)
-// CHECK: {start_line=29 start_col=5 end_line=30 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=31 start_col=1 end_line=31 end_col=17} ObjCInterfaceDecl=Baz:31:12
-// CHECK: {start_line=31 start_col=18 end_line=31 end_col=20} ObjCSuperClassRef=Bar:12:12
-// CHECK: {start_line=31 start_col=21 end_line=31 end_col=22} ObjCInterfaceDecl=Baz:31:12
-// CHECK: {start_line=31 start_col=23 end_line=31 end_col=26} ObjCProtocolRef=SubP:27:1
-// CHECK: {start_line=31 start_col=27 end_line=33 end_col=8} ObjCInterfaceDecl=Baz:31:12
-// CHECK: {start_line=33 start_col=9 end_line=33 end_col=15} ObjCIvarDecl=_anIVar:33:9 (Definition)
-// CHECK: {start_line=33 start_col=16 end_line=35 end_col=1} ObjCInterfaceDecl=Baz:31:12
-// CHECK: {start_line=36 start_col=1 end_line=36 end_col=20} ObjCInstanceMethodDecl=bazMethod:36:1
-// CHECK: {start_line=36 start_col=21 end_line=38 end_col=4} ObjCInterfaceDecl=Baz:31:12
-// CHECK: {start_line=38 start_col=5 end_line=39 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=40 start_col=1 end_line=41 end_col=2} EnumDecl=:40:1 (Definition)
-// CHECK: {start_line=41 start_col=3 end_line=41 end_col=10} EnumConstantDecl=someEnum:41:3 (Definition)
-// CHECK: {start_line=41 start_col=11 end_line=42 end_col=1} EnumDecl=:40:1 (Definition)
-// CHECK: {start_line=42 start_col=2 end_line=44 end_col=4} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=44 start_col=5 end_line=44 end_col=10} FunctionDecl=main:44:5 (Definition)
-// CHECK: {start_line=44 start_col=11 end_line=44 end_col=18} ParmDecl=argc:44:15 (Definition)
-// CHECK: {start_line=44 start_col=19 end_line=44 end_col=26} FunctionDecl=main:44:5 (Definition)
-// CHECK: {start_line=44 start_col=27 end_line=44 end_col=37} ParmDecl=argv:44:34 (Definition)
-// CHECK: {start_line=44 start_col=38 end_line=44 end_col=41} FunctionDecl=main:44:5 (Definition)
-// CHECK: {start_line=44 start_col=42 end_line=45 end_col=1} UnexposedStmt=main
-// CHECK: {start_line=45 start_col=2 end_line=45 end_col=4} ObjCClassRef=Baz:31:12
-// CHECK: {start_line=45 start_col=5 end_line=45 end_col=10} VarDecl=bee:45:8 (Definition)
-// CHECK: {start_line=45 start_col=11 end_line=45 end_col=11} UnexposedStmt=main
-// CHECK: {start_line=45 start_col=12 end_line=46 end_col=1} UnexposedStmt=main
-// CHECK: {start_line=46 start_col=2 end_line=46 end_col=3} TypeRef=id:0:0
-// CHECK: {start_line=46 start_col=4 end_line=46 end_col=8} VarDecl=a:46:5 (Definition)
-// CHECK: {start_line=46 start_col=9 end_line=46 end_col=9} ObjCMessageExpr=foo:7:1
-// CHECK: {start_line=46 start_col=10 end_line=46 end_col=12} DeclRefExpr=bee:45:8
-// CHECK: {start_line=46 start_col=13 end_line=46 end_col=17} ObjCMessageExpr=foo:7:1
-// CHECK: {start_line=46 start_col=18 end_line=46 end_col=18} UnexposedStmt=main
-// CHECK: {start_line=46 start_col=19 end_line=47 end_col=1} UnexposedStmt=main
-// CHECK: {start_line=47 start_col=2 end_line=47 end_col=3} TypeRef=id:0:0
-// CHECK: {start_line=47 start_col=4 end_line=47 end_col=5} VarDecl=c:47:12 (Definition)
-// CHECK: {start_line=47 start_col=6 end_line=47 end_col=9} ObjCProtocolRef=SubP:27:1
-// CHECK: {start_line=47 start_col=10 end_line=47 end_col=15} VarDecl=c:47:12 (Definition)
-// CHECK: {start_line=47 start_col=16 end_line=47 end_col=25} ObjCMessageExpr=fooC:8:1
-// CHECK: {start_line=47 start_col=26 end_line=47 end_col=26} UnexposedStmt=main
-// CHECK: {start_line=47 start_col=27 end_line=48 end_col=1} UnexposedStmt=main
-// CHECK: {start_line=48 start_col=2 end_line=48 end_col=3} TypeRef=id:0:0
-// CHECK: {start_line=48 start_col=4 end_line=48 end_col=5} VarDecl=d:48:13 (Definition)
-// CHECK: {start_line=48 start_col=6 end_line=48 end_col=10} ObjCProtocolRef=Proto:23:1
-// CHECK: {start_line=48 start_col=11 end_line=48 end_col=13} VarDecl=d:48:13 (Definition)
-// CHECK: {start_line=48 start_col=14 end_line=48 end_col=14} UnexposedStmt=main
-// CHECK: {start_line=48 start_col=15 end_line=49 end_col=1} UnexposedStmt=main
-// CHECK: {start_line=49 start_col=2 end_line=49 end_col=2} DeclRefExpr=d:48:13
-// CHECK: {start_line=49 start_col=3 end_line=49 end_col=5} UnexposedExpr=
-// CHECK: {start_line=49 start_col=6 end_line=49 end_col=6} DeclRefExpr=c:47:12
-// CHECK: {start_line=49 start_col=7 end_line=50 end_col=1} UnexposedStmt=main
-// CHECK: {start_line=50 start_col=2 end_line=50 end_col=2} ObjCMessageExpr=pMethod:24:1
-// CHECK: {start_line=50 start_col=3 end_line=50 end_col=3} DeclRefExpr=d:48:13
-// CHECK: {start_line=50 start_col=4 end_line=50 end_col=12} ObjCMessageExpr=pMethod:24:1
-// CHECK: {start_line=50 start_col=13 end_line=51 end_col=1} UnexposedStmt=main
-// CHECK: {start_line=51 start_col=2 end_line=51 end_col=2} ObjCMessageExpr=catMethodWithFloat::19:1
-// CHECK: {start_line=51 start_col=3 end_line=51 end_col=5} DeclRefExpr=bee:45:8
-// CHECK: {start_line=51 start_col=6 end_line=51 end_col=25} ObjCMessageExpr=catMethodWithFloat::19:1
-// CHECK: {start_line=51 start_col=26 end_line=51 end_col=26} ObjCMessageExpr=floatMethod:20:1
-// CHECK: {start_line=51 start_col=27 end_line=51 end_col=29} DeclRefExpr=bee:45:8
-// CHECK: {start_line=51 start_col=30 end_line=51 end_col=42} ObjCMessageExpr=floatMethod:20:1
-// CHECK: {start_line=51 start_col=43 end_line=51 end_col=43} ObjCMessageExpr=catMethodWithFloat::19:1
-// CHECK: {start_line=51 start_col=44 end_line=52 end_col=2} UnexposedStmt=main
-// CHECK: {start_line=52 start_col=3 end_line=52 end_col=6} DeclRefExpr=main:44:5
-// CHECK: {start_line=52 start_col=7 end_line=52 end_col=7} CallExpr=main:44:5
-// CHECK: {start_line=52 start_col=8 end_line=52 end_col=15} DeclRefExpr=someEnum:41:3
-// CHECK: {start_line=52 start_col=16 end_line=52 end_col=17} CallExpr=main:44:5
-// CHECK: {start_line=52 start_col=18 end_line=52 end_col=32} UnexposedExpr=bee:45:8
-// CHECK: {start_line=52 start_col=33 end_line=52 end_col=35} DeclRefExpr=bee:45:8
-// CHECK: {start_line=52 start_col=36 end_line=52 end_col=36} CallExpr=main:44:5
-// CHECK: {start_line=52 start_col=37 end_line=53 end_col=1} UnexposedStmt=main
+// CHECK: [1:1 - 3:1] Invalid Cursor => NoDeclFound
+// CHECK: [3:1 - 7:1] ObjCInterfaceDecl=Foo:3:12
+// CHECK: [7:1 - 7:7] ObjCInstanceMethodDecl=foo:7:1
+// CHECK: [7:7 - 8:1] ObjCInterfaceDecl=Foo:3:12
+// CHECK: [8:1 - 8:8] ObjCClassMethodDecl=fooC:8:1
+// CHECK: [8:8 - 10:5] ObjCInterfaceDecl=Foo:3:12
+// CHECK: [10:5 - 12:1] Invalid Cursor => NoDeclFound
+// CHECK: [12:1 - 12:18] ObjCInterfaceDecl=Bar:12:12
+// CHECK: [12:18 - 12:21] ObjCSuperClassRef=Foo:3:12
+// CHECK: [12:21 - 16:5] ObjCInterfaceDecl=Bar:12:12
+// CHECK: [16:5 - 18:1] Invalid Cursor => NoDeclFound
+// CHECK: [18:1 - 18:12] ObjCCategoryDecl=FooCat:18:12
+// CHECK: [18:12 - 18:15] ObjCClassRef=Foo:3:12
+// CHECK: [18:15 - 19:1] ObjCCategoryDecl=FooCat:18:12
+// CHECK: [19:1 - 19:29] ObjCInstanceMethodDecl=catMethodWithFloat::19:1
+// CHECK: [19:29 - 19:40] ParmDecl=fArg:19:36 (Definition)
+// CHECK: [19:40 - 19:41] ObjCInstanceMethodDecl=catMethodWithFloat::19:1
+// CHECK: [19:41 - 20:1] ObjCCategoryDecl=FooCat:18:12
+// CHECK: [20:1 - 20:23] ObjCInstanceMethodDecl=floatMethod:20:1
+// CHECK: [20:23 - 21:5] ObjCCategoryDecl=FooCat:18:12
+// CHECK: [21:5 - 23:1] Invalid Cursor => NoDeclFound
+// CHECK: [23:1 - 24:1] ObjCProtocolDecl=Proto:23:1 (Definition)
+// CHECK: [24:1 - 24:11] ObjCInstanceMethodDecl=pMethod:24:1
+// CHECK: [24:11 - 25:5] ObjCProtocolDecl=Proto:23:1 (Definition)
+// CHECK: [25:5 - 27:1] Invalid Cursor => NoDeclFound
+// CHECK: [27:1 - 27:17] ObjCProtocolDecl=SubP:27:1 (Definition)
+// CHECK: [27:17 - 27:22] ObjCProtocolRef=Proto:23:1
+// CHECK: [27:22 - 28:1] ObjCProtocolDecl=SubP:27:1 (Definition)
+// CHECK: [28:1 - 28:12] ObjCInstanceMethodDecl=spMethod:28:1
+// CHECK: [28:12 - 29:5] ObjCProtocolDecl=SubP:27:1 (Definition)
+// CHECK: [29:5 - 31:1] Invalid Cursor => NoDeclFound
+// CHECK: [31:1 - 31:18] ObjCInterfaceDecl=Baz:31:12
+// CHECK: [31:18 - 31:21] ObjCSuperClassRef=Bar:12:12
+// CHECK: [31:21 - 31:23] ObjCInterfaceDecl=Baz:31:12
+// CHECK: [31:23 - 31:27] ObjCProtocolRef=SubP:27:1
+// CHECK: [31:27 - 33:9] ObjCInterfaceDecl=Baz:31:12
+// CHECK: [33:9 - 33:16] ObjCIvarDecl=_anIVar:33:9 (Definition)
+// CHECK: [33:16 - 36:1] ObjCInterfaceDecl=Baz:31:12
+// CHECK: [36:1 - 36:21] ObjCInstanceMethodDecl=bazMethod:36:1
+// CHECK: [36:21 - 38:5] ObjCInterfaceDecl=Baz:31:12
+// CHECK: [38:5 - 40:1] Invalid Cursor => NoDeclFound
+// CHECK: [40:1 - 41:3] EnumDecl=:40:1 (Definition)
+// CHECK: [41:3 - 41:11] EnumConstantDecl=someEnum:41:3 (Definition)
+// CHECK: [41:11 - 42:2] EnumDecl=:40:1 (Definition)
+// CHECK: [42:2 - 44:5] Invalid Cursor => NoDeclFound
+// CHECK: [44:5 - 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:42 - 45:2] UnexposedStmt=
+// CHECK: [45:2 - 45:5] ObjCClassRef=Baz:31:12
+// CHECK: [45:5 - 45:11] VarDecl=bee:45:8 (Definition)
+// CHECK: [45:11 - 45:12] UnexposedStmt=
+// CHECK: [45:12 - 46:2] UnexposedStmt=
+// CHECK: [46:2 - 46:4] TypeRef=id:0:0
+// CHECK: [46:4 - 46:9] VarDecl=a:46:5 (Definition)
+// CHECK: [46:9 - 46:10] ObjCMessageExpr=foo:7:1
+// CHECK: [46:10 - 46:13] DeclRefExpr=bee:45:8
+// CHECK: [46:13 - 46:18] ObjCMessageExpr=foo:7:1
+// CHECK: [46:18 - 46:19] UnexposedStmt=
+// CHECK: [46:19 - 47:2] UnexposedStmt=
+// CHECK: [47:2 - 47:4] TypeRef=id:0:0
+// CHECK: [47:4 - 47:6] VarDecl=c:47:12 (Definition)
+// CHECK: [47:6 - 47:10] ObjCProtocolRef=SubP:27:1
+// CHECK: [47:10 - 47:16] VarDecl=c:47:12 (Definition)
+// CHECK: [47:16 - 47:26] ObjCMessageExpr=fooC:8:1
+// CHECK: [47:26 - 47:27] UnexposedStmt=
+// CHECK: [47:27 - 48:2] UnexposedStmt=
+// CHECK: [48:2 - 48:4] TypeRef=id:0:0
+// CHECK: [48:4 - 48:6] VarDecl=d:48:13 (Definition)
+// CHECK: [48:6 - 48:11] ObjCProtocolRef=Proto:23:1
+// CHECK: [48:11 - 48:14] VarDecl=d:48:13 (Definition)
+// CHECK: [48:14 - 48:15] UnexposedStmt=
+// CHECK: [48:15 - 49:2] UnexposedStmt=
+// CHECK: [49:2 - 49:3] DeclRefExpr=d:48:13
+// CHECK: [49:3 - 49:6] UnexposedExpr=
+// CHECK: [49:6 - 49:7] DeclRefExpr=c:47:12
+// CHECK: [49:7 - 50:2] UnexposedStmt=
+// CHECK: [50:2 - 50:3] ObjCMessageExpr=pMethod:24:1
+// CHECK: [50:3 - 50:4] DeclRefExpr=d:48:13
+// CHECK: [50:4 - 50:13] ObjCMessageExpr=pMethod:24:1
+// CHECK: [50:13 - 51:2] UnexposedStmt=
+// CHECK: [51:2 - 51:3] ObjCMessageExpr=catMethodWithFloat::19:1
+// CHECK: [51:3 - 51:6] DeclRefExpr=bee:45:8
+// CHECK: [51:6 - 51:26] ObjCMessageExpr=catMethodWithFloat::19:1
+// CHECK: [51:26 - 51:27] ObjCMessageExpr=floatMethod:20:1
+// CHECK: [51:27 - 51:30] DeclRefExpr=bee:45:8
+// CHECK: [51:30 - 51:43] ObjCMessageExpr=floatMethod:20:1
+// CHECK: [51:43 - 51:44] ObjCMessageExpr=catMethodWithFloat::19:1
+// CHECK: [51:44 - 52:3] UnexposedStmt=
+// CHECK: [52:3 - 52:7] DeclRefExpr=main:44:5
+// CHECK: [52:7 - 52:8] CallExpr=main:44:5
+// CHECK: [52:8 - 52:16] DeclRefExpr=someEnum:41:3
+// CHECK: [52:16 - 52:18] CallExpr=main:44:5
+// CHECK: [52:18 - 52:33] UnexposedExpr=bee:45:8
+// CHECK: [52:33 - 52:36] DeclRefExpr=bee:45:8
+// CHECK: [52:36 - 52:37] CallExpr=main:44:5
+// CHECK: [52:37 - 53:2] UnexposedStmt=
diff --git a/test/Index/cindex-from-source.m b/test/Index/cindex-from-source.m
index 8f79304cb68b..6c5d936e2066 100644
--- a/test/Index/cindex-from-source.m
+++ b/test/Index/cindex-from-source.m
@@ -4,6 +4,6 @@
// RUN: FileCheck %s < %t
// CHECK: cindex-from-source.m:{{.*}}:{{.*}}: StructDecl=s0:{{.*}}:{{.*}}
// CHECK: cindex-from-source.m:{{.*}}:{{.*}}: VarDecl=g0:{{.*}}:{{.*}}
-// CHECK: cindex-from-source.m:9:1: TypeRef=t0:1:13 [Extent=9:1:9:2]
+// CHECK: cindex-from-source.m:9:1: TypeRef=t0:1:13 Extent=[9:1 - 9:3]
struct s0 {};
t0 g0;
diff --git a/test/Index/cindex-test-inclusions.c b/test/Index/cindex-test-inclusions.c
new file mode 100644
index 000000000000..9c7de2e2c63d
--- /dev/null
+++ b/test/Index/cindex-test-inclusions.c
@@ -0,0 +1,13 @@
+// RUN: c-index-test -test-inclusion-stack-source %s 2>&1 | FileCheck %s
+
+#include "include_test.h"
+
+// CHECK: cindex-test-inclusions.c
+// CHECK: included by:
+// CHECK: include_test.h
+// CHECK: included by:
+// CHECK: cindex-test-inclusions.c:3:10
+// CHECK: include_test_2.h
+// CHECK: included by:
+// CHECK: include_test.h:1:10
+// CHECK: cindex-test-inclusions.c:3:10
diff --git a/test/Index/code-complete-errors.c b/test/Index/code-complete-errors.c
new file mode 100644
index 000000000000..520a8c87df20
--- /dev/null
+++ b/test/Index/code-complete-errors.c
@@ -0,0 +1,16 @@
+_Complex cd; // CHECK: code-complete-errors.c:1:1: warning: plain '_Complex' requires a type specifier; assuming '_Complex double'
+// CHECK: FIX-IT: Insert " double" at 1:9
+struct s {
+ int x, y;; // CHECK: code-complete-errors.c:4:12: warning: extra ';' inside a struct or union
+}; // CHECK: FIX-IT: Remove [4:12 - 4:13]
+
+struct s s0 = { y: 5 }; // CHECK: code-complete-errors.c:7:20: warning: use of GNU old-style field designator extension
+// CHECK: FIX-IT: Replace [7:17 - 7:19] with ".y = "
+int f(int *ptr1, float *ptr2) {
+ return ptr1 != ptr2; // CHECK: code-complete-errors.c:10:15:[10:10 - 10:14][10:18 - 10:22]: warning: comparison of distinct pointer types ('int *' and 'float *')
+}
+
+void g() { }
+
+// RUN: c-index-test -code-completion-at=%s:13:12 -pedantic %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK %s < %t
diff --git a/test/Index/include_test.h b/test/Index/include_test.h
new file mode 100644
index 000000000000..3c40c8dc4dd2
--- /dev/null
+++ b/test/Index/include_test.h
@@ -0,0 +1 @@
+#include "include_test_2.h"
diff --git a/test/Index/include_test_2.h b/test/Index/include_test_2.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Index/include_test_2.h
diff --git a/test/Index/load-exprs.c b/test/Index/load-exprs.c
index a360efd755a4..f72f1046c2e8 100644
--- a/test/Index/load-exprs.c
+++ b/test/Index/load-exprs.c
@@ -4,10 +4,15 @@ void f(void *ptr) {
T* t_ptr = (T *)ptr;
(void)sizeof(T);
struct X x = (struct X){1, 2};
+ void *xx = ptr ? : &x;
}
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// CHECK: load-exprs.c:4:15: TypeRef=T:1:13 [Extent=4:15:4:15]
-// CHECK: load-exprs.c:5:16: TypeRef=T:1:13 [Extent=5:16:5:16]
-// FIXME: the source location for "struct X" points at "struct", not "X"
+// CHECK: load-exprs.c:4:15: TypeRef=T:1:13 Extent=[4:15 - 4:16]
+// CHECK: load-exprs.c:5:16: TypeRef=T:1:13 Extent=[5:16 - 5:17]
+// 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]
diff --git a/test/Index/load-stmts.cpp b/test/Index/load-stmts.cpp
new file mode 100644
index 000000000000..fdfedfb16efb
--- /dev/null
+++ b/test/Index/load-stmts.cpp
@@ -0,0 +1,51 @@
+typedef int T;
+struct X { int a, b; };
+void f(int x) {
+ for (T y = x; T z = x; ++x) {
+ }
+ if (T *z2 = &x) { }
+ while (T *z3 = &x) { }
+ switch (T z4 = x) {
+ case 17: break;
+ }
+}
+
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+// CHECK: load-stmts.cpp:3:6: UnexposedStmt= Extent=[4:3 - 5:4]
+// CHECK: load-stmts.cpp:3:6: UnexposedStmt= Extent=[4:8 - 4:16]
+// 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]
+// CHECK: load-stmts.cpp:4:14: DeclRefExpr=x:3:12 Extent=[4:14 - 4:15]
+// CHECK: load-stmts.cpp:4:19: VarDecl=z:4:19 (Definition) Extent=[4:17 - 4:24]
+// CHECK: load-stmts.cpp:4:17: TypeRef=T:1:13 Extent=[4:17 - 4:18]
+// CHECK: load-stmts.cpp:4:23: DeclRefExpr=x:3:12 Extent=[4:23 - 4:24]
+// CHECK: load-stmts.cpp:4:19: UnexposedExpr=z:4:19 Extent=[4:19 - 4:20]
+// CHECK: load-stmts.cpp:4:19: DeclRefExpr=z:4:19 Extent=[4:19 - 4:20]
+// CHECK: load-stmts.cpp:4:26: UnexposedExpr= Extent=[4:26 - 4:29]
+// CHECK: load-stmts.cpp:4:28: DeclRefExpr=x:3:12 Extent=[4:28 - 4:29]
+// CHECK: load-stmts.cpp:4:19: UnexposedStmt= Extent=[4:31 - 5:4]
+// CHECK: load-stmts.cpp:4:19: UnexposedStmt= Extent=[6:3 - 6:22]
+// CHECK: load-stmts.cpp:6:10: VarDecl=z2:6:10 (Definition) Extent=[6:7 - 6:17]
+// CHECK: load-stmts.cpp:6:7: TypeRef=T:1:13 Extent=[6:7 - 6:8]
+// CHECK: load-stmts.cpp:6:15: UnexposedExpr= Extent=[6:15 - 6:17]
+// CHECK: load-stmts.cpp:6:16: DeclRefExpr=x:3:12 Extent=[6:16 - 6:17]
+// CHECK: load-stmts.cpp:6:10: UnexposedExpr=z2:6:10 Extent=[6:10 - 6:12]
+// CHECK: load-stmts.cpp:6:10: DeclRefExpr=z2:6:10 Extent=[6:10 - 6:12]
+// CHECK: load-stmts.cpp:6:10: UnexposedStmt= Extent=[6:19 - 6:22]
+// CHECK: load-stmts.cpp:6:10: UnexposedStmt= Extent=[7:3 - 7:25]
+// CHECK: load-stmts.cpp:7:13: VarDecl=z3:7:13 (Definition) Extent=[7:10 - 7:20]
+// CHECK: load-stmts.cpp:7:10: TypeRef=T:1:13 Extent=[7:10 - 7:11]
+// CHECK: load-stmts.cpp:7:18: UnexposedExpr= Extent=[7:18 - 7:20]
+// CHECK: load-stmts.cpp:7:19: DeclRefExpr=x:3:12 Extent=[7:19 - 7:20]
+// CHECK: load-stmts.cpp:7:13: UnexposedExpr=z3:7:13 Extent=[7:13 - 7:15]
+// CHECK: load-stmts.cpp:7:13: DeclRefExpr=z3:7:13 Extent=[7:13 - 7:15]
+// CHECK: load-stmts.cpp:7:13: UnexposedStmt= Extent=[7:22 - 7:25]
+// CHECK: load-stmts.cpp:7:13: UnexposedStmt= Extent=[8:3 - 10:4]
+// CHECK: load-stmts.cpp:8:13: VarDecl=z4:8:13 (Definition) Extent=[8:11 - 8:19]
+// CHECK: load-stmts.cpp:8:11: TypeRef=T:1:13 Extent=[8:11 - 8:12]
+// CHECK: load-stmts.cpp:8:18: DeclRefExpr=x:3:12 Extent=[8:18 - 8:19]
+// CHECK: load-stmts.cpp:8:13: DeclRefExpr=z4:8:13 Extent=[8:13 - 8:15]
+// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[8:21 - 10:4]
+// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[9:3 - 9:17]
+// CHECK: load-stmts.cpp:8:13: UnexposedStmt= Extent=[9:12 - 9:17]
+// CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10]
diff --git a/test/Index/remap-cursor-at.c b/test/Index/remap-cursor-at.c
index f7bcf79b759f..fb97d5d62bc7 100644
--- a/test/Index/remap-cursor-at.c
+++ b/test/Index/remap-cursor-at.c
@@ -1,5 +1,5 @@
// RUN: c-index-test -cursor-at=%s:1:15 -cursor-at=%s:2:21 -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck %s
-// RUN: CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -cursor-at=%s:1:15 -cursor-at=%s:2:21 -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck %s
+// RUN: env CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -cursor-at=%s:1:15 -cursor-at=%s:2:21 -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck %s
// CHECK: ParmDecl=parm1:1:13 (Definition)
// CHECK: DeclRefExpr=parm2:1:26
diff --git a/test/Index/remap-load.c b/test/Index/remap-load.c
index 84e45bcda40d..b8415e6a17d4 100644
--- a/test/Index/remap-load.c
+++ b/test/Index/remap-load.c
@@ -1,13 +1,14 @@
// RUN: c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s
-// RUN: CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s
+// RUN: env CINDEXTEST_USE_EXTERNAL_AST_GENERATION=1 c-index-test -test-load-source all -remap-file="%s;%S/Inputs/remap-load-to.c" %s | FileCheck -check-prefix=CHECK %s
+// XFAIL: win32
-// CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) [Extent=1:5:3:1]
-// CHECK: remap-load.c:1:13: ParmDecl=parm1:1:13 (Definition) [Extent=1:9:1:17]
-// CHECK: remap-load.c:1:26: ParmDecl=parm2:1:26 (Definition) [Extent=1:20:1:30]
-// CHECK: remap-load.c:1:5: UnexposedStmt=foo [Extent=1:33:3:1]
-// CHECK: remap-load.c:1:5: UnexposedStmt=foo [Extent=2:3:2:22]
-// CHECK: remap-load.c:2:10: UnexposedExpr= [Extent=2:10:2:22]
-// CHECK: remap-load.c:2:10: UnexposedExpr= [Extent=2:10:2:22]
-// CHECK: remap-load.c:2:10: UnexposedExpr=parm1:1:13 [Extent=2:10:2:14]
-// CHECK: remap-load.c:2:10: DeclRefExpr=parm1:1:13 [Extent=2:10:2:14]
-// CHECK: remap-load.c:2:18: DeclRefExpr=parm2:1:26 [Extent=2:18:2:22]
+// CHECK: remap-load.c:1:5: FunctionDecl=foo:1:5 (Definition) Extent=[1:5 - 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:1:5: UnexposedStmt= Extent=[1:33 - 3:2]
+// CHECK: remap-load.c:1:5: UnexposedStmt= Extent=[2:3 - 2:23]
+// CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23]
+// CHECK: remap-load.c:2:10: UnexposedExpr= Extent=[2:10 - 2:23]
+// CHECK: remap-load.c:2:10: UnexposedExpr=parm1:1:13 Extent=[2:10 - 2:15]
+// CHECK: remap-load.c:2:10: DeclRefExpr=parm1:1:13 Extent=[2:10 - 2:15]
+// CHECK: remap-load.c:2:18: DeclRefExpr=parm2:1:26 Extent=[2:18 - 2:23]
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index 80371a94eb38..e138f59d608c 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -24,3 +24,12 @@ void bar() {
C;
}
+
+// rdar://7597492
+#define sprintf(str, A, B) \
+__builtin___sprintf_chk (str, 0, 42, A, B)
+
+void baz(char *Msg) {
+ sprintf(Msg, " sizeof FoooLib : =%3u\n", 12LL);
+}
+
diff --git a/test/PCH/cxx_exprs.cpp b/test/PCH/cxx_exprs.cpp
index 51269d57b147..0f0fe88dc54a 100644
--- a/test/PCH/cxx_exprs.cpp
+++ b/test/PCH/cxx_exprs.cpp
@@ -1,13 +1,14 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/cxx_exprs.h -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include %S/cxx_exprs.h -std=c++0x -fsyntax-only -verify %s
// Test with pch.
-// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx_exprs.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++-header -std=c++0x -emit-pch -o %t %S/cxx_exprs.h
+// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -verify %s
int integer;
double floating;
char character;
+bool boolean;
// CXXStaticCastExpr
static_cast_result void_ptr = &integer;
@@ -24,3 +25,11 @@ const_cast_result char_ptr = &character;
// CXXFunctionalCastExpr
functional_cast_result *double_ptr = &floating;
+
+// CXXBoolLiteralExpr
+bool_literal_result *bool_ptr = &boolean;
+static_assert(true_value, "true_value is true");
+static_assert(!false_value, "false_value is false");
+
+// CXXNullPtrLiteralExpr
+cxx_null_ptr_result null_ptr = nullptr;
diff --git a/test/PCH/cxx_exprs.h b/test/PCH/cxx_exprs.h
index b64942849419..a871aa201f12 100644
--- a/test/PCH/cxx_exprs.h
+++ b/test/PCH/cxx_exprs.h
@@ -1,21 +1,29 @@
// Header for PCH test cxx_exprs.cpp
// CXXStaticCastExpr
-typedef typeof(static_cast<void *>(0)) static_cast_result;
+typedef __typeof__(static_cast<void *>(0)) static_cast_result;
// CXXDynamicCastExpr
struct Base { virtual void f(); };
struct Derived : Base { };
Base *base_ptr;
-typedef typeof(dynamic_cast<Derived *>(base_ptr)) dynamic_cast_result;
+typedef __typeof__(dynamic_cast<Derived *>(base_ptr)) dynamic_cast_result;
// CXXReinterpretCastExpr
-typedef typeof(reinterpret_cast<void *>(0)) reinterpret_cast_result;
+typedef __typeof__(reinterpret_cast<void *>(0)) reinterpret_cast_result;
// CXXConstCastExpr
const char *const_char_ptr_value;
-typedef typeof(const_cast<char *>(const_char_ptr_value)) const_cast_result;
+typedef __typeof__(const_cast<char *>(const_char_ptr_value)) const_cast_result;
// CXXFunctionalCastExpr
int int_value;
-typedef typeof(double(int_value)) functional_cast_result;
+typedef __typeof__(double(int_value)) functional_cast_result;
+
+// CXXBoolLiteralExpr
+typedef __typeof__(true) bool_literal_result;
+const bool true_value = true;
+const bool false_value = false;
+
+// CXXNullPtrLiteralExpr
+typedef __typeof__(nullptr) cxx_null_ptr_result;
diff --git a/test/Parser/altivec.c b/test/Parser/altivec.c
new file mode 100644
index 000000000000..99544ea5c103
--- /dev/null
+++ b/test/Parser/altivec.c
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -faltivec -fsyntax-only -verify %s
+
+__vector char vv_c;
+__vector signed char vv_sc;
+__vector unsigned char vv_uc;
+__vector short vv_s;
+__vector signed short vv_ss;
+__vector unsigned short vv_us;
+__vector short int vv_si;
+__vector signed short int vv_ssi;
+__vector unsigned short int vv_usi;
+__vector int vv_i;
+__vector signed int vv_sint;
+__vector unsigned int vv_ui;
+__vector float vv_f;
+__vector bool vv_b;
+__vector __pixel vv_p;
+__vector pixel vv__p;
+__vector int vf__r();
+void vf__a(__vector int a);
+void vf__a2(int b, __vector int a);
+
+vector char v_c;
+vector signed char v_sc;
+vector unsigned char v_uc;
+vector short v_s;
+vector signed short v_ss;
+vector unsigned short v_us;
+vector short int v_si;
+vector signed short int v_ssi;
+vector unsigned short int v_usi;
+vector int v_i;
+vector signed int v_sint;
+vector unsigned int v_ui;
+vector float v_f;
+vector bool v_b;
+vector __pixel v_p;
+vector pixel v__p;
+vector int f__r();
+void f_a(vector int a);
+void f_a2(int b, vector int a);
+
+// These should have warnings.
+__vector long vv_l; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector signed long vv_sl; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector unsigned long vv_ul; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector long int vv_li; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector signed long int vv_sli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector unsigned long int vv_uli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector long v_l; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector signed long v_sl; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector unsigned long v_ul; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector long int v_li; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector signed long int v_sli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector unsigned long int v_uli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector long double vv_ld; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+vector long double v_ld; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+
+// These should have errors.
+__vector double vv_d; // expected-error {{cannot use "double" with "__vector"}}
+__vector double vv_d; // expected-error {{cannot use "double" with "__vector"}}
+vector double v_d; // expected-error {{cannot use "double" with "__vector"}}
+vector double v_d; // expected-error {{cannot use "double" with "__vector"}}
+__vector long double vv_ld; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+vector long double v_ld; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+
+void f() {
+ __vector unsigned int v = {0,0,0,0};
+ __vector int v__cast = (__vector int)v;
+ __vector int v_cast = (vector int)v;
+ __vector char vb_cast = (vector char)v;
+
+ // Check some casting between gcc and altivec vectors.
+ #define gccvector __attribute__((vector_size(16)))
+ gccvector unsigned int gccv = {0,0,0,0};
+ gccvector unsigned int gccv1 = gccv;
+ gccvector int gccv2 = (gccvector int)gccv;
+ gccvector unsigned int gccv3 = v;
+ __vector unsigned int av = gccv;
+ __vector int avi = (__vector int)gccv;
+ gccvector unsigned int gv = v;
+ gccvector int gvi = (gccvector int)v;
+ __attribute__((vector_size(8))) unsigned int gv8;
+ gv8 = gccv; // expected-error {{incompatible type assigning '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int', expected '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int'}}
+ av = gv8; // expected-error {{incompatible type assigning '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int', expected '__vector unsigned int'}}
+
+ v = gccv;
+ __vector unsigned int tv = gccv;
+ gccv = v;
+ gccvector unsigned int tgv = v;
+}
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
new file mode 100644
index 000000000000..a26eee4ef487
--- /dev/null
+++ b/test/Parser/cxx-altivec.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -faltivec -fsyntax-only -verify %s
+
+// This is the same as the C version:
+
+__vector char vv_c;
+__vector signed char vv_sc;
+__vector unsigned char vv_uc;
+__vector short vv_s;
+__vector signed short vv_ss;
+__vector unsigned short vv_us;
+__vector short int vv_si;
+__vector signed short int vv_ssi;
+__vector unsigned short int vv_usi;
+__vector int vv_i;
+__vector signed int vv_sint;
+__vector unsigned int vv_ui;
+__vector float vv_f;
+__vector bool vv_b;
+__vector __pixel vv_p;
+__vector pixel vv__p;
+__vector int vf__r();
+void vf__a(__vector int a);
+void vf__a2(int b, __vector int a);
+
+vector char v_c;
+vector signed char v_sc;
+vector unsigned char v_uc;
+vector short v_s;
+vector signed short v_ss;
+vector unsigned short v_us;
+vector short int v_si;
+vector signed short int v_ssi;
+vector unsigned short int v_usi;
+vector int v_i;
+vector signed int v_sint;
+vector unsigned int v_ui;
+vector float v_f;
+vector bool v_b;
+vector __pixel v_p;
+vector pixel v__p;
+vector int f__r();
+void f_a(vector int a);
+void f_a2(int b, vector int a);
+
+// These should have warnings.
+__vector long vv_l; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector signed long vv_sl; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector unsigned long vv_ul; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector long int vv_li; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector signed long int vv_sli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector unsigned long int vv_uli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector long v_l; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector signed long v_sl; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector unsigned long v_ul; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector long int v_li; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector signed long int v_sli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+vector unsigned long int v_uli; // expected-warning {{Use of "long" with "__vector" is deprecated}}
+__vector long double vv_ld; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+vector long double v_ld; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+
+// These should have errors.
+__vector double vv_d1; // expected-error {{cannot use "double" with "__vector"}}
+vector double v_d2; // expected-error {{cannot use "double" with "__vector"}}
+__vector long double vv_ld3; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+vector long double v_ld4; // expected-warning {{Use of "long" with "__vector" is deprecated}} expected-error {{cannot use "double" with "__vector"}}
+
+void f() {
+ __vector unsigned int v = {0,0,0,0};
+ __vector int v__cast = (__vector int)v;
+ __vector int v_cast = (vector int)v;
+ __vector char vb_cast = (vector char)v;
+
+ // Check some casting between gcc and altivec vectors.
+ #define gccvector __attribute__((vector_size(16)))
+ gccvector unsigned int gccv = {0,0,0,0};
+ gccvector unsigned int gccv1 = gccv;
+ gccvector int gccv2 = (gccvector int)gccv;
+ gccvector unsigned int gccv3 = v;
+ __vector unsigned int av = gccv;
+ __vector int avi = (__vector int)gccv;
+ gccvector unsigned int gv = v;
+ gccvector int gvi = (gccvector int)v;
+ __attribute__((vector_size(8))) unsigned int gv8;
+ gv8 = gccv; // expected-error {{incompatible type assigning '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int', expected '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int'}}
+ av = gv8; // expected-error {{incompatible type assigning '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int', expected '__vector unsigned int'}}
+
+ v = gccv;
+ __vector unsigned int tv = gccv;
+ gccv = v;
+ gccvector unsigned int tgv = v;
+}
+
+// Now for the C++ version:
+
+class vc__v {
+ __vector int v;
+ __vector int f__r();
+ void f__a(__vector int a);
+ void f__a2(int b, __vector int a);
+};
+
+class c_v {
+ vector int v;
+ vector int f__r();
+ void f__a(vector int a);
+ void f__a2(int b, vector int a);
+};
+
diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp
index 3c88b7adfa84..f37604cc5443 100644
--- a/test/Parser/cxx-decl.cpp
+++ b/test/Parser/cxx-decl.cpp
@@ -52,3 +52,9 @@ void test(struct Type *P) {
(y:b) // expected-error {{unexpected ':' in nested name specifier}}
4) : 5;
}
+
+struct test4 {
+ int x // expected-error {{expected ';' at end of declaration list}}
+ int y;
+ int z // expected-error {{expected ';' at end of declaration list}}
+};
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 5cb84a63069b..3f8f1ec9d0be 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -96,3 +96,13 @@ void f2() {
// PR3844
template <> struct S<int> { }; // expected-error{{explicit specialization of non-template struct 'S'}}
+
+namespace PR6184 {
+ namespace N {
+ template <typename T>
+ void bar(typename T::x);
+ }
+
+ template <typename T>
+ void N::bar(typename T::x) { }
+}
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
index 3831199c8d71..91803c1c5d79 100644
--- a/test/Parser/declarators.c
+++ b/test/Parser/declarators.c
@@ -47,8 +47,8 @@ int test6() { return a; } // a should be declared.
// Use of tagged type without tag. rdar://6783347
struct xyz { int y; };
enum myenum { ASDFAS };
-xyz b; // expected-error {{use of tagged type 'xyz' without 'struct' tag}}
-myenum c; // expected-error {{use of tagged type 'myenum' without 'enum' tag}}
+xyz b; // expected-error {{must use 'struct' tag to refer to type 'xyz'}}
+myenum c; // expected-error {{must use 'enum' tag to refer to type 'myenum'}}
float *test7() {
// We should recover 'b' by parsing it with a valid type of "struct xyz", which
@@ -64,3 +64,22 @@ static f; // expected-warning {{type specifier missing, defaults to 'int'}}
static g = 4; // expected-warning {{type specifier missing, defaults to 'int'}}
static h // expected-warning {{type specifier missing, defaults to 'int'}}
__asm__("foo");
+
+
+struct test9 {
+ int x // expected-error {{expected ';' at end of declaration list}}
+ int y;
+ int z // expected-warning {{expected ';' at end of declaration list}}
+};
+
+// PR6208
+struct test10 { int a; } static test10x;
+struct test11 { int a; } const test11x;
+
+// PR6216
+void test12() {
+ (void)__builtin_offsetof(struct { char c; int i; }, i);
+}
+
+// rdar://7608537
+struct test13 { int a; } (test13x);
diff --git a/test/Parser/objc-property-syntax.m b/test/Parser/objc-property-syntax.m
index b5f57f305f39..064a2090b005 100644
--- a/test/Parser/objc-property-syntax.m
+++ b/test/Parser/objc-property-syntax.m
@@ -5,8 +5,10 @@
};
@property unsigned char bufferedUTF8Bytes[4]; // expected-error {{property cannot have array or function type}}
@property unsigned char bufferedUTFBytes:1; // expected-error {{property name cannot be a bitfield}}
+@property(nonatomic, retain, setter=ab_setDefaultToolbarItems) MyClass *ab_defaultToolbarItems; // expected-error {{method name referenced in property setter attribute must end with ':'}}
@end
@implementation MyClass
+@dynamic ab_defaultToolbarItems;
@end
diff --git a/test/Parser/statements.c b/test/Parser/statements.c
index 8fec0f1b262f..a662c9b82118 100644
--- a/test/Parser/statements.c
+++ b/test/Parser/statements.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unreachable-code
void test1() {
{ ; { ;;}} ;;
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index a1485b65013f..cccee762e264 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -443,7 +443,6 @@
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=pic16-none-none < /dev/null | FileCheck -check-prefix PIC16 %s
//
-// PIC16:#define _CONFIG(conf) asm("CONFIG "#conf)
// PIC16:#define __CHAR_BIT__ 8
// PIC16:#define __DBL_DENORM_MIN__ 1.40129846e-45F
// PIC16:#define __DBL_DIG__ 6
@@ -500,6 +499,7 @@
// PIC16:#define __LONG_LONG_MAX__ 2147483647LL
// PIC16:#define __LONG_MAX__ 2147483647L
// PIC16:#define __NO_INLINE__ 1
+// PIC16:#define __PIC16 1
// PIC16:#define __POINTER_WIDTH__ 16
// PIC16:#define __PTRDIFF_TYPE__ int
// PIC16:#define __PTRDIFF_WIDTH__ 16
@@ -515,12 +515,15 @@
// PIC16:#define __WCHAR_WIDTH__ 16
// PIC16:#define __WINT_TYPE__ int
// PIC16:#define __WINT_WIDTH__ 16
+// PIC16:#define __address(Addr) __attribute__((section("Address="#Addr)))
// PIC16:#define __clang__ 1
+// PIC16:#define __config(conf) asm("CONFIG "#conf)
+// PIC16:#define __idlocs(value) asm("__IDLOCS "#value)
// PIC16:#define __llvm__ 1
// PIC16:#define __pic16 1
-// PIC16:#define _address(Addr) __attribute__((section("Address="#Addr)))
-// PIC16:#define _interrupt __attribute__((section("interrupt=0x4"))) __attribute__((used))
-// PIC16:#define _section(SectName) __attribute__((section(SectName)))
+// PIC16:#define __section(SectName) __attribute__((section(SectName)))
+// PIC16:#define interrupt __attribute__((section("interrupt=0x4"))) __attribute__((used))
+// PIC16:#define near __attribute__((section("Address=NEAR")))
// PIC16:#define ram __attribute__((address_space(0)))
// PIC16:#define rom __attribute__((address_space(1)))
//
diff --git a/test/Preprocessor/mi_opt2.c b/test/Preprocessor/mi_opt2.c
new file mode 100644
index 000000000000..198d19fdb7ac
--- /dev/null
+++ b/test/Preprocessor/mi_opt2.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -E %s | FileCheck %s
+// PR6282
+// This test should not trigger the include guard optimization since
+// the guard macro is defined on the first include.
+
+#define ITERATING 1
+#define X 1
+#include "mi_opt2.h"
+#undef X
+#define X 2
+#include "mi_opt2.h"
+
+// CHECK: b: 1
+// CHECK: b: 2
+
diff --git a/test/Preprocessor/mi_opt2.h b/test/Preprocessor/mi_opt2.h
new file mode 100644
index 000000000000..df37eba81870
--- /dev/null
+++ b/test/Preprocessor/mi_opt2.h
@@ -0,0 +1,5 @@
+#ifndef ITERATING
+a: X
+#else
+b: X
+#endif
diff --git a/test/Rewriter/blockcast3.mm b/test/Rewriter/blockcast3.mm
new file mode 100644
index 000000000000..97f417cec9ef
--- /dev/null
+++ b/test/Rewriter/blockcast3.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7607781
+
+typedef struct {
+ int a;
+ int b;
+} mystruct;
+
+void g(int (^block)(mystruct s)) {
+ mystruct x;
+ int v = block(x);
+}
+
+void f(const void **arg) {
+ __block const void **q = arg;
+ g(^(mystruct s){
+ *q++ = (void*)s.a;
+ return 314;
+ });
+}
+
+// CHECK-LP: (struct __Block_byref_q_0 *)&q
diff --git a/test/Rewriter/rewrite-block-pointer.mm b/test/Rewriter/rewrite-block-pointer.mm
new file mode 100644
index 000000000000..b03b7a9dec0a
--- /dev/null
+++ b/test/Rewriter/rewrite-block-pointer.mm
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7638400
+
+@interface X
+@end
+
+void foo(void (^block)(int));
+
+@implementation X
+static void enumerateIt(void (^block)(id, id, char *)) {
+ foo(^(int idx) { });
+}
+@end
+
+// CHECK-LP: static void enumerateIt(void (*)(id, id, char *));
diff --git a/test/Rewriter/rewrite-byref-vars.mm b/test/Rewriter/rewrite-byref-vars.mm
index 1489c5947293..58b925a2b28c 100644
--- a/test/Rewriter/rewrite-byref-vars.mm
+++ b/test/Rewriter/rewrite-byref-vars.mm
@@ -36,9 +36,19 @@ __declspec(dllexport) extern "C" __declspec(dllexport) void XXXXBreakTheRewriter
id list;
}
- (void) Meth;
+// radar 7589385 use before definition
+- (void) allObjects;
@end
@implementation I
+// radar 7589385 use before definition
+- (void) allObjects {
+ __attribute__((__blocks__(byref))) id *listp;
+
+ ^(void) {
+ *listp++ = 0;
+ };
+}
- (void) Meth { __attribute__((__blocks__(byref))) void ** listp = (void **)list; }
@end
diff --git a/test/Rewriter/rewrite-cast-ivar-access.mm b/test/Rewriter/rewrite-cast-ivar-access.mm
new file mode 100644
index 000000000000..c04cbab40369
--- /dev/null
+++ b/test/Rewriter/rewrite-cast-ivar-access.mm
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7575882
+
+@interface F {
+ int supervar;
+}
+@end
+
+@interface G : F {
+@public
+ int ivar;
+}
+@end
+
+@implementation G
+- (void)foo:(F *)arg {
+ int q = arg->supervar;
+ int v = ((G *)arg)->ivar;
+}
+@end
+
+void objc_assign_strongCast(id);
+void __CFAssignWithWriteBarrier(void **location, void *value) {
+ objc_assign_strongCast((id)value);
+}
+
+// radar 7607605
+@interface RealClass {
+ @public
+ int f;
+}
+@end
+
+@implementation RealClass
+@end
+
+@interface Foo {
+ id reserved;
+}
+@end
+
+@implementation Foo
+- (void)bar {
+ ((RealClass*)reserved)->f = 99;
+}
+@end
+
+// CHECK-LP: ((struct G_IMPL *)arg)->ivar
+
+// CHECK-LP: objc_assign_strongCast((id)value)
+
+// CHECK-LP: ((struct RealClass_IMPL *)((RealClass *)((struct Foo_IMPL *)self)->reserved))->f
diff --git a/test/Rewriter/rewrite-category-property.mm b/test/Rewriter/rewrite-category-property.mm
new file mode 100644
index 000000000000..6b8f07622234
--- /dev/null
+++ b/test/Rewriter/rewrite-category-property.mm
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7630636
+
+@class Y, Z;
+
+@interface A
+@property (readonly) Y *y;
+@end
+
+@interface A (cat)
+@property (readonly) Z *z;
+@end
+
+// CHECK-LP: // @property (readonly) Z *z;
diff --git a/test/Rewriter/rewrite-implementation.mm b/test/Rewriter/rewrite-implementation.mm
new file mode 100644
index 000000000000..608707c43034
--- /dev/null
+++ b/test/Rewriter/rewrite-implementation.mm
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -DSEL="void *" -S %t-rw.cpp
+// radar 7649577
+
+@interface a
+@end
+
+@interface b : a
+@end
+
+@implementation b
+@end
+
diff --git a/test/Rewriter/rewrite-message-expr.mm b/test/Rewriter/rewrite-message-expr.mm
new file mode 100644
index 000000000000..d909f3ef93c3
--- /dev/null
+++ b/test/Rewriter/rewrite-message-expr.mm
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7617047
+
+@interface Baz
+- (id)y;
++ (id)z;
+@end
+
+@interface Foo {
+@public
+ int bar;
+}
+@end
+
+extern Foo* x(id a);
+
+int f(Baz *baz) {
+ int i = x([Baz z])->bar;
+ int j = ((Foo*)[Baz z])->bar;
+ int k = x([baz y])->bar;
+ return i+j+k;
+}
+
+// CHECK-LP: ((struct Foo_IMPL *)x(((id (*)(id, SEL))(void *)objc_msgSend)(objc_getClass("Baz"), sel_registerName("z"))))->bar
diff --git a/test/Rewriter/rewrite-nested-ivar.mm b/test/Rewriter/rewrite-nested-ivar.mm
new file mode 100644
index 000000000000..bbc9d28d2513
--- /dev/null
+++ b/test/Rewriter/rewrite-nested-ivar.mm
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7583971
+
+
+@interface NSURLResponse {
+@public
+ NSURLResponse *InnerResponse;
+}
+@end
+
+@interface NSCachedURLResponseInternal
+{
+ @public
+ NSURLResponse *response;
+}
+@end
+
+@interface NSCachedURLResponse
+{
+ @private
+ NSCachedURLResponseInternal *_internal;
+}
+- (void) Meth;
+@end
+
+@implementation NSCachedURLResponse
+- (void) Meth {
+ _internal->response->InnerResponse = 0;
+ }
+@end
+
+// CHECK-LP: ((struct NSURLResponse_IMPL *)((struct NSCachedURLResponseInternal_IMPL *)((struct NSCachedURLResponse_IMPL *)self)->_internal)->response)->InnerResponse
diff --git a/test/Rewriter/rewrite-protocol-qualified.mm b/test/Rewriter/rewrite-protocol-qualified.mm
new file mode 100644
index 000000000000..e91c3db8616f
--- /dev/null
+++ b/test/Rewriter/rewrite-protocol-qualified.mm
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7589414
+
+@protocol NSPortDelegate;
+@interface NSConnection @end
+
+@interface NSMessagePort
+- (void) clone;
+@end
+
+@implementation NSMessagePort
+- (void) clone {
+ NSConnection <NSPortDelegate> *conn = 0;
+ id <NSPortDelegate> *idc = 0;
+}
+@end
+
+// radar 7607413
+@protocol Proto1, Proto2;
+
+@protocol Proto
+@end
+
+unsigned char func(id<Proto1, Proto2> inProxy);
+
+id bar(id);
+
+void f() {
+ id a;
+ id b = bar((id <Proto>)a);
+}
+
+// CHECK-LP: NSConnection /*<NSPortDelegate>*/ *conn = 0;
+
+// CHECK-LP: id /*<NSPortDelegate>*/ *idc = 0;
+
+// CHECK-LP: func(id/*<Proto1, Proto2>*/ inProxy);
+
+// CHECK-LP: bar((id /*<Proto>*/)a);
+
diff --git a/test/Rewriter/rewrite-typeof.mm b/test/Rewriter/rewrite-typeof.mm
index f95cd9ac7c76..b859ac3d684c 100644
--- a/test/Rewriter/rewrite-typeof.mm
+++ b/test/Rewriter/rewrite-typeof.mm
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -o - %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
extern "C" {
extern "C" void *_Block_copy(const void *aBlock);
@@ -18,3 +19,21 @@ int main() {
return 0;
}
+// CHECK-LP: ((void (^)(void))_Block_copy((const void *)(b)))
+
+// radar 7628153
+void f() {
+ int a;
+ __typeof__(a) aVal = a;
+ char *a1t = (char *)@encode(__typeof__(a));
+ __typeof__(aVal) bVal;
+ char *a2t = (char *)@encode(__typeof__(bVal));
+ __typeof__(bVal) cVal = bVal;
+ char *a3t = (char *)@encode(__typeof__(cVal));
+
+}
+
+
+// CHECK-LP: int aVal = a;
+
+// CHECK-LP: int bVal;
diff --git a/test/Rewriter/rewrite-unique-block-api.mm b/test/Rewriter/rewrite-unique-block-api.mm
new file mode 100644
index 000000000000..780a3f0a5e2b
--- /dev/null
+++ b/test/Rewriter/rewrite-unique-block-api.mm
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// radar 7630551
+
+void f(void (^b)(char c));
+
+@interface a
+- (void)processStuff;
+@end
+
+@implementation a
+- (void)processStuff {
+ f(^(char x) { });
+}
+@end
+
+@interface b
+- (void)processStuff;
+@end
+
+@implementation b
+- (void)processStuff {
+ f(^(char x) { });
+}
+@end
+
+// CHECK-LP: struct __a__processStuff_block_impl_0
+// CHECK-LP: static void __a__processStuff_block_func_0
+
+// CHECK-LP: struct __b__processStuff_block_impl_0
+// CHECK-LP: static void __b__processStuff_block_func_0
diff --git a/test/Sema/Inputs/conversion.h b/test/Sema/Inputs/conversion.h
new file mode 100644
index 000000000000..9f6ed2e70fb2
--- /dev/null
+++ b/test/Sema/Inputs/conversion.h
@@ -0,0 +1,3 @@
+/* Fake system header for Sema/conversion.c */
+
+#define LONG_MAX __LONG_MAX__
diff --git a/test/Sema/arm-layout.c b/test/Sema/arm-layout.c
new file mode 100644
index 000000000000..1e239d275a82
--- /dev/null
+++ b/test/Sema/arm-layout.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple armv7-unknown-unknown -target-abi apcs-gnu %s -verify
+// RUN: %clang_cc1 -triple armv7-unknown-unknown -target-abi aapcs %s -verify
+
+#ifdef __ARM_EABI__
+
+struct s0 { char field0; double field1; };
+int g0[sizeof(struct s0) == 16 ? 1 : -1];
+
+struct s1 { char field0; long double field1; };
+int g1[sizeof(struct s1) == 16 ? 1 : -1];
+
+#else
+
+struct s0 { char field0; double field1; };
+int g0[sizeof(struct s0) == 12 ? 1 : -1];
+
+struct s1 { char field0; long double field1; };
+int g1[sizeof(struct s1) == 12 ? 1 : -1];
+
+#endif
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 18d900c80dd4..6f2272da9e77 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -76,3 +76,6 @@ int test7(unsigned long long b) {
asm volatile("foo %0 %1" : "=a" (a) :"0" (b)); // expected-error {{input with type 'unsigned long long' matching output with type 'int'}}
return a;
}
+
+// <rdar://problem/7574870>
+asm volatile (""); // expected-warning {{meaningless 'volatile' on asm outside function}}
diff --git a/test/Sema/attr-mode.c b/test/Sema/attr-mode.c
index 9acd2c6f65d3..0c5336282c4d 100644
--- a/test/Sema/attr-mode.c
+++ b/test/Sema/attr-mode.c
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -DTEST_32BIT_X86 -fsyntax-only \
+// RUN: -verify %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -DTEST_64BIT_X86 -fsyntax-only \
+// RUN: -verify %s
typedef int i16_1 __attribute((mode(HI)));
int i16_1_test[sizeof(i16_1) == 2 ? 1 : -1];
@@ -20,3 +23,37 @@ typedef _Complex double c32 __attribute((mode(SC)));
int c32_test[sizeof(c32) == 8 ? 1 : -1];
typedef _Complex float c64 __attribute((mode(DC)));
typedef _Complex float c80 __attribute((mode(XC)));
+
+// PR6108: Correctly select 'long' built in type on 64-bit platforms for 64 bit
+// modes. Also test other mode-based conversions.
+typedef int i8_mode_t __attribute__ ((__mode__ (__QI__)));
+typedef unsigned int ui8_mode_t __attribute__ ((__mode__ (__QI__)));
+typedef int i16_mode_t __attribute__ ((__mode__ (__HI__)));
+typedef unsigned int ui16_mode_t __attribute__ ((__mode__ (__HI__)));
+typedef int i32_mode_t __attribute__ ((__mode__ (__SI__)));
+typedef unsigned int ui32_mode_t __attribute__ ((__mode__ (__SI__)));
+typedef int i64_mode_t __attribute__ ((__mode__ (__DI__)));
+typedef unsigned int ui64_mode_t __attribute__ ((__mode__ (__DI__)));
+void f_i8_arg(i8_mode_t* x) { (void)x; }
+void f_ui8_arg(ui8_mode_t* x) { (void)x; }
+void f_i16_arg(i16_mode_t* x) { (void)x; }
+void f_ui16_arg(ui16_mode_t* x) { (void)x; }
+void f_i32_arg(i32_mode_t* x) { (void)x; }
+void f_ui32_arg(ui32_mode_t* x) { (void)x; }
+void f_i64_arg(i64_mode_t* x) { (void)x; }
+void f_ui64_arg(ui64_mode_t* x) { (void)x; }
+void test_char_to_i8(signed char* y) { f_i8_arg(y); }
+void test_char_to_ui8(unsigned char* y) { f_ui8_arg(y); }
+void test_short_to_i16(short* y) { f_i16_arg(y); }
+void test_short_to_ui16(unsigned short* y) { f_ui16_arg(y); }
+void test_int_to_i32(int* y) { f_i32_arg(y); }
+void test_int_to_ui32(unsigned int* y) { f_ui32_arg(y); }
+#if TEST_32BIT_X86
+void test_long_to_i64(long long* y) { f_i64_arg(y); }
+void test_long_to_ui64(unsigned long long* y) { f_ui64_arg(y); }
+#elif TEST_64BIT_X86
+void test_long_to_i64(long* y) { f_i64_arg(y); }
+void test_long_to_ui64(unsigned long* y) { f_ui64_arg(y); }
+#else
+#error Unknown test architecture.
+#endif
diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c
index 3f064a01c867..b17f9fd12920 100644
--- a/test/Sema/attr-noreturn.c
+++ b/test/Sema/attr-noreturn.c
@@ -11,7 +11,7 @@ static void __attribute__((noreturn)) f0(void) {
// On K&R
int f1() __attribute__((noreturn));
-int g0 __attribute__((noreturn)); // expected-warning {{'noreturn' attribute only applies to function types}}
+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)}}
diff --git a/test/Sema/block-args.c b/test/Sema/block-args.c
index 08af9b377361..a07c82e75afa 100644
--- a/test/Sema/block-args.c
+++ b/test/Sema/block-args.c
@@ -27,3 +27,9 @@ int main(int argc, char** argv) {
argCount = 3;
}(argc);
}
+
+// radar 7528255
+void f0() {
+ ^(int, double d, char) {}(1, 1.34, 'a'); // expected-error {{parameter name omitted}} \
+ // expected-error {{parameter name omitted}}
+}
diff --git a/test/Sema/block-printf-attribute-1.c b/test/Sema/block-printf-attribute-1.c
index 8ea77ece12d8..c19b3788a3a4 100644
--- a/test/Sema/block-printf-attribute-1.c
+++ b/test/Sema/block-printf-attribute-1.c
@@ -6,7 +6,6 @@ int main() {
void (^z) (int arg, const char * format, ...) __attribute__ ((__format__ (__printf__, 2, 3))) = ^ __attribute__ ((__format__ (__printf__, 2, 3))) (int arg, const char * format, ...) {};
- // FIXME: argument type poking not yet supportted.
- z(1, "%s", 1); /* { dg-warning "format \\'\%s\\' expects type \\'char \\*\\'\, but argument 3 has type \\'int\\'" } */
- z(1, "%s", "HELLO"); // OK
+ z(1, "%s", 1); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+ z(1, "%s", "HELLO"); // no-warning
}
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index 6416545cb7ea..2385106630d7 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -109,7 +109,7 @@ void foo6() {
void foo7()
{
- const int (^BB) (void) = ^{ const int i = 1; return i; }; // OK
+ const int (^BB) (void) = ^{ const int i = 1; return i; }; // expected-error{{incompatible block pointer types initializing 'int (^)(void)', expected 'int const (^)(void)'}}
const int (^CC) (void) = ^const int{ const int i = 1; return i; }; // OK
int i;
@@ -123,9 +123,8 @@ void foo7()
__block const int k;
const int cint = 100;
- int (^MM) (void) = ^{ return k; }; // expected-error {{incompatible block pointer types initializing 'int const (^)(void)', expected 'int (^)(void)'}}
- int (^NN) (void) = ^{ return cint; }; // expected-error {{incompatible block pointer types initializing 'int const (^)(void)', expected 'int (^)(void)'}}
-
+ int (^MM) (void) = ^{ return k; };
+ int (^NN) (void) = ^{ return cint; };
}
diff --git a/test/Sema/builtin-unary-fp.c b/test/Sema/builtin-unary-fp.c
index 8f48d7ffc56c..57568db8ae3f 100644
--- a/test/Sema/builtin-unary-fp.c
+++ b/test/Sema/builtin-unary-fp.c
@@ -9,4 +9,8 @@ void a() {
check(__builtin_isfinite(1)); // expected-error{{requires argument of floating point type}}
check(__builtin_isinf()); // expected-error{{too few arguments}}
check(__builtin_isnan(1,2)); // expected-error{{too many arguments}}
+ check(__builtin_fpclassify(0, 0, 0, 0, 0, 1.0));
+ check(__builtin_fpclassify(0, 0, 0, 0, 0, 1)); // expected-error{{requires argument of floating point type}}
+ check(__builtin_fpclassify(0, 0, 0, 0, 1)); // expected-error{{too few arguments}}
+ check(__builtin_fpclassify(0, 0, 0, 0, 0, 1, 0)); // expected-error{{too many arguments}}
}
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
index a32a4953084d..0752606ed908 100644
--- a/test/Sema/callingconv.c
+++ b/test/Sema/callingconv.c
@@ -9,15 +9,30 @@ void __attribute__((stdcall)) bar(float *a) {
void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{attribute requires 0 argument(s)}}
}
-void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use 'fastcall' calling convention}}
+void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use fastcall calling convention}}
}
void __attribute__((fastcall)) test1(void) {
}
-void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic function cannot use 'fastcall' calling convention}}
+void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic function cannot use fastcall calling convention}}
}
void __attribute__((cdecl)) ctest0() {}
void __attribute__((cdecl(1))) ctest1(float x) {} // expected-error {{attribute requires 0 argument(s)}}
+
+void (__attribute__((fastcall)) *pfoo)(float*) = foo;
+
+void (__attribute__((stdcall)) *pbar)(float*) = bar;
+
+void (__attribute__((cdecl)) *ptest1)(void) = test1; // expected-warning {{incompatible pointer types}}
+
+void (*pctest0)() = ctest0;
+
+void ctest2() {}
+void (__attribute__((cdecl)) *pctest2)() = ctest2;
+
+typedef void (__attribute__((fastcall)) *Handler) (float *);
+Handler H = foo;
+
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 579c3e5d6bdc..2821a935c3c7 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare %s -Wno-unreachable-code
int test(char *C) { // nothing here should warn.
return C != ((void*)0);
diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c
index fee8d97f9bb4..9c537250a93a 100644
--- a/test/Sema/const-eval.c
+++ b/test/Sema/const-eval.c
@@ -75,3 +75,4 @@ EVAL_EXPR(35, constbool)
EVAL_EXPR(36, constbool)
EVAL_EXPR(37, (1,2.0) == 2.0)
+EVAL_EXPR(38, __builtin_expect(1,1) == 1)
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index 298bf7564219..8b93a4662821 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wconversion -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconversion -nostdinc -isystem %S/Inputs -triple x86_64-apple-darwin %s -Wno-unreachable-code
+
+#include <conversion.h>
#define BIG 0x7f7f7f7f7f7f7f7fL
@@ -271,3 +273,9 @@ unsigned char test19(unsigned long u64) {
unsigned char x3 = u64 & mask;
return x1 + x2 + x3;
}
+
+// <rdar://problem/7631400>
+void test_7631400(void) {
+ // This should show up despite the caret being inside a macro substitution
+ char s = LONG_MAX; // expected-warning {{implicit cast loses integer precision: 'long' to 'char'}}
+}
diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c
index 5b1196016032..d9f4157ab3db 100644
--- a/test/Sema/declspec.c
+++ b/test/Sema/declspec.c
@@ -7,11 +7,13 @@ void foof(const char *, ...) __attribute__((__format__(__printf__, 1, 2))), barf
int typedef validTypeDecl() { } // expected-error {{function definition declared 'typedef'}}
-struct _zend_module_entry { }
-typedef struct _zend_function_entry { } // expected-error {{cannot combine with previous 'struct' declaration specifier}}
-static void buggy(int *x) { } // expected-error {{function definition declared 'typedef'}} \
- // expected-error {{cannot combine with previous 'typedef' declaration specifier}} \
- // expected-error {{cannot combine with previous 'struct' declaration specifier}}
+struct _zend_module_entry { } // expected-error {{expected ';' after struct}}
+int gv1;
+typedef struct _zend_function_entry { } // expected-error {{expected ';' after struct}} \
+ // expected-error {{declaration does not declare anything}}
+int gv2;
+
+static void buggy(int *x) { }
// Type qualifiers.
typedef int f(void);
@@ -22,3 +24,10 @@ __restrict__ fptr v3; // expected-error {{pointer to function type 'f' (aka 'int
f *__restrict__ v4; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
restrict struct hallo; // expected-error {{restrict requires a pointer or reference}}
+
+// PR6180
+struct test1 {
+} // expected-error {{expected ';' after struct}}
+
+void test2() {}
+
diff --git a/test/Sema/enum.c b/test/Sema/enum.c
index 916de41176bc..9b4650091e19 100644
--- a/test/Sema/enum.c
+++ b/test/Sema/enum.c
@@ -92,3 +92,7 @@ typedef enum {
} an_enum;
// FIXME: why is this only a warning?
char * s = (an_enum) an_enumerator; // expected-warning {{incompatible integer to pointer conversion initializing 'an_enum', expected 'char *'}}
+
+// PR4515
+enum PR4515 {PR4515a=1u,PR4515b=(PR4515a-2)/2};
+int CheckPR4515[PR4515b==0?1:-1];
diff --git a/test/Sema/format-string-percentm.c b/test/Sema/format-string-percentm.c
index f2e9dd81bab3..1ffc439af07a 100644
--- a/test/Sema/format-string-percentm.c
+++ b/test/Sema/format-string-percentm.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple i686-pc-linux-gnu
+// PR 4142 - support glibc extension to printf: '%m' (which prints strerror(errno)).
int printf(char const*,...);
void percentm(void) {
printf("%m");
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 20e4dcd97fab..f1fa6580e3b8 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -40,18 +40,22 @@ void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
// rdar://6079877
printf("abc"
- "%*d", (unsigned) 1, 1); // expected-warning {{field width should have type 'int'}}
+ "%*d", 1, 1); // no-warning
printf("abc\
def"
- "%*d", (unsigned) 1, 1); // expected-warning {{field width should have type 'int'}}
-
+ "%*d", 1, 1); // no-warning
+
+ // <rdar://problem/6079850>, allow 'unsigned' (instead of 'int') to be used for both
+ // the field width and precision. This deviates from C99, but is reasonably safe
+ // and is also accepted by GCC.
+ printf("%*d", (unsigned) 1, 1); // no-warning
}
void check_conditional_literal(const char* s, int i) {
printf(i == 1 ? "yes" : "no"); // no-warning
printf(i == 0 ? (i == 1 ? "yes" : "no") : "dont know"); // no-warning
printf(i == 0 ? (i == 1 ? s : "no") : "dont know"); // expected-warning{{format string is not a string literal}}
- printf("yes" ?: "no %d", 1); // expected-warning{{more data arguments than '%' conversions}}
+ printf("yes" ?: "no %d", 1); // expected-warning{{more data arguments than format specifiers}}
}
void check_writeback_specifier()
@@ -65,10 +69,10 @@ void check_writeback_specifier()
void check_invalid_specifier(FILE* fp, char *buf)
{
- printf("%s%lb%d","unix",10,20); // expected-warning {{lid conversion '%lb'}}
- fprintf(fp,"%%%l"); // expected-warning {{lid conversion '%l'}}
- sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // no-warning
- snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning {{sion '%;'}}
+ printf("%s%lb%d","unix",10,20); // expected-warning {{invalid conversion specifier 'b'}}
+ fprintf(fp,"%%%l"); // expected-warning {{incomplete format specifier}}
+ sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // expected-warning{{conversion specifies type 'long' but the argument has type 'int'}}
+ snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{conversion specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}}
}
void check_null_char_string(char* b)
@@ -137,5 +141,66 @@ void test9(char *P) {
void torture(va_list v8) {
vprintf ("%*.*d", v8); // no-warning
+
+}
+
+void test10(int x, float f, int i, long long lli) {
+ printf("%@", 12); // expected-warning{{invalid conversion specifier '@'}}
+ printf("\0"); // expected-warning{{format string contains '\0' within the string body}}
+ printf("xs\0"); // expected-warning{{format string contains '\0' within the string body}}
+ printf("%*d\n"); // expected-warning{{'*' specified field width is missing a matching 'int' argument}}
+ printf("%*.*d\n", x); // expected-warning{{'.*' specified field precision is missing a matching 'int' argument}}
+ printf("%*d\n", f, x); // expected-warning{{field width should have type 'int', but argument has type 'double'}}
+ printf("%*.*d\n", x, f, x); // expected-warning{{field precision should have type 'int', but argument has type 'double'}}
+ printf("%**\n"); // expected-warning{{invalid conversion specifier '*'}}
+ printf("%n", &i); // expected-warning{{use of '%n' in format string discouraged (potentially insecure)}}
+ printf("%d%d\n", x); // expected-warning{{more '%' conversions than data arguments}}
+ printf("%d\n", x, x); // expected-warning{{more data arguments than format specifiers}}
+ printf("%W%d%Z\n", x, x, x); // expected-warning{{invalid conversion specifier 'W'}} expected-warning{{invalid conversion specifier 'Z'}}
+ printf("%"); // expected-warning{{incomplete format specifier}}
+ printf("%.d", x); // no-warning
+ printf("%.", x); // expected-warning{{incomplete format specifier}}
+ printf("%f", 4); // expected-warning{{conversion specifies type 'double' but the argument has type 'int'}}
+ printf("%qd", lli);
+ printf("hhX %hhX", (unsigned char)10); // no-warning
+ printf("llX %llX", (long long) 10); // no-warning
+ // This is fine, because there is an implicit conversion to an int.
+ printf("%d", (unsigned char) 10); // no-warning
+ printf("%d", (long long) 10); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
+ printf("%Lf\n", (long double) 1.0); // no-warning
+ printf("%f\n", (long double) 1.0); // expected-warning{{conversion specifies type 'double' but the argument has type 'long double'}}
+}
+
+void test11(void *p, char *s) {
+ printf("%p", p); // no-warning
+ printf("%.4p", p); // expected-warning{{precision used in 'p' conversion specifier (where it has no meaning)}}
+ printf("%+p", p); // expected-warning{{flag '+' results in undefined behavior in 'p' conversion specifier}}
+ printf("% p", p); // expected-warning{{flag ' ' results in undefined behavior in 'p' conversion specifier}}
+ printf("%0p", p); // expected-warning{{flag '0' results in undefined behavior in 'p' conversion specifier}}
+ printf("%s", s); // no-warning
+ printf("%+s", p); // expected-warning{{flag '+' results in undefined behavior in 's' conversion specifier}}
+ printf("% s", p); // expected-warning{{flag ' ' results in undefined behavior in 's' conversion specifier}}
+ printf("%0s", p); // expected-warning{{flag '0' results in undefined behavior in 's' conversion specifier}}
+}
+
+void test12(char *b) {
+ unsigned char buf[4];
+ printf ("%.4s\n", buf); // no-warning
+ printf ("%.4s\n", &buf); // expected-warning{{conversion specifies type 'char *' but the argument has type 'unsigned char (*)[4]'}}
+
+ // Verify that we are checking asprintf
+ asprintf(&b, "%d", "asprintf"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}}
+}
+
+typedef struct __aslclient *aslclient;
+typedef struct __aslmsg *aslmsg;
+int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5)));
+void test_asl(aslclient asl) {
+ // Test case from <rdar://problem/7341605>.
+ asl_log(asl, 0, 3, "Error: %m"); // no-warning
+ asl_log(asl, 0, 3, "Error: %W"); // expected-warning{{invalid conversion specifier 'W'}}
}
+// <rdar://problem/7595366>
+typedef enum { A } int_t;
+void f0(int_t x) { printf("%d\n", x); }
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
index 9544dc9baef6..1302b34b107a 100644
--- a/test/Sema/function-redecl.c
+++ b/test/Sema/function-redecl.c
@@ -125,3 +125,7 @@ void test_x() {
x(5);
x2(5); // expected-warning{{incompatible integer to pointer conversion passing 'int', expected 'int *'}}
}
+
+enum e0 {};
+void f3();
+void f3(enum e0 x) {}
diff --git a/test/Sema/incomplete-decl.c b/test/Sema/incomplete-decl.c
index 753d9c0a3c1a..e5b6d5f0da6d 100644
--- a/test/Sema/incomplete-decl.c
+++ b/test/Sema/incomplete-decl.c
@@ -16,7 +16,7 @@ int ary[]; // expected-warning {{tentative array definition assumed to have one
struct foo bary[]; // expected-error {{array has incomplete element type 'struct foo'}}
void func() {
- int ary[]; // expected-error{{variable has incomplete type 'int []'}}
+ int ary[]; // expected-error{{definition of variable with array type needs an explicit size or an initializer}}
void b; // expected-error {{variable has incomplete type 'void'}}
struct foo f; // expected-error {{variable has incomplete type 'struct foo'}}
}
diff --git a/test/Sema/indirect-goto.c b/test/Sema/indirect-goto.c
index 134ccd8a7076..4c1c6c328a18 100644
--- a/test/Sema/indirect-goto.c
+++ b/test/Sema/indirect-goto.c
@@ -2,6 +2,9 @@
struct c {int x;};
int a(struct c x, long long y) {
+ void const* l1_ptr = &&l1;
+ goto *l1_ptr;
+l1:
goto *x; // expected-error{{incompatible type}}
goto *y; // expected-warning{{incompatible integer to pointer conversion}}
}
diff --git a/test/Sema/return-noreturn.c b/test/Sema/return-noreturn.c
index 198ab11c6760..ff43754a4299 100644
--- a/test/Sema/return-noreturn.c
+++ b/test/Sema/return-noreturn.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks -Wmissing-noreturn
+// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks -Wmissing-noreturn -Wno-unreachable-code
int j;
void test1() { // expected-warning {{function could be attribute 'noreturn'}}
diff --git a/test/Sema/return.c b/test/Sema/return.c
index 17d21789f05a..5d1c97f2a2ef 100644
--- a/test/Sema/return.c
+++ b/test/Sema/return.c
@@ -1,4 +1,4 @@
-// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks
+// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wno-unreachable-code
// clang emits the following warning by default.
// With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the
diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c
index 74bc7c46f8f5..7d293f2747ed 100644
--- a/test/Sema/scope-check.c
+++ b/test/Sema/scope-check.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu99 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu99 %s -Wno-unreachable-code
int test1(int x) {
goto L; // expected-error{{illegal goto into protected scope}}
diff --git a/test/Sema/statements.c b/test/Sema/statements.c
index 3cd2460e79d9..6da2daa01ac2 100644
--- a/test/Sema/statements.c
+++ b/test/Sema/statements.c
@@ -33,3 +33,11 @@ void *test10() {
bar:
return &&bar; // expected-warning {{returning address of label, which is local}}
}
+
+// PR6034
+void test11(int bit) {
+ switch (bit)
+ switch (env->fpscr) // expected-error {{use of undeclared identifier 'env'}}
+ {
+ }
+}
diff --git a/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c
index c45f93e07c05..a06952647984 100644
--- a/test/Sema/stdcall-fastcall.c
+++ b/test/Sema/stdcall-fastcall.c
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// CC qualifier can be applied only to functions
-int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' attribute only applies to function types}}
-int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' attribute only applies to function types}}
+int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' only applies to function types; type here is 'int'}}
+int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' only applies to function types; type here is 'int'}}
// Different CC qualifiers are not compatible
void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{stdcall and fastcall attributes are not compatible}}
-void __attribute__((stdcall)) foo4();
-void __attribute__((fastcall)) foo4(void); // expected-error{{fastcall and stdcall attributes are not compatible}}
+void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}}
+void __attribute__((fastcall)) foo4(void); // expected-error{{function declared 'fastcall' here was previously declared 'stdcall'}}
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
index 08ab0e0ebd73..2690ad28e99a 100644
--- a/test/Sema/switch.c
+++ b/test/Sema/switch.c
@@ -85,3 +85,141 @@ int f0(int var) { // expected-note{{'var' declared here}}
}
return 2;
}
+
+void test7() {
+ enum {
+ A = 1,
+ B
+ } a;
+ switch(a) { //expected-warning{{enumeration value 'B' not handled in switch}}
+ case A:
+ break;
+ }
+ switch(a) {
+ case B:
+ case A:
+ break;
+ }
+ switch(a) {
+ case A:
+ case B:
+ case 3: // expected-warning{{case value not in enumerated type ''}}
+ break;
+ }
+ switch(a) {
+ case A:
+ case B:
+ case 3 ... //expected-warning{{case value not in enumerated type ''}}
+ 4: //expected-warning{{case value not in enumerated type ''}}
+ break;
+ }
+ switch(a) {
+ case 1 ... 2:
+ break;
+ }
+ switch(a) {
+ case 0 ... 2: //expected-warning{{case value not in enumerated type ''}}
+ break;
+ }
+ switch(a) {
+ case 1 ... 3: //expected-warning{{case value not in enumerated type ''}}
+ break;
+ }
+ switch(a) {
+ case 0 ... //expected-warning{{case value not in enumerated type ''}}
+ 3: //expected-warning{{case value not in enumerated type ''}}
+ break;
+ }
+
+}
+
+void test8() {
+ enum {
+ A,
+ B,
+ C = 1
+ } a;
+ switch(a) {
+ case A:
+ case B:
+ break;
+ }
+ switch(a) {
+ case A:
+ case C:
+ break;
+ }
+ switch(a) { //expected-warning{{enumeration value 'B' not handled in switch}}
+ case A:
+ break;
+ }
+}
+
+void test9() {
+ enum {
+ A = 3,
+ C = 1
+ } a;
+ switch(a) {
+ case 0: //expected-warning{{case value not in enumerated type ''}}
+ case 1:
+ case 2: //expected-warning{{case value not in enumerated type ''}}
+ case 3:
+ case 4: //expected-warning{{case value not in enumerated type ''}}
+ break;
+ }
+}
+
+void test10() {
+ enum {
+ A = 10,
+ C = 2,
+ B = 4,
+ D = 12
+ } a;
+ switch(a) {
+ case 0 ... //expected-warning{{case value not in enumerated type ''}}
+ 1: //expected-warning{{case value not in enumerated type ''}}
+ case 2 ... 4:
+ case 5 ... //expected-warning{{case value not in enumerated type ''}}
+ 9: //expected-warning{{case value not in enumerated type ''}}
+ case 10 ... 12:
+ case 13 ... //expected-warning{{case value not in enumerated type ''}}
+ 16: //expected-warning{{case value not in enumerated type ''}}
+ break;
+ }
+}
+
+void test11() {
+ enum {
+ A = -1,
+ B,
+ C
+ } a;
+ switch(a) { //expected-warning{{enumeration value 'A' not handled in switch}}
+ case B:
+ case C:
+ break;
+ }
+
+ switch(a) {
+ case B:
+ case C:
+ break;
+
+ default:
+ break;
+ }
+}
+
+void test12() {
+ enum {
+ A = -1,
+ B = 4294967286
+ } a;
+ switch(a) {
+ case A:
+ case B:
+ break;
+ }
+}
diff --git a/test/Sema/ucn-cstring.c b/test/Sema/ucn-cstring.c
index f5bf457ed144..ac1d37f186a4 100644
--- a/test/Sema/ucn-cstring.c
+++ b/test/Sema/ucn-cstring.c
@@ -5,8 +5,8 @@ int printf(const char *, ...);
int main(void) {
int a[sizeof("hello \u2192 \u2603 \u2190 world") == 24 ? 1 : -1];
- printf("%s (%d)\n", "hello \u2192 \u2603 \u2190 world", sizeof("hello \u2192 \u2603 \u2190 world"));
- printf("%s (%d)\n", "\U00010400\U0001D12B", sizeof("\U00010400\U0001D12B"));
+ printf("%s (%zd)\n", "hello \u2192 \u2603 \u2190 world", sizeof("hello \u2192 \u2603 \u2190 world"));
+ printf("%s (%zd)\n", "\U00010400\U0001D12B", sizeof("\U00010400\U0001D12B"));
// Some error conditions...
printf("%s\n", "\U"); // expected-error{{\u used with no following hex digits}}
printf("%s\n", "\U00"); // expected-error{{incomplete universal character name}}
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index 68503bd6a161..4c6c47b34517 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unreachable-code
int foo(int X, int Y);
diff --git a/test/Sema/vla.c b/test/Sema/vla.c
index 7ddd432fbc0f..ebf9b889ee2a 100644
--- a/test/Sema/vla.c
+++ b/test/Sema/vla.c
@@ -54,3 +54,9 @@ int (*pr2044c(void))[pr2044b]; // expected-error {{variably modified type}}
const int f5_ci = 1;
void f5() { char a[][f5_ci] = {""}; } // expected-error {{variable-sized object may not be initialized}}
+
+// PR5185
+void pr5185(int a[*]);
+void pr5185(int a[*]) // expected-error {{variable length array must be bound in function definition}}
+{
+}
diff --git a/test/Sema/warn-unused-function.c b/test/Sema/warn-unused-function.c
new file mode 100644
index 000000000000..178527f01c0f
--- /dev/null
+++ b/test/Sema/warn-unused-function.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-function -verify %s
+
+void foo() {}
+static void f2() {}
+static void f1() {f2();} // expected-warning{{unused}}
+
+static int f0() { return 17; } // expected-warning{{unused}}
+int x = sizeof(f0());
+
+static void f3();
+extern void f3() { } // expected-warning{{unused}}
+
+// FIXME: This will trigger a warning when it should not.
+// Update once PR6281 is fixed.
+//inline static void f4();
+//void f4() { } \ No newline at end of file
diff --git a/test/Sema/x86-attr-force-align-arg-pointer.c b/test/Sema/x86-attr-force-align-arg-pointer.c
new file mode 100644
index 000000000000..9609fadf7feb
--- /dev/null
+++ b/test/Sema/x86-attr-force-align-arg-pointer.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fsyntax-only -verify %s
+
+int a __attribute__((force_align_arg_pointer)); // expected-warning{{attribute only applies to function types}}
+
+// It doesn't matter where the attribute is located.
+void b(void) __attribute__((force_align_arg_pointer));
+void __attribute__((force_align_arg_pointer)) c(void);
+
+// Functions only have to be declared force_align_arg_pointer once.
+void b(void) {}
+
+// It doesn't matter which declaration has the attribute.
+void d(void);
+void __attribute__((force_align_arg_pointer)) d(void) {}
+
+// Attribute is ignored on function pointer types.
+void (__attribute__((force_align_arg_pointer)) *p)(); //expected-warning{{force_align_arg_pointer used on function pointer; attribute ignored}}
+
diff --git a/test/SemaCXX/Inputs/lit.local.cfg b/test/SemaCXX/Inputs/lit.local.cfg
new file mode 100644
index 000000000000..e6f55eef7af5
--- /dev/null
+++ b/test/SemaCXX/Inputs/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = []
diff --git a/test/SemaCXX/Inputs/malloc.h b/test/SemaCXX/Inputs/malloc.h
new file mode 100644
index 000000000000..c54d6215017b
--- /dev/null
+++ b/test/SemaCXX/Inputs/malloc.h
@@ -0,0 +1,3 @@
+extern "C" {
+extern void *malloc (__SIZE_TYPE__ __size) throw () __attribute__ ((__malloc__)) ;
+}
diff --git a/test/SemaCXX/access-base-class.cpp b/test/SemaCXX/access-base-class.cpp
index f4c58d940b63..d0b0fb8ee223 100644
--- a/test/SemaCXX/access-base-class.cpp
+++ b/test/SemaCXX/access-base-class.cpp
@@ -2,10 +2,10 @@
namespace T1 {
class A { };
-class B : private A { }; // expected-note {{'private' inheritance specifier here}}
+class B : private A { }; // expected-note {{declared private here}}
void f(B* b) {
- A *a = b; // expected-error{{conversion from 'class T1::B' to inaccessible base class 'class T1::A'}}
+ A *a = b; // expected-error{{cannot cast 'class T1::B' to its private base class 'class T1::A'}}
}
}
@@ -13,10 +13,10 @@ void f(B* b) {
namespace T2 {
class A { };
-class B : A { }; // expected-note {{inheritance is implicitly 'private'}}
+class B : A { }; // expected-note {{implicitly declared private here}}
void f(B* b) {
- A *a = b; // expected-error {{conversion from 'class T2::B' to inaccessible base class 'class T2::A'}}
+ A *a = b; // expected-error {{cannot cast 'class T2::B' to its private base class 'class T2::A'}}
}
}
@@ -63,13 +63,13 @@ namespace T6 {
class A {};
- class B : private A { // expected-note {{'private' inheritance specifier here}}
+ class B : private A { // expected-note {{declared private here}}
void f(C* c);
};
class C : public B {
void f(C *c) {
- A* a = c; // expected-error {{conversion from 'class T6::C' to inaccessible base class 'class T6::A'}}
+ A* a = c; // expected-error {{cannot cast 'class T6::C' to its private base class 'class T6::A'}}
}
};
@@ -77,3 +77,14 @@ namespace T6 {
A *a = c;
}
}
+
+namespace T7 {
+ class A {};
+ class B : public A {};
+ class C : private B {
+ void f(C *c) {
+ A* a = c; // okay
+ }
+ };
+}
+
diff --git a/test/SemaCXX/access-control-check.cpp b/test/SemaCXX/access-control-check.cpp
index cf2d191a294f..783d4def5327 100644
--- a/test/SemaCXX/access-control-check.cpp
+++ b/test/SemaCXX/access-control-check.cpp
@@ -11,5 +11,5 @@ class P {
class N : M,P {
N() {}
- int PR() { return iP + PPR(); } // expected-error 2 {{access to private member of 'class P'}}
+ int PR() { return iP + PPR(); } // expected-error 2 {{private member of 'class P'}}
};
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index ac482151fac1..83f4179d9136 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
// Verify that we can't initialize non-aggregates with an initializer
// list.
@@ -30,3 +30,40 @@ NonAggr4 na4 = { 17 }; // expected-error{{non-aggregate type 'struct NonAggr4' c
// PR5817
typedef int type[][2];
const type foo = {0};
+
+// Vector initialization.
+typedef short __v4hi __attribute__ ((__vector_size__ (8)));
+__v4hi v1 = { (void *)1, 2, 3 }; // expected-error {{cannot initialize a vector element of type 'short' with an rvalue of type 'void *'}}
+
+// Array initialization.
+int a[] = { (void *)1 }; // expected-error {{cannot initialize an array element of type 'int' with an rvalue of type 'void *'}}
+
+// Struct initialization.
+struct S { int a; } s = { (void *)1 }; // expected-error {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}}
+
+// Check that we're copy-initializing the structs.
+struct A {
+ A();
+ A(int);
+ ~A();
+
+ A(const A&) = delete; // expected-note 2 {{function has been explicitly marked deleted here}}
+};
+
+struct B {
+ A a;
+};
+
+struct C {
+ const A& a;
+};
+
+void f() {
+ A as1[1] = { };
+ A as2[1] = { 1 }; // expected-error {{copying array element of type 'struct A' invokes deleted copy constructor}}
+
+ B b1 = { };
+ B b2 = { 1 }; // expected-error {{copying member subobject of type 'struct A' invokes deleted copy constructor}}
+
+ C c1 = { 1 };
+}
diff --git a/test/SemaCXX/builtin-exception-spec.cpp b/test/SemaCXX/builtin-exception-spec.cpp
new file mode 100644
index 000000000000..324d20ea6a15
--- /dev/null
+++ b/test/SemaCXX/builtin-exception-spec.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
+#include <malloc.h>
+
+extern "C" {
+void *malloc(__SIZE_TYPE__);
+}
diff --git a/test/SemaCXX/builtins.cpp b/test/SemaCXX/builtins.cpp
index a75b4f2e403a..568ba5dde129 100644
--- a/test/SemaCXX/builtins.cpp
+++ b/test/SemaCXX/builtins.cpp
@@ -5,3 +5,5 @@ typedef const struct __CFString * CFStringRef;
void f() {
(void)CFStringRef(CFSTR("Hello"));
}
+
+void a() { __builtin_va_list x, y; ::__builtin_va_copy(x, y); }
diff --git a/test/SemaCXX/cast-conversion.cpp b/test/SemaCXX/cast-conversion.cpp
index 77f4a528906d..074e1330403d 100644
--- a/test/SemaCXX/cast-conversion.cpp
+++ b/test/SemaCXX/cast-conversion.cpp
@@ -30,7 +30,7 @@ X0<T> make_X0(const T &Val) {
}
void test_X0() {
- const char array[2];
+ const char array[2] = { 'a', 'b' };
make_X0(array);
}
diff --git a/test/SemaCXX/comma.cpp b/test/SemaCXX/comma.cpp
new file mode 100644
index 000000000000..79ff7d1cde25
--- /dev/null
+++ b/test/SemaCXX/comma.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR6076
+void f();
+void (&g)() = (void(), f);
+
+int a[1];
+int (&b)[1] = (void(), a);
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index b71133bfeec8..b961ff2de910 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -25,7 +25,7 @@ struct Derived : Base {
void fn2();
};
struct Convertible { operator Base&(); };
-struct Priv : private Base {}; // expected-note 4 {{'private' inheritance specifier here}}
+struct Priv : private Base {}; // expected-note 4 {{declared private here}}
struct Mid : Base {};
struct Fin : Mid, Derived {};
typedef void (Derived::*DFnPtr)();
@@ -111,12 +111,12 @@ void test()
Priv priv;
Fin fin;
- (void)(i1 ? Base() : Priv()); // expected-error{{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
- (void)(i1 ? Priv() : Base()); // expected-error{{error: conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+ (void)(i1 ? Base() : Priv()); // expected-error{{private base class}}
+ (void)(i1 ? Priv() : Base()); // expected-error{{private base class}}
(void)(i1 ? Base() : Fin()); // expected-error{{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
(void)(i1 ? Fin() : Base()); // expected-error{{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
- (void)(i1 ? base : priv); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
- (void)(i1 ? priv : base); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+ (void)(i1 ? base : priv); // expected-error {{private base class}}
+ (void)(i1 ? priv : base); // expected-error {{private base class}}
(void)(i1 ? base : fin); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
(void)(i1 ? fin : base); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index 53f057ed0f35..2efb7b9c2145 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -104,8 +104,8 @@ struct M { // expected-note 2 {{candidate constructor (the implicit
};
struct N : M {
- N() : M(1), // expected-error {{no matching constructor for initialization of 'M'}}
- m1(100) { } // expected-error {{no matching constructor for initialization of 'm1'}}
+ N() : M(1), // expected-error {{no matching constructor for initialization of 'struct M'}}
+ m1(100) { } // expected-error {{no matching constructor for initialization of 'struct M'}}
M m1;
};
@@ -116,8 +116,8 @@ struct P : M {
};
struct Q {
- Q() : f1(1,2), // expected-error {{Too many arguments for member initializer 'f1'}}
- pf(0.0) { } // expected-error {{incompatible type passing 'double', expected 'float *'}}
+ Q() : f1(1,2), // expected-error {{excess elements in scalar initializer}}
+ pf(0.0) { } // expected-error {{cannot initialize a member subobject of type 'float *' with an rvalue of type 'double'}}
float f1;
float *pf;
diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp
index 315e29a5b5ec..d7eb5cf1e60d 100644
--- a/test/SemaCXX/copy-assignment.cpp
+++ b/test/SemaCXX/copy-assignment.cpp
@@ -47,22 +47,22 @@ struct ConvertibleToInt {
void test() {
A a, na;
- const A constA;
+ const A constA = A();
ConvertibleToA convertibleToA;
ConvertibleToConstA convertibleToConstA;
B b, nb;
- const B constB;
+ const B constB = B();
ConvertibleToB convertibleToB;
ConvertibleToBref convertibleToBref;
ConvertibleToConstB convertibleToConstB;
ConvertibleToConstBref convertibleToConstBref;
C c, nc;
- const C constC;
+ const C constC = C();
D d, nd;
- const D constD;
+ const D constD = D();
ConvertibleToInt convertibleToInt;
diff --git a/test/SemaCXX/dcl_ambig_res.cpp b/test/SemaCXX/dcl_ambig_res.cpp
index 859d2045da09..f0ba2978e8d7 100644
--- a/test/SemaCXX/dcl_ambig_res.cpp
+++ b/test/SemaCXX/dcl_ambig_res.cpp
@@ -12,8 +12,8 @@ void foo(double a)
{
S w(int(a)); // expected-warning{{disambiguated}}
w(17);
- S x(int()); // expected-warning{{disambiguated}}
- x(&returns_an_int);
+ S x1(int()); // expected-warning{{disambiguated}}
+ x1(&returns_an_int);
S y((int)a);
y.bar();
S z = int(a);
diff --git a/test/SemaCXX/dcl_init_aggr.cpp b/test/SemaCXX/dcl_init_aggr.cpp
index 07ddb0add2ca..861eb3dcb163 100644
--- a/test/SemaCXX/dcl_init_aggr.cpp
+++ b/test/SemaCXX/dcl_init_aggr.cpp
@@ -120,4 +120,4 @@ u u1 = { 1 };
u u2 = u1;
u u3 = 1; // expected-error{{no viable conversion}}
u u4 = { 0, "asdf" }; // expected-error{{excess elements in union initializer}}
-u u5 = { "asdf" }; // expected-error{{incompatible type initializing 'char const [5]', expected 'int'}}
+u u5 = { "asdf" }; // expected-error{{cannot initialize a member subobject of type 'int' with an lvalue of type 'char const [5]'}}
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
index 656f3436a0c3..2f7d8a4c77ef 100644
--- a/test/SemaCXX/decl-init-ref.cpp
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -24,3 +24,6 @@ int main() {
const A& rca = f(); // expected-error {{reference initialization of type 'struct A const &' with initializer of type 'class B' is ambiguous}}
A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot bind to a temporary of type 'class B'}}
}
+
+struct PR6139 { A (&x)[1]; };
+PR6139 x = {{A()}}; // expected-error{{non-const lvalue reference to type 'struct A [1]' cannot bind to a temporary of type 'struct A'}}
diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp
index 47ae06ab0e69..dc4a506dda21 100644
--- a/test/SemaCXX/enum.cpp
+++ b/test/SemaCXX/enum.cpp
@@ -67,3 +67,7 @@ namespace PR6061 {
enum { id };
};
}
+
+namespace Conditional {
+ enum a { A }; a x(const enum a x) { return 1?x:A; }
+}
diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp
new file mode 100644
index 000000000000..717ed1e3caf2
--- /dev/null
+++ b/test/SemaCXX/explicit.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+namespace Constructor {
+struct A {
+ A(int);
+};
+
+struct B {
+ explicit B(int);
+};
+
+B::B(int) { }
+
+struct C {
+ void f(const A&);
+ void f(const B&);
+};
+
+void f(C c) {
+ c.f(10);
+}
+}
+
+namespace Conversion {
+ struct A {
+ operator int();
+ explicit operator bool();
+ };
+
+ A::operator bool() { return false; }
+
+ struct B {
+ void f(int);
+ void f(bool);
+ };
+
+ void f(A a, B b) {
+ b.f(a);
+ }
+}
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index 8c70bc258701..4f2f19746783 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -21,3 +21,19 @@ int a() {
case t:; // expected-error {{not an integer constant expression}}
}
}
+
+// PR6206: out-of-line definitions are legit
+namespace pr6206 {
+ class Foo {
+ public:
+ static const int kBar;
+ };
+
+ const int Foo::kBar = 20;
+
+ char Test() {
+ char str[Foo::kBar];
+ str[0] = '0';
+ return str[0];
+ }
+}
diff --git a/test/SemaCXX/illegal-member-initialization.cpp b/test/SemaCXX/illegal-member-initialization.cpp
index 1890dbc9b594..be5f91d51ac8 100644
--- a/test/SemaCXX/illegal-member-initialization.cpp
+++ b/test/SemaCXX/illegal-member-initialization.cpp
@@ -1,9 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A {
- A() : value(), cvalue() { } // expected-error {{cannot initialize the member to null in default constructor because reference member 'value' cannot be null-initialized}} \
- // expected-error {{constructor for 'struct A' must explicitly initialize the reference member 'value'}}
- int &value; // expected-note{{declared at}} {{expected-note{{declared at}}
+ A() : value(), cvalue() { } // expected-error {{reference to type 'int' requires an initializer}}
+ int &value;
const int cvalue;
};
@@ -18,7 +17,7 @@ struct X {
int &value; // expected-note{{declared at}}
const int cvalue; // expected-note{{declared at}}
B& b; // expected-note{{declared at}}
- const B cb; // expected-note{{declared at}}
+ const B cb; // expected-note{{declared here}}
};
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
index f9836064d131..06114c34cc47 100644
--- a/test/SemaCXX/namespace-alias.cpp
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -62,3 +62,24 @@ namespace J {
func();
}
}
+
+namespace K {
+ namespace KA { void func(); }
+
+ void f() {
+ namespace KB = KA;
+ KB::func();
+ }
+
+ template <class T> void g() {
+ namespace KC = KA;
+ KC::func();
+ }
+ template void g<int>();
+ template void g<long>();
+
+ void h() {
+ KB::func(); // expected-error {{undeclared identifier 'KB'}}
+ KC::func(); // expected-error {{undeclared identifier 'KC'}}
+ }
+}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 8618f0339bca..8a217b312088 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -212,7 +212,7 @@ namespace test1 {
// non-lexical scope.
namespace test2 {
namespace ns {
- int *count_ptr;
+ extern int *count_ptr;
}
namespace {
int count = 0;
@@ -220,3 +220,12 @@ namespace test2 {
int *ns::count_ptr = &count;
}
+
+// PR6259, invalid case
+namespace test3 {
+ // FIXME: this should really only trigger once
+ class A; // expected-note 2 {{forward declaration}}
+ void foo(const char *path) {
+ A::execute(path); // expected-error 2 {{incomplete type 'class test3::A' named in nested name specifier}}
+ }
+}
diff --git a/test/SemaCXX/new-delete-predefined-decl.cpp b/test/SemaCXX/new-delete-predefined-decl.cpp
new file mode 100644
index 000000000000..20b15b729cd0
--- /dev/null
+++ b/test/SemaCXX/new-delete-predefined-decl.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -DTEMPLATE_OVERLOAD -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#include <stddef.h>
+
+// Note that each test must be run separately so it can be the first operator
+// new declaration in the file.
+
+#if defined(TEMPLATE_OVERLOAD)
+// Don't crash on global template operator new overloads.
+template<typename T> void* operator new(size_t, T);
+void test_template_overload() {
+ (void)new(0) double;
+}
+#endif
+
+void test_predefined() {
+ (void)new double;
+}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index b058fc13d96f..acd4a23cb35a 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -216,3 +216,18 @@ static void* f(void* g)
{
return new (g) X13();
}
+
+class X14 {
+ static void operator delete(void*, const size_t);
+};
+
+void f(X14 *x14a, X14 *x14b) {
+ delete x14a;
+}
+
+namespace PR5918 { // Look for template operator new overloads.
+ struct S { template<typename T> static void* operator new(size_t, T); };
+ void test() {
+ (void)new(0) S;
+ }
+}
diff --git a/test/SemaCXX/overload-call-copycon.cpp b/test/SemaCXX/overload-call-copycon.cpp
index 472fae26b81f..f57484e5069a 100644
--- a/test/SemaCXX/overload-call-copycon.cpp
+++ b/test/SemaCXX/overload-call-copycon.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -Wnon-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wnon-pod-varargs
class X { };
int& copycon(X x);
@@ -37,7 +37,6 @@ void test_copycon3(B b, const B bc) {
float& f1 = copycon3(bc); // expected-warning {{cannot pass object of non-POD type}}
}
-
class C : public B { };
float& copycon4(A a);
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 12dc5daccb6d..e2a4fd8a0d59 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -347,3 +347,15 @@ namespace test3 {
foo(*P); // expected-error {{no matching function for call to 'foo'}}
}
}
+
+namespace DerivedToBaseVsVoid {
+ struct A { };
+ struct B : A { };
+
+ float &f(void *);
+ int &f(const A*);
+
+ void g(B *b) {
+ int &ir = f(b);
+ }
+}
diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp
index 22416f3ea48e..77d9965ab796 100644
--- a/test/SemaCXX/overload-member-call.cpp
+++ b/test/SemaCXX/overload-member-call.cpp
@@ -89,7 +89,7 @@ namespace test1 {
A a;
a.foo(4, "hello"); //expected-error {{no matching member function for call to 'foo'}}
- const A b;
+ const A b = A();
b.bar(0); //expected-error {{no matching member function for call to 'bar'}}
a.baz(b); //expected-error {{no matching member function for call to 'baz'}}
diff --git a/test/SemaCXX/overloaded-operator-decl.cpp b/test/SemaCXX/overloaded-operator-decl.cpp
index c43d7c217cca..5f8655cee70c 100644
--- a/test/SemaCXX/overloaded-operator-decl.cpp
+++ b/test/SemaCXX/overloaded-operator-decl.cpp
@@ -37,3 +37,9 @@ Y operator++(Y&, INT);
X operator++(X&, FLOAT); // expected-error{{parameter of overloaded post-increment operator must have type 'int' (not 'FLOAT' (aka 'float'))}}
int operator+; // expected-error{{'operator+' cannot be the name of a variable or data member}}
+
+namespace PR6238 {
+ static struct {
+ void operator()();
+ } plus;
+}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 861d679c7261..e07afe202031 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -344,7 +344,7 @@ namespace pr5900 {
int operator[](unsigned); // expected-note {{candidate}}
};
int test1() {
- const NonConstArray x;
+ const NonConstArray x = NonConstArray();
return x[0]; // expected-error {{no viable overloaded operator[] for type}}
}
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index 630f53f2839e..df8337bec82c 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -102,3 +102,16 @@ string getInput();
void test9() {
string &s = getInput(); // expected-error{{lvalue reference}}
}
+
+void test10() {
+ __attribute((vector_size(16))) typedef int vec4;
+ typedef __attribute__(( ext_vector_type(4) )) int ext_vec4;
+
+ vec4 v;
+ int &a = v[0]; // expected-error{{non-const reference cannot bind to vector element}}
+ const int &b = v[0];
+
+ ext_vec4 ev;
+ int &c = ev.x; // expected-error{{non-const reference cannot bind to vector element}}
+ const int &d = ev.x;
+}
diff --git a/test/SemaCXX/reinterpret-cast.cpp b/test/SemaCXX/reinterpret-cast.cpp
index da675609d123..f7ab80e67fd0 100644
--- a/test/SemaCXX/reinterpret-cast.cpp
+++ b/test/SemaCXX/reinterpret-cast.cpp
@@ -47,7 +47,7 @@ void constness()
// Invalid: T1 const* -> T2*
(void)reinterpret_cast<int*>(icp); // expected-error {{reinterpret_cast from 'int const *' to 'int *' casts away constness}}
// Invalid: T1*** -> T2 const* const**
- int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***const' to 'int const *const **' casts away constness}}
+ int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***' to 'int const *const **' casts away constness}}
// Valid: T1* -> T2*
int *ip = reinterpret_cast<int*>(icpcpp);
// Valid: T* -> T const*
diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp
index cdaa843b8170..4818b041ad08 100644
--- a/test/SemaCXX/static-cast.cpp
+++ b/test/SemaCXX/static-cast.cpp
@@ -4,7 +4,7 @@ struct B : public A {}; // Single public base.
struct C1 : public virtual B {}; // Single virtual base.
struct C2 : public virtual B {};
struct D : public C1, public C2 {}; // Diamond
-struct E : private A {}; // Single private base. expected-note 3 {{'private' inheritance specifier here}}
+struct E : private A {}; // Single private base. expected-note 3 {{declared private here}}
struct F : public C1 {}; // Single path to B with virtual.
struct G1 : public B {};
struct G2 : public B {};
@@ -56,7 +56,7 @@ void t_529_2()
// Bad code below
(void)static_cast<void*>((const int*)0); // expected-error {{static_cast from 'int const *' to 'void *' is not allowed}}
- (void)static_cast<A*>((E*)0); // expected-error {{inaccessible base class 'struct A'}}
+ (void)static_cast<A*>((E*)0); // expected-error {{private base class 'struct A'}}
(void)static_cast<A*>((H*)0); // expected-error {{ambiguous conversion}}
(void)static_cast<int>((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}}
(void)static_cast<A**>((B**)0); // expected-error {{static_cast from 'struct B **' to 'struct A **' is not allowed}}
@@ -86,8 +86,8 @@ void t_529_5_8()
(void)static_cast<D&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct D &' via virtual base 'struct B'}}
(void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'struct A const *' to 'struct B *' casts away constness}}
(void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'struct A const' to 'struct B &' casts away constness}}
- (void)static_cast<E*>((A*)0); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
- (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
+ (void)static_cast<E*>((A*)0); // expected-error {{cannot cast private base class 'struct A' to 'struct E'}}
+ (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast private base class 'struct A' to 'struct E'}}
(void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<H&>(*((A*)0)); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'struct B *' to 'struct E *' is not allowed}}
@@ -178,3 +178,6 @@ struct X4 {
const X2 *x2;
};
+
+// PR5897 - accept static_cast from const void* to const int (*)[1].
+void PR5897() { (void)static_cast<const int(*)[1]>((const void*)0); }
diff --git a/test/SemaCXX/templated-friend-decl.cpp b/test/SemaCXX/templated-friend-decl.cpp
new file mode 100644
index 000000000000..c0034cd72f78
--- /dev/null
+++ b/test/SemaCXX/templated-friend-decl.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s
+
+template <typename T>
+struct Foo {
+ template <typename U>
+ struct Bar {};
+
+ // The templated declaration for class Bar should not be instantiated when
+ // Foo<int> is. This is to protect against PR5848; for now, this "parses" but
+ // requires a rewrite of the templated friend code to be properly fixed.
+ template <typename U>
+ friend struct Bar;
+};
+
+Foo<int> x;
diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp
index e8a7d70976ec..30c4cfd997a1 100644
--- a/test/SemaCXX/using-decl-1.cpp
+++ b/test/SemaCXX/using-decl-1.cpp
@@ -60,3 +60,38 @@ namespace P {
g(f);
}
}
+
+// Make sure that ADL can find names brought in by using decls.
+namespace test0 {
+ namespace ns {
+ class Foo {};
+
+ namespace inner {
+ void foo(char *); // expected-note {{no known conversion}}
+ }
+
+ using inner::foo;
+ }
+
+ void test(ns::Foo *p) {
+ foo(*p); // expected-error {{no matching function for call to 'foo'}}
+ }
+}
+
+// Redeclarations!
+namespace test1 {
+ namespace ns0 { struct Foo {}; }
+ namespace A { void foo(ns0::Foo *p, int y, int z); }
+ namespace ns2 { using A::foo; }
+ namespace ns1 { struct Bar : ns0::Foo {}; }
+ namespace A { void foo(ns0::Foo *p, int y, int z = 0); } // expected-note {{candidate}}
+ namespace ns1 { using A::foo; }
+ namespace ns2 { struct Baz : ns1::Bar {}; }
+ namespace A { void foo(ns0::Foo *p, int y = 0, int z); }
+
+ void test(ns2::Baz *p) {
+ foo(p, 0, 0); // okay!
+ foo(p, 0); // should be fine!
+ foo(p); // expected-error {{no matching function}}
+ }
+}
diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp
index 5e1e9b0899c6..09cbfadf9b37 100644
--- a/test/SemaCXX/virtual-override.cpp
+++ b/test/SemaCXX/virtual-override.cpp
@@ -29,14 +29,14 @@ class B : A {
namespace T3 {
struct a { };
-struct b : private a { }; // expected-note{{'private' inheritance specifier here}}
+struct b : private a { }; // expected-note{{declared private here}}
class A {
virtual a* f(); // expected-note{{overridden virtual function is here}}
};
class B : A {
- virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides (conversion from 'struct T3::b' to inaccessible base class 'struct T3::a')}}
+ virtual b* f(); // expected-error{{invalid covariant return for virtual function: 'struct T3::a' is a private base class of 'struct T3::b'}}
};
}
@@ -215,6 +215,29 @@ namespace PR6110 {
Y1<Derived*, Base*> y;
}
+// Defer checking for covariance if either return type is dependent.
+namespace type_dependent_covariance {
+ struct B {};
+ template <int N> struct TD : public B {};
+ template <> struct TD<1> {};
+
+ template <int N> struct TB {};
+ struct D : public TB<0> {};
+
+ template <int N> struct X {
+ virtual B* f1(); // expected-note{{overridden virtual function is here}}
+ virtual TB<N>* f2(); // expected-note{{overridden virtual function is here}}
+ };
+ template <int N, int M> struct X1 : X<N> {
+ virtual TD<M>* f1(); // expected-error{{return type of virtual function 'f1' is not covariant with the return type of the function it overrides ('TD<1> *'}}
+ virtual D* f2(); // expected-error{{return type of virtual function 'f2' is not covariant with the return type of the function it overrides ('struct type_dependent_covariance::D *' is not derived from 'TB<1> *')}}
+ };
+
+ X1<0, 0> good;
+ X1<0, 1> bad_derived; // expected-note{{instantiation}}
+ X1<1, 0> bad_base; // expected-note{{instantiation}}
+}
+
namespace T10 {
struct A { };
struct B : A { };
diff --git a/test/SemaCXX/warn-missing-noreturn.cpp b/test/SemaCXX/warn-missing-noreturn.cpp
new file mode 100644
index 000000000000..32d020f15f3d
--- /dev/null
+++ b/test/SemaCXX/warn-missing-noreturn.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wmissing-noreturn
+void f() __attribute__((noreturn));
+
+template<typename T> void g(T) { // expected-warning {{function could be attribute 'noreturn'}}
+ f();
+}
+
+template void g<int>(int); // expected-note {{in instantiation of function template specialization 'g<int>' requested here}}
+
+template<typename T> struct A {
+ void g() { // expected-warning {{function could be attribute 'noreturn'}}
+ f();
+ }
+};
+
+template struct A<int>; // expected-note {{in instantiation of member function 'A<int>::g' requested here}}
+
+struct B {
+ template<typename T> void g(T) { // expected-warning {{function could be attribute 'noreturn'}}
+ f();
+ }
+};
+
+template void B::g<int>(int); // expected-note {{in instantiation of function template specialization 'B::g<int>' requested here}}
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index 5620248f5005..3b5349a5ce1b 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -1,8 +1,7 @@
-// RUN: %clang -fsyntax-only -Wunused-variable -verify %s
-
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -verify %s
template<typename T> void f() {
- T t;
- t = 17;
+ T t;
+ t = 17;
}
// PR5407
@@ -27,7 +26,7 @@ namespace PR5531 {
};
void test() {
- A();
+ A(); // expected-warning{{expression result unused}}
B(17);
C();
}
@@ -43,3 +42,12 @@ void bah() {
x.foo(); // expected-warning {{ignoring return value of function declared with warn_unused_result attribute}}
x2->foo(); // expected-warning {{ignoring return value of function declared with warn_unused_result attribute}}
}
+
+template<typename T>
+struct X0 { };
+
+template<typename T>
+void test_dependent_init(T *p) {
+ X0<int> i(p);
+ (void)i;
+}
diff --git a/test/SemaCXX/warn-weak-vtables.cpp b/test/SemaCXX/warn-weak-vtables.cpp
new file mode 100644
index 000000000000..1ea88a548e71
--- /dev/null
+++ b/test/SemaCXX/warn-weak-vtables.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wweak-vtables
+
+struct A { // expected-warning {{'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit}}
+ virtual void f() { }
+};
+
+template<typename T> struct B {
+ virtual void f() { }
+};
+
+namespace {
+ struct C {
+ virtual void f() { }
+ };
+}
+
+void f() {
+ struct A {
+ virtual void f() { }
+ };
+} \ No newline at end of file
diff --git a/test/SemaObjC/cocoa.m b/test/SemaObjC/cocoa.m
index 9c92731fe7b9..a8cfb72e1ea8 100644
--- a/test/SemaObjC/cocoa.m
+++ b/test/SemaObjC/cocoa.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -target-cpu pentium4 %s -print-stats
+// RUN: %clang -arch x86_64 %s -fsyntax-only -Xclang -print-stats
#ifdef __APPLE__
#include <Cocoa/Cocoa.h>
#endif
diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m
new file mode 100644
index 000000000000..be2397bd2007
--- /dev/null
+++ b/test/SemaObjC/default-synthesize.m
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi2 -verify %s
+
+@interface NSString @end
+
+@interface NSObject @end
+
+@interface SynthItAll
+@property int howMany;
+@property (retain) NSString* what;
+@end
+
+@implementation SynthItAll
+//@synthesize howMany, what;
+@end
+
+
+@interface SynthSetter : NSObject
+@property (nonatomic) int howMany; // REM: nonatomic to avoid warnings about only implementing one of the pair
+@property (nonatomic, retain) NSString* what;
+@end
+
+@implementation SynthSetter
+//@synthesize howMany, what;
+
+- (int) howMany {
+ return howMany;
+}
+// - (void) setHowMany: (int) value
+
+- (NSString*) what {
+ return what;
+}
+// - (void) setWhat: (NSString*) value
+@end
+
+
+@interface SynthGetter : NSObject
+@property (nonatomic) int howMany; // REM: nonatomic to avoid warnings about only implementing one of the pair
+@property (nonatomic, retain) NSString* what;
+@end
+
+@implementation SynthGetter
+//@synthesize howMany, what;
+
+// - (int) howMany
+- (void) setHowMany: (int) value {
+ howMany = value;
+}
+
+// - (NSString*) what
+- (void) setWhat: (NSString*) value {
+ if (what != value) {
+ }
+}
+@end
+
+
+@interface SynthNone : NSObject
+@property int howMany;
+@property (retain) NSString* what;
+@end
+
+@implementation SynthNone
+//@synthesize howMany, what; // REM: Redundant anyway
+
+- (int) howMany {
+ return howMany;
+}
+- (void) setHowMany: (int) value {
+ howMany = value;
+}
+
+- (NSString*) what {
+ return what;
+}
+- (void) setWhat: (NSString*) value {
+ if (what != value) {
+ }
+}
+@end
+
diff --git a/test/SemaObjC/duplicate-property-class-extension.m b/test/SemaObjC/duplicate-property-class-extension.m
new file mode 100644
index 000000000000..bdf4786c76e8
--- /dev/null
+++ b/test/SemaObjC/duplicate-property-class-extension.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface Foo
+@property (readonly) char foo;
+@end
+
+@interface Foo ()
+@property (readwrite) char foo; // expected-note {{property declared here}}
+@end
+
+@interface Foo ()
+@property (readwrite) char foo; // expected-error {{property has a previous declaration}}
+@end
diff --git a/test/SemaObjC/exprs.m b/test/SemaObjC/exprs.m
index f4424f57a91d..33b144461f2b 100644
--- a/test/SemaObjC/exprs.m
+++ b/test/SemaObjC/exprs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wno-unreachable-code
// rdar://6597252
Class test1(Class X) {
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index e7550a758bdf..7abfe9622358 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -29,15 +29,24 @@ extern void *_NSConstantStringClassReference;
typedef const struct __CFString * CFStringRef;
extern void CFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(CFString, 1, 2)));
+int printf(const char * restrict, ...) ;
+
//===----------------------------------------------------------------------===//
// Test cases.
//===----------------------------------------------------------------------===//
void check_nslog(unsigned k) {
NSLog(@"%d%%", k); // no-warning
- NSLog(@"%s%lb%d", "unix", 10,20); // expected-warning {{lid conversion '%lb'}}
+ NSLog(@"%s%lb%d", "unix", 10,20); // expected-warning {{invalid conversion specifier 'b'}}
}
// Check type validation
extern void NSLog2(int format, ...) __attribute__((format(__NSString__, 1, 2))); // expected-error {{format argument not an NSString}}
extern void CFStringCreateWithFormat2(int *format, ...) __attribute__((format(CFString, 1, 2))); // expected-error {{format argument not a CFString}}
+
+// <rdar://problem/7068334> - Catch use of long long with int arguments.
+void rdar_7068334() {
+ long long test = 500;
+ printf("%i ",test); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
+ NSLog(@"%i ",test); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
+}
diff --git a/test/SemaObjC/method-arg-decay.m b/test/SemaObjC/method-arg-decay.m
index 82bdc6d9fb7b..f600029fda7b 100644
--- a/test/SemaObjC/method-arg-decay.m
+++ b/test/SemaObjC/method-arg-decay.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -checker-cfref -verify %s
+// RUN: %clang_cc1 -analyzer-check-objc-mem -verify %s
typedef signed char BOOL;
typedef int NSInteger;
typedef unsigned int NSUInteger;
diff --git a/test/SemaObjC/property-13.m b/test/SemaObjC/property-13.m
index f34ec568b94c..6d56dabb9c0e 100644
--- a/test/SemaObjC/property-13.m
+++ b/test/SemaObjC/property-13.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unreachable-code
@interface NSObject
+ alloc;
diff --git a/test/SemaObjC/property-not-lvalue.m b/test/SemaObjC/property-not-lvalue.m
index f1bda094c2db..473ef8649fa0 100644
--- a/test/SemaObjC/property-not-lvalue.m
+++ b/test/SemaObjC/property-not-lvalue.m
@@ -18,3 +18,17 @@ void foo() {
f.size.width = 2.2; // expected-error {{cannot assign to a sub-structure of an ivar using property assignment syntax}}
f.size.inner.dim = 200; // expected-error {{cannot assign to a sub-structure of an ivar using property assignment syntax}}
}
+
+// radar 7628953
+
+@interface Gorf {
+}
+- (NSSize)size;
+@end
+
+@implementation Gorf
+- (void)MyView_sharedInit {
+ self.size.width = 2.2; // expected-error {{cannot assign to a sub-structure returned via a getter using property assignment syntax}}
+}
+- (NSSize)size {}
+@end
diff --git a/test/SemaObjC/protocol-warn.m b/test/SemaObjC/protocol-warn.m
new file mode 100644
index 000000000000..d0c51e3ffabe
--- /dev/null
+++ b/test/SemaObjC/protocol-warn.m
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// radar 7638810
+
+@protocol NSObject @end
+
+@interface NSObject <NSObject> @end
+
+@interface UIResponder : NSObject
+@end
+
+@implementation UIResponder
+@end
+
+@interface UIView : UIResponder
+@end
+
+@implementation UIView
+@end
+
+@interface UIWebTiledView : UIView
+@end
+
+@implementation UIWebTiledView
+@end
+
+@interface UIWebDocumentView : UIWebTiledView
+@end
+
+@implementation UIWebDocumentView
+@end
+
+@interface UIWebBrowserView : UIWebDocumentView
+@end
+
+@implementation UIWebBrowserView
+@end
+
+@interface UIPDFView : UIView
+@end
+
+@implementation UIPDFView
+@end
+
+@interface UIWebPDFView : UIPDFView
+@end
+
+@implementation UIWebPDFView
+@end
+
+UIWebPDFView *getView()
+{
+ UIWebBrowserView *browserView;
+ UIWebPDFView *pdfView;
+ return pdfView ? pdfView : browserView; // expected-warning {{incompatible pointer types returning 'UIView<NSObject> *', expected 'UIWebPDFView *'}}
+}
diff --git a/test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm b/test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm
new file mode 100644
index 000000000000..fcabaded7c4d
--- /dev/null
+++ b/test/SemaObjCXX/reinterpret-cast-objc-pointertype.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface NSString @end
+
+typedef const struct __CFString * CFStringRef;
+const NSString* fRef;
+
+CFStringRef func() {
+ return reinterpret_cast<CFStringRef>(fRef);
+}
+
+CFStringRef fRef1;
+
+const NSString* func1() {
+ return reinterpret_cast<const NSString*>(fRef1);
+}
+
+@interface I @end
+const I *fRef2;
+
+const NSString* func2() {
+ return reinterpret_cast<const NSString*>(fRef2);
+}
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index 375d199f5899..8d00bb796e94 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -86,3 +86,15 @@ int array4[is_same<Replace<vector<int, _2>, double, float>::type, vector<int, fl
template <typename T, int N> void f(const T (&a)[N]);
int iarr[] = { 1 };
void test_PR5911() { f(iarr); }
+
+// Must not examine base classes of incomplete type during template argument
+// deduction.
+namespace PR6257 {
+ template <typename T> struct X {
+ template <typename U> X(const X<U>& u);
+ };
+ struct A;
+ void f(A& a);
+ void f(const X<A>& a);
+ void test(A& a) { (void)f(a); }
+}
diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp
index 131b80cb1f36..3da43fa67502 100644
--- a/test/SemaTemplate/default-expr-arguments.cpp
+++ b/test/SemaTemplate/default-expr-arguments.cpp
@@ -177,3 +177,10 @@ namespace PR5810 {
X<float> x; // expected-note{{member function}}
}
}
+
+template<typename T> void f4(T, int = 17);
+template<> void f4<int>(int, int);
+
+void f4_test(int i) {
+ f4(i);
+}
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index 227856f1a8e2..de51f0992baa 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -76,3 +76,10 @@ template void print_type<double>(double*);
// PR5069
template<int I> void foo0 (int (&)[I + 1]) { }
template void foo0<2> (int (&)[3]);
+
+namespace explicit_instantiation_after_implicit_instantiation {
+ template <int I> struct X0 { static int x; };
+ template <int I> int X0<I>::x;
+ void test1() { (void)&X0<1>::x; }
+ template struct X0<1>;
+}
diff --git a/test/SemaTemplate/instantiate-decl-init.cpp b/test/SemaTemplate/instantiate-decl-init.cpp
index b0c2aa8afa91..6b76d72e3261 100644
--- a/test/SemaTemplate/instantiate-decl-init.cpp
+++ b/test/SemaTemplate/instantiate-decl-init.cpp
@@ -20,3 +20,27 @@ void fn(T t, const arg& arg) {
void test() {
fn(1, arg());
}
+
+struct X0 { };
+
+struct X1 {
+ explicit X1(const X0 &x0 = X0());
+};
+
+template<typename T>
+void f0() {
+ X1 x1;
+}
+
+template void f0<int>();
+template void f0<float>();
+
+struct NonTrivial {
+ NonTrivial();
+ ~NonTrivial();
+};
+
+template<int N> void f1() {
+ NonTrivial array[N];
+}
+template<> void f1<2>();
diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp
index e4e071dd20d7..e88b49447cb9 100644
--- a/test/SemaTemplate/instantiate-declref-ice.cpp
+++ b/test/SemaTemplate/instantiate-declref-ice.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-
template<int i> struct x {
static const int j = i;
x<j>* y;
@@ -10,7 +9,6 @@ const int x<i>::j;
int array0[x<2>::j];
-
template<typename T>
struct X0 {
static const unsigned value = sizeof(T);
diff --git a/test/SemaTemplate/instantiate-declref.cpp b/test/SemaTemplate/instantiate-declref.cpp
index da8b263ab3ab..f883b9361b66 100644
--- a/test/SemaTemplate/instantiate-declref.cpp
+++ b/test/SemaTemplate/instantiate-declref.cpp
@@ -87,3 +87,11 @@ struct smart_ptr {
void test_smart_ptr(smart_ptr<int> p) {
if (p) { }
}
+
+// PR5517
+namespace test0 {
+ template <int K> struct X {
+ X() { extern void x(); }
+ };
+ void g() { X<2>(); }
+}
diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp
index 663749ddce5b..d1b05f66a586 100644
--- a/test/SemaTemplate/instantiate-expr-1.cpp
+++ b/test/SemaTemplate/instantiate-expr-1.cpp
@@ -87,6 +87,18 @@ void add(const T &x) {
(void)(x + x);
}
+namespace PR6237 {
+ template <typename T>
+ void f(T t) {
+ t++;
+ }
+
+ struct B { };
+ B operator++(B &, int);
+
+ template void f(B);
+}
+
struct Addable {
Addable operator+(const Addable&) const;
};
@@ -112,3 +124,16 @@ void test_call_operator(CallOperator call_op, int i, double d) {
int &ir = test_call_operator<int&>(call_op, i);
double &dr = test_call_operator<double&>(call_op, d);
}
+
+template<typename T>
+void test_asm(T t) {
+ asm ("nop" : "=a"(*t) : "r"(*t)); // expected-error {{indirection requires pointer operand ('int' invalid)}}
+}
+
+void test_asm() {
+ int* a;
+ test_asm(a);
+
+ int b;
+ test_asm(b); // expected-note {{in instantiation of function template specialization 'test_asm<int>' requested here}}
+}
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index 428ef1ba8736..c5eb3cc53e7a 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -173,8 +173,8 @@ struct is_pod {
static const bool value = __is_pod(T);
};
-static const int is_pod0[is_pod<X>::value? -1 : 1];
-static const int is_pod1[is_pod<Y>::value? 1 : -1];
+static int is_pod0[is_pod<X>::value? -1 : 1];
+static int is_pod1[is_pod<Y>::value? 1 : -1];
// ---------------------------------------------------------------------
// initializer lists
@@ -197,7 +197,7 @@ template struct InitList1<APair, int*>;
template<typename T, typename Val1, typename Val2>
struct InitList2 {
void f(Val1 val1, Val2 val2) {
- T x = { val1, val2 }; // expected-error{{incompatible}}
+ T x = { val1, val2 }; // expected-error{{cannot initialize}}
}
};
diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp
index 768eb2170a15..72ad90a04f20 100644
--- a/test/SemaTemplate/instantiate-local-class.cpp
+++ b/test/SemaTemplate/instantiate-local-class.cpp
@@ -32,3 +32,21 @@ namespace PR5764 {
}
}
+// Instantiation of local classes with virtual functions.
+namespace local_class_with_virtual_functions {
+ template <typename T> struct X { };
+ template <typename T> struct Y { };
+
+ template <typename T>
+ void f() {
+ struct Z : public X<Y<T>*> {
+ virtual void g(Y<T>* y) { }
+ void g2(int x) {(void)x;}
+ };
+ Z z;
+ (void)z;
+ }
+
+ struct S { };
+ void test() { f<S>(); }
+}
diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp
index f7b7e47e1e9b..eecb445ea923 100644
--- a/test/SemaTemplate/instantiate-member-initializers.cpp
+++ b/test/SemaTemplate/instantiate-member-initializers.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -Wall -verify %s
template<typename T> struct A {
- A() : a(1) { } // expected-error{{incompatible type passing 'int', expected 'void *'}}
+ A() : a(1) { } // expected-error{{cannot initialize a member subobject of type 'void *' with an rvalue of type 'int'}}
T a;
};
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
index b4f0a9c6509d..c1260cf6a81e 100644
--- a/test/SemaTemplate/instantiate-member-template.cpp
+++ b/test/SemaTemplate/instantiate-member-template.cpp
@@ -131,3 +131,28 @@ namespace N0 {
x1.f(x0l);
}
}
+
+namespace PR6239 {
+ template <typename T>
+ struct X0 {
+ class type {
+ typedef T E;
+ template <E e> // subsitute T for E and bug goes away
+ struct sfinae { };
+
+ template <class U>
+ typename sfinae<&U::operator=>::type test(int);
+ };
+ };
+
+ template <typename T>
+ struct X1 {
+ typedef T E;
+ template <E e> // subsitute T for E and bug goes away
+ struct sfinae { };
+
+ template <class U>
+ typename sfinae<&U::operator=>::type test(int);
+ };
+
+}
diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp
index 5ea8c1010e5c..aea62855c225 100644
--- a/test/SemaTemplate/member-function-template.cpp
+++ b/test/SemaTemplate/member-function-template.cpp
@@ -73,3 +73,15 @@ void test_incomplete_access(X1<int> *x1, X2<int> *x2) {
float &fr = x1->get<float>();
(void)x2->get<float>(); // expected-error{{implicit instantiation of undefined template}}
}
+
+// Instantiation of template template parameters in a member function
+// template.
+namespace TTP {
+ template<int Dim> struct X {
+ template<template<class> class M, class T> void f(const M<T>&);
+ };
+
+ template<typename T> struct Y { };
+
+ void test_f(X<3> x, Y<int> y) { x.f(y); }
+}
diff --git a/test/SemaTemplate/qualified-id.cpp b/test/SemaTemplate/qualified-id.cpp
index 655a80e2bfbf..2e3a826ce894 100644
--- a/test/SemaTemplate/qualified-id.cpp
+++ b/test/SemaTemplate/qualified-id.cpp
@@ -29,3 +29,18 @@ namespace test2 {
}
};
}
+
+namespace PR6063 {
+ template <typename T> void f(T, T);
+
+ namespace detail
+ {
+ using PR6063::f;
+ }
+
+ template <typename T>
+ void g(T a, T b)
+ {
+ detail::f(a, b);
+ }
+}
diff --git a/test/SemaTemplate/recursive-template-instantiation.cpp b/test/SemaTemplate/recursive-template-instantiation.cpp
index 0ddedaf2354a..d6a0b247dd45 100644
--- a/test/SemaTemplate/recursive-template-instantiation.cpp
+++ b/test/SemaTemplate/recursive-template-instantiation.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template<typename T> void f(T* t) { // expected-note{{candidate function}}
+template<typename T> void f(T* t) { // expected-note{{failed template argument deduction}}
f(*t); // expected-error{{no matching function}}\
// expected-note 3{{requested here}}
}
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 133b8db9491a..fdfd4e47b240 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -34,16 +34,6 @@ public:
};
A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}}
-template<X const *Ptr> struct A2;
-
-X *X_ptr;
-X an_X;
-X array_of_Xs[10];
-A2<X_ptr> *a12;
-A2<array_of_Xs> *a13;
-A2<&an_X> *a13_2;
-A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
-
float f(float);
float g(float);
@@ -67,6 +57,7 @@ struct Y { } y;
volatile X * X_volatile_ptr;
template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}}
+X an_X;
A4<an_X> *a15_1; // okay
A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}}
A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}} \
@@ -170,3 +161,13 @@ struct X1 {
void test_X0_X1() {
X0<X1::pfunc> x01;
}
+
+// PR6249
+namespace pr6249 {
+ template<typename T, T (*func)()> T f() {
+ return func();
+ }
+
+ int h();
+ template int f<int, h>();
+}
diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp
index e86f07a02ffe..8a07fd7292c2 100644
--- a/test/SemaTemplate/temp_class_spec.cpp
+++ b/test/SemaTemplate/temp_class_spec.cpp
@@ -348,3 +348,16 @@ namespace PR6025 {
{
};
}
+
+namespace PR6181 {
+ template <class T>
+ class a;
+
+ class s;
+
+ template <class U>
+ class a<s> // expected-error{{partial specialization of 'a' does not use any of its template parameters}}
+ {
+ };
+
+}
diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp
index 70a1062c2287..b3f41be7bfad 100644
--- a/test/SemaTemplate/template-id-expr.cpp
+++ b/test/SemaTemplate/template-id-expr.cpp
@@ -27,3 +27,20 @@ struct X0 {
void test_X0_int(X0<int> xi, float f) {
xi.f2(f);
}
+
+// Not template-id expressions, but they almost look like it.
+template<typename F>
+struct Y {
+ Y(const F&);
+};
+
+template<int I>
+struct X {
+ X(int, int);
+ void f() {
+ Y<X<I> >(X<I>(0, 0));
+ Y<X<I> >(::X<I>(0, 0));
+ }
+};
+
+template struct X<3>;
diff --git a/test/SemaTemplate/typename-specifier-4.cpp b/test/SemaTemplate/typename-specifier-4.cpp
index 7fd88f130fa6..0a6fef74c340 100644
--- a/test/SemaTemplate/typename-specifier-4.cpp
+++ b/test/SemaTemplate/typename-specifier-4.cpp
@@ -68,3 +68,34 @@ struct X0 {
void f2(typename X0<T>::Inner<T*, T&>::type); // expected-note{{here}}
void f2(typename X0<T>::template Inner<T*, T&>::type); // expected-error{{redecl}}
};
+
+namespace PR6236 {
+ template<typename T, typename U> struct S { };
+
+ template<typename T> struct S<T, T> {
+ template<typename U> struct K { };
+
+ void f() {
+ typedef typename S<T, T>::template K<T> Foo;
+ }
+ };
+}
+
+namespace PR6268 {
+ template <typename T>
+ struct Outer {
+ template <typename U>
+ struct Inner {};
+
+ template <typename U>
+ typename Outer<T>::template Inner<U>
+ foo(typename Outer<T>::template Inner<U>);
+ };
+
+ template <typename T>
+ template <typename U>
+ typename Outer<T>::template Inner<U>
+ Outer<T>::foo(typename Outer<T>::template Inner<U>) {
+ return Inner<U>();
+ }
+}
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 84f908d57183..f9995eb743df 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -14,11 +14,15 @@
#include "CIndexer.h"
#include "CXCursor.h"
+#include "CXSourceLocation.h"
+#include "CIndexDiagnostic.h"
#include "clang/Basic/Version.h"
+
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -116,34 +120,6 @@ public:
#endif
#endif
-typedef llvm::PointerIntPair<ASTContext *, 1, bool> CXSourceLocationPtr;
-
-/// \brief Translate a Clang source location into a CIndex source location.
-static CXSourceLocation translateSourceLocation(ASTContext &Context,
- SourceLocation Loc,
- bool AtEnd = false) {
- CXSourceLocationPtr Ptr(&Context, AtEnd);
- CXSourceLocation Result = { Ptr.getOpaqueValue(), Loc.getRawEncoding() };
- return Result;
-}
-
-/// \brief Translate a Clang source range into a CIndex source range.
-static CXSourceRange translateSourceRange(ASTContext &Context, SourceRange R) {
- CXSourceRange Result = { &Context,
- R.getBegin().getRawEncoding(),
- R.getEnd().getRawEncoding() };
- return Result;
-}
-
-static SourceLocation translateSourceLocation(CXSourceLocation L) {
- return SourceLocation::getFromRawEncoding(L.int_data);
-}
-
-static SourceRange translateSourceRange(CXSourceRange R) {
- return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data),
- SourceLocation::getFromRawEncoding(R.end_int_data));
-}
-
/// \brief The result of comparing two source ranges.
enum RangeComparisonResult {
/// \brief Either the ranges overlap or one of the ranges is invalid.
@@ -163,13 +139,57 @@ static RangeComparisonResult RangeCompare(SourceManager &SM,
SourceRange R2) {
assert(R1.isValid() && "First range is invalid?");
assert(R2.isValid() && "Second range is invalid?");
- if (SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
+ if (R1.getEnd() == R2.getBegin() ||
+ SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
return RangeBefore;
- if (SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin()))
+ if (R2.getEnd() == R1.getBegin() ||
+ SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin()))
return RangeAfter;
return RangeOverlap;
}
+/// \brief Translate a Clang source range into a CIndex source range.
+///
+/// Clang internally represents ranges where the end location points to the
+/// start of the token at the end. However, for external clients it is more
+/// useful to have a CXSourceRange be a proper half-open interval. This routine
+/// does the appropriate translation.
+CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceRange R) {
+ // FIXME: This is largely copy-paste from
+ // TextDiagnosticPrinter::HighlightRange. When it is clear that this is what
+ // we want the two routines should be refactored.
+
+ // We want the last character in this location, so we will adjust the
+ // instantiation location accordingly.
+
+ // If the location is from a macro instantiation, get the end of the
+ // instantiation range.
+ SourceLocation EndLoc = R.getEnd();
+ SourceLocation InstLoc = SM.getInstantiationLoc(EndLoc);
+ if (EndLoc.isMacroID())
+ InstLoc = SM.getInstantiationRange(EndLoc).second;
+
+ // Measure the length token we're pointing at, so we can adjust the physical
+ // location in the file to point at the last character.
+ //
+ // FIXME: This won't cope with trigraphs or escaped newlines well. For that,
+ // we actually need a preprocessor, which isn't currently available
+ // here. Eventually, we'll switch the pointer data of
+ // CXSourceLocation/CXSourceRange to a translation unit (CXXUnit), so that the
+ // preprocessor will be available here. At that point, we can use
+ // Preprocessor::getLocForEndOfToken().
+ if (InstLoc.isValid()) {
+ unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, LangOpts);
+ EndLoc = EndLoc.getFileLocWithOffset(Length);
+ }
+
+ CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts },
+ R.getBegin().getRawEncoding(),
+ EndLoc.getRawEncoding() };
+ return Result;
+}
//===----------------------------------------------------------------------===//
// Cursor visitor.
@@ -214,15 +234,9 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
/// \brief Determine whether this particular source range comes before, comes
/// after, or overlaps the region of interest.
///
- /// \param R a source range retrieved from the abstract syntax tree.
+ /// \param R a half-open source range retrieved from the abstract syntax tree.
RangeComparisonResult CompareRegionOfInterest(SourceRange R);
- /// \brief Determine whether this particular source range comes before, comes
- /// after, or overlaps the region of interest.
- ///
- /// \param CXR a source range retrieved from a cursor.
- RangeComparisonResult CompareRegionOfInterest(CXSourceRange CXR);
-
public:
CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData,
unsigned MaxPCHLevel,
@@ -292,6 +306,8 @@ public:
// FIXME: LabelStmt label?
bool VisitIfStmt(IfStmt *S);
bool VisitSwitchStmt(SwitchStmt *S);
+ bool VisitWhileStmt(WhileStmt *S);
+ bool VisitForStmt(ForStmt *S);
// Expression visitors
bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
@@ -302,20 +318,9 @@ public:
} // end anonymous namespace
RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
- assert(RegionOfInterest.isValid() && "RangeCompare called with invalid range");
- if (R.isInvalid())
- return RangeOverlap;
-
- // Move the end of the input range to the end of the last token in that
- // range.
- R.setEnd(TU->getPreprocessor().getLocForEndOfToken(R.getEnd(), 1));
return RangeCompare(TU->getSourceManager(), R, RegionOfInterest);
}
-RangeComparisonResult CursorVisitor::CompareRegionOfInterest(CXSourceRange CXR) {
- return CompareRegionOfInterest(translateSourceRange(CXR));
-}
-
/// \brief Visit the given cursor and, if requested by the visitor,
/// its children.
///
@@ -343,9 +348,9 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
// If we have a range of interest, and this cursor doesn't intersect with it,
// we're done.
if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) {
- CXSourceRange Range = clang_getCursorExtent(Cursor);
- if (translateSourceRange(Range).isInvalid() ||
- CompareRegionOfInterest(Range))
+ SourceRange Range =
+ cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor));
+ if (Range.isInvalid() || CompareRegionOfInterest(Range))
return false;
}
@@ -360,7 +365,7 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
return VisitChildren(Cursor);
}
- llvm_unreachable("Silly GCC, we can't get here");
+ return false;
}
/// \brief Visit the children of the given cursor.
@@ -432,12 +437,15 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
for (DeclContext::decl_iterator
I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+ CXCursor Cursor = MakeCXCursor(*I, TU);
+
if (RegionOfInterest.isValid()) {
- SourceRange R = (*I)->getSourceRange();
- if (R.isInvalid())
+ SourceRange Range =
+ cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor));
+ if (Range.isInvalid())
continue;
-
- switch (CompareRegionOfInterest(R)) {
+
+ switch (CompareRegionOfInterest(Range)) {
case RangeBefore:
// This declaration comes before the region of interest; skip it.
continue;
@@ -452,7 +460,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
}
}
- if (Visit(MakeCXCursor(*I, TU), true))
+ if (Visit(Cursor, true))
return true;
}
@@ -783,7 +791,7 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
bool CursorVisitor::VisitStmt(Stmt *S) {
for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end();
Child != ChildEnd; ++Child) {
- if (Visit(MakeCXCursor(*Child, StmtParent, TU)))
+ if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU)))
return true;
}
@@ -793,7 +801,7 @@ bool CursorVisitor::VisitStmt(Stmt *S) {
bool CursorVisitor::VisitDeclStmt(DeclStmt *S) {
for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
- if (Visit(MakeCXCursor(*D, TU)))
+ if (*D && Visit(MakeCXCursor(*D, TU)))
return true;
}
@@ -804,12 +812,12 @@ bool CursorVisitor::VisitIfStmt(IfStmt *S) {
if (VarDecl *Var = S->getConditionVariable()) {
if (Visit(MakeCXCursor(Var, TU)))
return true;
- } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
- return true;
+ }
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
if (S->getThen() && Visit(MakeCXCursor(S->getThen(), StmtParent, TU)))
return true;
-
if (S->getElse() && Visit(MakeCXCursor(S->getElse(), StmtParent, TU)))
return true;
@@ -820,9 +828,42 @@ bool CursorVisitor::VisitSwitchStmt(SwitchStmt *S) {
if (VarDecl *Var = S->getConditionVariable()) {
if (Visit(MakeCXCursor(Var, TU)))
return true;
- } else if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ }
+
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
+ if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitWhileStmt(WhileStmt *S) {
+ if (VarDecl *Var = S->getConditionVariable()) {
+ if (Visit(MakeCXCursor(Var, TU)))
+ return true;
+ }
+
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
+ if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU)))
return true;
+ return false;
+}
+
+bool CursorVisitor::VisitForStmt(ForStmt *S) {
+ if (S->getInit() && Visit(MakeCXCursor(S->getInit(), StmtParent, TU)))
+ return true;
+ if (VarDecl *Var = S->getConditionVariable()) {
+ if (Visit(MakeCXCursor(Var, TU)))
+ return true;
+ }
+
+ if (S->getCond() && Visit(MakeCXCursor(S->getCond(), StmtParent, TU)))
+ return true;
+ if (S->getInc() && Visit(MakeCXCursor(S->getInc(), StmtParent, TU)))
+ return true;
if (S->getBody() && Visit(MakeCXCursor(S->getBody(), StmtParent, TU)))
return true;
@@ -868,37 +909,59 @@ CXString CIndexer::createCXString(const char *String, bool DupString){
return Str;
}
+CXString CIndexer::createCXString(llvm::StringRef String, bool DupString) {
+ CXString Result;
+ if (DupString || (!String.empty() && String.data()[String.size()] != 0)) {
+ char *Spelling = (char *)malloc(String.size() + 1);
+ memmove(Spelling, String.data(), String.size());
+ Spelling[String.size()] = 0;
+ Result.Spelling = Spelling;
+ Result.MustFreeString = 1;
+ } else {
+ Result.Spelling = String.data();
+ Result.MustFreeString = 0;
+ }
+ return Result;
+}
+
extern "C" {
-CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
- int displayDiagnostics) {
+CXIndex clang_createIndex(int excludeDeclarationsFromPCH) {
CIndexer *CIdxr = new CIndexer();
if (excludeDeclarationsFromPCH)
CIdxr->setOnlyLocalDecls();
- if (displayDiagnostics)
- CIdxr->setDisplayDiagnostics();
return CIdxr;
}
void clang_disposeIndex(CXIndex CIdx) {
- assert(CIdx && "Passed null CXIndex");
- delete static_cast<CIndexer *>(CIdx);
+ if (CIdx)
+ delete static_cast<CIndexer *>(CIdx);
}
void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) {
- assert(CIdx && "Passed null CXIndex");
- CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
- CXXIdx->setUseExternalASTGeneration(value);
+ if (CIdx) {
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ CXXIdx->setUseExternalASTGeneration(value);
+ }
}
-// FIXME: need to pass back error info.
CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
- const char *ast_filename) {
- assert(CIdx && "Passed null CXIndex");
+ const char *ast_filename,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
+ if (!CIdx)
+ return 0;
+
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
- return ASTUnit::LoadFromPCHFile(ast_filename, CXXIdx->getDiags(),
- CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true);
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ llvm::OwningPtr<Diagnostic> Diags;
+ Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
+ CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
+ Diags->setClient(&DiagClient);
+
+ return ASTUnit::LoadFromPCHFile(ast_filename, *Diags,
+ CXXIdx->getOnlyLocalDecls());
}
CXTranslationUnit
@@ -907,10 +970,21 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
int num_command_line_args,
const char **command_line_args,
unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files) {
- assert(CIdx && "Passed null CXIndex");
+ struct CXUnsavedFile *unsaved_files,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
+ if (!CIdx)
+ return 0;
+
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ llvm::OwningPtr<Diagnostic> Diags;
+ Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
+ CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
+ Diags->setClient(&DiagClient);
+
llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
for (unsigned I = 0; I != num_unsaved_files; ++I) {
const llvm::MemoryBuffer *Buffer
@@ -932,7 +1006,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
Args.insert(Args.end(), command_line_args,
command_line_args + num_command_line_args);
- unsigned NumErrors = CXXIdx->getDiags().getNumErrors();
+ unsigned NumErrors = Diags->getNumErrors();
#ifdef USE_CRASHTRACER
ArgsCrashTracerInfo ACTI(Args);
@@ -940,16 +1014,15 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
llvm::OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
- CXXIdx->getDiags(),
+ *Diags,
CXXIdx->getClangResourcesPath(),
CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true,
RemappedFiles.data(),
RemappedFiles.size()));
// FIXME: Until we have broader testing, just drop the entire AST if we
// encountered an error.
- if (NumErrors != CXXIdx->getDiags().getNumErrors())
+ if (NumErrors != Diags->getNumErrors())
return 0;
return Unit.take();
@@ -1004,6 +1077,13 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
argv.push_back(arg);
}
+ // Generate a temporary name for the diagnostics file.
+ char tmpFileResults[L_tmpnam];
+ char *tmpResultsFileName = tmpnam(tmpFileResults);
+ llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
+ TemporaryFiles.push_back(DiagnosticsFile);
+ argv.push_back("-fdiagnostics-binary");
+
// Add the null terminator.
argv.push_back(NULL);
@@ -1011,30 +1091,39 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
std::string ErrMsg;
- const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DevNull, NULL };
+ const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DiagnosticsFile,
+ NULL };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
- /* redirects */ !CXXIdx->getDisplayDiagnostics() ? &Redirects[0] : NULL,
+ /* redirects */ &Redirects[0],
/* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg);
- if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg
- << '\n' << "Arguments: \n";
+ if (!ErrMsg.empty()) {
+ std::string AllArgs;
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
- I!=E; ++I) {
+ I != E; ++I) {
+ AllArgs += ' ';
if (*I)
- llvm::errs() << ' ' << *I << '\n';
+ AllArgs += *I;
}
- llvm::errs() << '\n';
+
+ Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
}
- ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, CXXIdx->getDiags(),
+ // FIXME: Parse the (redirected) standard error to emit diagnostics.
+
+ ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, *Diags,
CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true,
RemappedFiles.data(),
RemappedFiles.size());
if (ATU)
ATU->unlinkTemporaryFile();
+ // FIXME: Currently we don't report diagnostics on invalid ASTs.
+ if (ATU)
+ ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
+ num_unsaved_files, unsaved_files,
+ ATU->getASTContext().getLangOptions());
+
for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
TemporaryFiles[i].eraseFromDisk();
@@ -1042,12 +1131,14 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
}
void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
- assert(CTUnit && "Passed null CXTranslationUnit");
- delete static_cast<ASTUnit *>(CTUnit);
+ if (CTUnit)
+ delete static_cast<ASTUnit *>(CTUnit);
}
CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
- assert(CTUnit && "Passed null CXTranslationUnit");
+ if (!CTUnit)
+ return CIndexer::createCXString("");
+
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
return CIndexer::createCXString(CXXUnit->getOriginalSourceFileName().c_str(),
true);
@@ -1066,12 +1157,14 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
extern "C" {
CXSourceLocation clang_getNullLocation() {
- CXSourceLocation Result = { 0, 0 };
+ CXSourceLocation Result = { { 0, 0 }, 0 };
return Result;
}
unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
- return loc1.ptr_data == loc2.ptr_data && loc1.int_data == loc2.int_data;
+ return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
+ loc1.ptr_data[1] == loc2.ptr_data[1] &&
+ loc1.int_data == loc2.int_data);
}
CXSourceLocation clang_getLocation(CXTranslationUnit tu,
@@ -1087,67 +1180,46 @@ CXSourceLocation clang_getLocation(CXTranslationUnit tu,
static_cast<const FileEntry *>(file),
line, column);
- return translateSourceLocation(CXXUnit->getASTContext(), SLoc, false);
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+}
+
+CXSourceRange clang_getNullRange() {
+ CXSourceRange Result = { { 0, 0 }, 0, 0 };
+ return Result;
}
CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
- if (begin.ptr_data != end.ptr_data) {
- CXSourceRange Result = { 0, 0, 0 };
- return Result;
- }
+ if (begin.ptr_data[0] != end.ptr_data[0] ||
+ begin.ptr_data[1] != end.ptr_data[1])
+ return clang_getNullRange();
- CXSourceRange Result = { begin.ptr_data, begin.int_data, end.int_data };
+ CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
+ begin.int_data, end.int_data };
return Result;
}
void clang_getInstantiationLocation(CXSourceLocation location,
CXFile *file,
unsigned *line,
- unsigned *column) {
- CXSourceLocationPtr Ptr
- = CXSourceLocationPtr::getFromOpaqueValue(location.ptr_data);
+ unsigned *column,
+ unsigned *offset) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
- if (!Ptr.getPointer() || Loc.isInvalid()) {
+ if (!location.ptr_data[0] || Loc.isInvalid()) {
if (file)
*file = 0;
if (line)
*line = 0;
if (column)
*column = 0;
+ if (offset)
+ *offset = 0;
return;
}
- // FIXME: This is largely copy-paste from
- ///TextDiagnosticPrinter::HighlightRange. When it is clear that this is
- // what we want the two routines should be refactored.
- ASTContext &Context = *Ptr.getPointer();
- SourceManager &SM = Context.getSourceManager();
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
SourceLocation InstLoc = SM.getInstantiationLoc(Loc);
-
- if (Ptr.getInt()) {
- // We want the last character in this location, so we will adjust
- // the instantiation location accordingly.
-
- // If the location is from a macro instantiation, get the end of
- // the instantiation range.
- if (Loc.isMacroID())
- InstLoc = SM.getInstantiationRange(Loc).second;
-
- // Measure the length token we're pointing at, so we can adjust
- // the physical location in the file to point at the last
- // character.
- // FIXME: This won't cope with trigraphs or escaped newlines
- // well. For that, we actually need a preprocessor, which isn't
- // currently available here. Eventually, we'll switch the pointer
- // data of CXSourceLocation/CXSourceRange to a translation unit
- // (CXXUnit), so that the preprocessor will be available here. At
- // that point, we can use Preprocessor::getLocForEndOfToken().
- unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM,
- Context.getLangOptions());
- if (Length > 0)
- InstLoc = InstLoc.getFileLocWithOffset(Length - 1);
- }
if (file)
*file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc));
@@ -1155,18 +1227,19 @@ void clang_getInstantiationLocation(CXSourceLocation location,
*line = SM.getInstantiationLineNumber(InstLoc);
if (column)
*column = SM.getInstantiationColumnNumber(InstLoc);
+ if (offset)
+ *offset = SM.getDecomposedLoc(InstLoc).second;
}
CXSourceLocation clang_getRangeStart(CXSourceRange range) {
- CXSourceLocation Result = { range.ptr_data, range.begin_int_data };
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.begin_int_data };
return Result;
}
CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
- llvm::PointerIntPair<ASTContext *, 1, bool> Ptr;
- Ptr.setPointer(static_cast<ASTContext *>(range.ptr_data));
- Ptr.setInt(true);
- CXSourceLocation Result = { Ptr.getOpaqueValue(), range.end_int_data };
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.end_int_data };
return Result;
}
@@ -1181,7 +1254,6 @@ const char *clang_getFileName(CXFile SFile) {
if (!SFile)
return 0;
- assert(SFile && "Passed null CXFile");
FileEntry *FEnt = static_cast<FileEntry *>(SFile);
return FEnt->getName();
}
@@ -1190,7 +1262,6 @@ time_t clang_getFileTime(CXFile SFile) {
if (!SFile)
return 0;
- assert(SFile && "Passed null CXFile");
FileEntry *FEnt = static_cast<FileEntry *>(SFile);
return FEnt->getModificationTime();
}
@@ -1230,6 +1301,18 @@ static Decl *getDeclFromExpr(Stmt *E) {
return 0;
}
+static SourceLocation getLocationFromExpr(Expr *E) {
+ if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
+ return /*FIXME:*/Msg->getLeftLoc();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getLocation();
+ if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
+ return Member->getMemberLoc();
+ if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
+ return Ivar->getLocation();
+ return E->getLocStart();
+}
+
extern "C" {
unsigned clang_visitChildren(CXCursor parent,
@@ -1274,7 +1357,6 @@ static CXString getDeclSpelling(Decl *D) {
}
CXString clang_getCursorSpelling(CXCursor C) {
- assert(getCursorDecl(C) && "CXCursor has null decl");
if (clang_isTranslationUnit(C.kind))
return clang_getTranslationUnitSpelling(C.data[2]);
@@ -1314,7 +1396,10 @@ CXString clang_getCursorSpelling(CXCursor C) {
return CIndexer::createCXString("");
}
- return getDeclSpelling(getCursorDecl(C));
+ if (clang_isDeclaration(C.kind))
+ return getDeclSpelling(getCursorDecl(C));
+
+ return CIndexer::createCXString("");
}
const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) {
@@ -1373,11 +1458,10 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
- SourceLocation SLoc = translateSourceLocation(Loc);
+ SourceLocation SLoc = cxloc::translateSourceLocation(Loc);
CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
if (SLoc.isValid()) {
- SourceRange RegionOfInterest(SLoc,
- CXXUnit->getPreprocessor().getLocForEndOfToken(SLoc, 1));
+ SourceRange RegionOfInterest(SLoc, SLoc.getFileLocWithOffset(1));
// FIXME: Would be great to have a "hint" cursor, then walk from that
// hint cursor upward until we find a cursor whose source range encloses
@@ -1426,42 +1510,30 @@ CXCursorKind clang_getCursorKind(CXCursor C) {
return C.kind;
}
-static SourceLocation getLocationFromExpr(Expr *E) {
- if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
- return /*FIXME:*/Msg->getLeftLoc();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return DRE->getLocation();
- if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
- return Member->getMemberLoc();
- if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
- return Ivar->getLocation();
- return E->getLocStart();
-}
-
CXSourceLocation clang_getCursorLocation(CXCursor C) {
if (clang_isReference(C.kind)) {
switch (C.kind) {
case CXCursor_ObjCSuperClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCSuperClassRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCProtocolRef: {
std::pair<ObjCProtocolDecl *, SourceLocation> P
= getCursorObjCProtocolRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCClassRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_TypeRef: {
std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
- return translateSourceLocation(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
default:
@@ -1471,19 +1543,17 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
}
if (clang_isExpression(C.kind))
- return translateSourceLocation(getCursorContext(C),
+ return cxloc::translateSourceLocation(getCursorContext(C),
getLocationFromExpr(getCursorExpr(C)));
- if (!getCursorDecl(C)) {
- CXSourceLocation empty = { 0, 0 };
- return empty;
- }
+ if (!getCursorDecl(C))
+ return clang_getNullLocation();
Decl *D = getCursorDecl(C);
SourceLocation Loc = D->getLocation();
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
Loc = Class->getClassLoc();
- return translateSourceLocation(D->getASTContext(), Loc);
+ return cxloc::translateSourceLocation(D->getASTContext(), Loc);
}
CXSourceRange clang_getCursorExtent(CXCursor C) {
@@ -1492,25 +1562,25 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
case CXCursor_ObjCSuperClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCSuperClassRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCProtocolRef: {
std::pair<ObjCProtocolDecl *, SourceLocation> P
= getCursorObjCProtocolRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCClassRef: {
std::pair<ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCClassRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
case CXCursor_TypeRef: {
std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
- return translateSourceRange(P.first->getASTContext(), P.second);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
}
default:
@@ -1520,20 +1590,18 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
}
if (clang_isExpression(C.kind))
- return translateSourceRange(getCursorContext(C),
+ return cxloc::translateSourceRange(getCursorContext(C),
getCursorExpr(C)->getSourceRange());
if (clang_isStatement(C.kind))
- return translateSourceRange(getCursorContext(C),
+ return cxloc::translateSourceRange(getCursorContext(C),
getCursorStmt(C)->getSourceRange());
- if (!getCursorDecl(C)) {
- CXSourceRange empty = { 0, 0, 0 };
- return empty;
- }
+ if (!getCursorDecl(C))
+ return clang_getNullRange();
Decl *D = getCursorDecl(C);
- return translateSourceRange(D->getASTContext(), D->getSourceRange());
+ return cxloc::translateSourceRange(D->getASTContext(), D->getSourceRange());
}
CXCursor clang_getCursorReferenced(CXCursor C) {
@@ -1643,7 +1711,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::CXXRecord:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
- if (TagDecl *Def = cast<TagDecl>(D)->getDefinition(D->getASTContext()))
+ if (TagDecl *Def = cast<TagDecl>(D)->getDefinition())
return MakeCXCursor(Def, CXXUnit);
return clang_getNullCursor();
@@ -1659,23 +1727,10 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
}
case Decl::Var: {
- VarDecl *Var = cast<VarDecl>(D);
-
- // Variables with initializers have definitions.
- const VarDecl *Def = 0;
- if (Var->getDefinition(Def))
- return MakeCXCursor(const_cast<VarDecl *>(Def), CXXUnit);
-
- // extern and private_extern variables are not definitions.
- if (Var->hasExternalStorage())
- return clang_getNullCursor();
-
- // In-line static data members do not have definitions.
- if (Var->isStaticDataMember() && !Var->isOutOfLine())
- return clang_getNullCursor();
-
- // All other variables are themselves definitions.
- return C;
+ // Ask the variable if it has a definition.
+ if (VarDecl *Def = cast<VarDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, CXXUnit);
+ return clang_getNullCursor();
}
case Decl::FunctionTemplate: {
@@ -1687,7 +1742,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ClassTemplate: {
if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl()
- ->getDefinition(D->getASTContext()))
+ ->getDefinition())
return MakeCXCursor(
cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(),
CXXUnit);
@@ -1843,6 +1898,247 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
} // end: extern "C"
//===----------------------------------------------------------------------===//
+// Token-based Operations.
+//===----------------------------------------------------------------------===//
+
+/* CXToken layout:
+ * int_data[0]: a CXTokenKind
+ * int_data[1]: starting token location
+ * int_data[2]: token length
+ * int_data[3]: reserved
+ * ptr_data: for identifiers and keywords, an IdentifierInfo*.
+ * otherwise unused.
+ */
+extern "C" {
+
+CXTokenKind clang_getTokenKind(CXToken CXTok) {
+ return static_cast<CXTokenKind>(CXTok.int_data[0]);
+}
+
+CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
+ switch (clang_getTokenKind(CXTok)) {
+ case CXToken_Identifier:
+ case CXToken_Keyword:
+ // We know we have an IdentifierInfo*, so use that.
+ return CIndexer::createCXString(
+ static_cast<IdentifierInfo *>(CXTok.ptr_data)->getNameStart());
+
+ case CXToken_Literal: {
+ // We have stashed the starting pointer in the ptr_data field. Use it.
+ const char *Text = static_cast<const char *>(CXTok.ptr_data);
+ return CIndexer::createCXString(llvm::StringRef(Text, CXTok.int_data[2]),
+ true);
+ }
+
+ case CXToken_Punctuation:
+ case CXToken_Comment:
+ break;
+ }
+
+ // We have to find the starting buffer pointer the hard way, by
+ // deconstructing the source location.
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit)
+ return CIndexer::createCXString("");
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]);
+ std::pair<FileID, unsigned> LocInfo
+ = CXXUnit->getSourceManager().getDecomposedLoc(Loc);
+ std::pair<const char *,const char *> Buffer
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first);
+
+ return CIndexer::createCXString(llvm::StringRef(Buffer.first+LocInfo.second,
+ CXTok.int_data[2]),
+ true);
+}
+
+CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit)
+ return clang_getNullLocation();
+
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(),
+ SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
+}
+
+CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit)
+ return clang_getNullRange();
+
+ return cxloc::translateSourceRange(CXXUnit->getASTContext(),
+ SourceLocation::getFromRawEncoding(CXTok.int_data[1]));
+}
+
+void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
+ CXToken **Tokens, unsigned *NumTokens) {
+ if (Tokens)
+ *Tokens = 0;
+ if (NumTokens)
+ *NumTokens = 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit || !Tokens || !NumTokens)
+ return;
+
+ SourceRange R = cxloc::translateCXSourceRange(Range);
+ if (R.isInvalid())
+ return;
+
+ SourceManager &SourceMgr = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> BeginLocInfo
+ = SourceMgr.getDecomposedLoc(R.getBegin());
+ std::pair<FileID, unsigned> EndLocInfo
+ = SourceMgr.getDecomposedLoc(R.getEnd());
+
+ // Cannot tokenize across files.
+ if (BeginLocInfo.first != EndLocInfo.first)
+ return;
+
+ // Create a lexer
+ std::pair<const char *,const char *> Buffer
+ = SourceMgr.getBufferData(BeginLocInfo.first);
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOptions(),
+ Buffer.first, Buffer.first + BeginLocInfo.second, Buffer.second);
+ Lex.SetCommentRetentionState(true);
+
+ // Lex tokens until we hit the end of the range.
+ const char *EffectiveBufferEnd = Buffer.first + EndLocInfo.second;
+ llvm::SmallVector<CXToken, 32> CXTokens;
+ Token Tok;
+ do {
+ // Lex the next token
+ Lex.LexFromRawLexer(Tok);
+ if (Tok.is(tok::eof))
+ break;
+
+ // Initialize the CXToken.
+ CXToken CXTok;
+
+ // - Common fields
+ CXTok.int_data[1] = Tok.getLocation().getRawEncoding();
+ CXTok.int_data[2] = Tok.getLength();
+ CXTok.int_data[3] = 0;
+
+ // - Kind-specific fields
+ if (Tok.isLiteral()) {
+ CXTok.int_data[0] = CXToken_Literal;
+ CXTok.ptr_data = (void *)Tok.getLiteralData();
+ } else if (Tok.is(tok::identifier)) {
+ // Lookup the identifier to determine whether we have a
+ std::pair<FileID, unsigned> LocInfo
+ = SourceMgr.getDecomposedLoc(Tok.getLocation());
+ const char *StartPos
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first).first +
+ LocInfo.second;
+ IdentifierInfo *II
+ = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos);
+ CXTok.int_data[0] = II->getTokenID() == tok::identifier?
+ CXToken_Identifier
+ : CXToken_Keyword;
+ CXTok.ptr_data = II;
+ } else if (Tok.is(tok::comment)) {
+ CXTok.int_data[0] = CXToken_Comment;
+ CXTok.ptr_data = 0;
+ } else {
+ CXTok.int_data[0] = CXToken_Punctuation;
+ CXTok.ptr_data = 0;
+ }
+ CXTokens.push_back(CXTok);
+ } while (Lex.getBufferLocation() <= EffectiveBufferEnd);
+
+ if (CXTokens.empty())
+ return;
+
+ *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size());
+ memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size());
+ *NumTokens = CXTokens.size();
+}
+
+typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
+
+enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ AnnotateTokensData *Data = static_cast<AnnotateTokensData *>(client_data);
+
+ // We only annotate the locations of declarations, simple
+ // references, and expressions which directly reference something.
+ CXCursorKind Kind = clang_getCursorKind(cursor);
+ if (clang_isDeclaration(Kind) || clang_isReference(Kind)) {
+ // Okay: We can annotate the location of this declaration with the
+ // declaration or reference
+ } else if (clang_isExpression(cursor.kind)) {
+ if (Kind != CXCursor_DeclRefExpr &&
+ Kind != CXCursor_MemberRefExpr &&
+ Kind != CXCursor_ObjCMessageExpr)
+ return CXChildVisit_Recurse;
+
+ CXCursor Referenced = clang_getCursorReferenced(cursor);
+ if (Referenced == cursor || Referenced == clang_getNullCursor())
+ return CXChildVisit_Recurse;
+
+ // Okay: we can annotate the location of this expression
+ } else {
+ // Nothing to annotate
+ return CXChildVisit_Recurse;
+ }
+
+ CXSourceLocation Loc = clang_getCursorLocation(cursor);
+ (*Data)[Loc.int_data] = cursor;
+ return CXChildVisit_Recurse;
+}
+
+void clang_annotateTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens,
+ CXCursor *Cursors) {
+ if (NumTokens == 0)
+ return;
+
+ // Any token we don't specifically annotate will have a NULL cursor.
+ for (unsigned I = 0; I != NumTokens; ++I)
+ Cursors[I] = clang_getNullCursor();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ if (!CXXUnit || !Tokens)
+ return;
+
+ // Annotate all of the source locations in the region of interest that map
+ SourceRange RegionOfInterest;
+ RegionOfInterest.setBegin(
+ cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0])));
+ SourceLocation End
+ = cxloc::translateSourceLocation(clang_getTokenLocation(TU,
+ Tokens[NumTokens - 1]));
+ RegionOfInterest.setEnd(CXXUnit->getPreprocessor().getLocForEndOfToken(End));
+ // FIXME: Would be great to have a "hint" cursor, then walk from that
+ // hint cursor upward until we find a cursor whose source range encloses
+ // the region of interest, rather than starting from the translation unit.
+ AnnotateTokensData Annotated;
+ CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);
+ CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated,
+ Decl::MaxPCHLevel, RegionOfInterest);
+ AnnotateVis.VisitChildren(Parent);
+
+ for (unsigned I = 0; I != NumTokens; ++I) {
+ // Determine whether we saw a cursor at this token's location.
+ AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
+ if (Pos == Annotated.end())
+ continue;
+
+ Cursors[I] = Pos->second;
+ }
+}
+
+void clang_disposeTokens(CXTranslationUnit TU,
+ CXToken *Tokens, unsigned NumTokens) {
+ free(Tokens);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
// CXString Operations.
//===----------------------------------------------------------------------===//
@@ -1864,8 +2160,8 @@ void clang_disposeString(CXString string) {
extern "C" {
-const char *clang_getClangVersion() {
- return getClangFullVersion();
+CXString clang_getClangVersion() {
+ return CIndexer::createCXString(getClangFullVersion(), true);
}
} // end: extern "C"
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
index d349086b9c11..2c738190b4ad 100644
--- a/tools/CIndex/CIndex.exports
+++ b/tools/CIndex/CIndex.exports
@@ -1,3 +1,4 @@
+_clang_annotateTokens
_clang_codeComplete
_clang_createIndex
_clang_createTranslationUnit
@@ -5,6 +6,7 @@ _clang_createTranslationUnitFromSourceFile
_clang_disposeCodeCompleteResults
_clang_disposeIndex
_clang_disposeString
+_clang_disposeTokens
_clang_disposeTranslationUnit
_clang_equalCursors
_clang_equalLocations
@@ -23,17 +25,33 @@ _clang_getCursorReferenced
_clang_getCursorSpelling
_clang_getCursorUSR
_clang_getDefinitionSpellingAndExtent
+_clang_getDiagnosticFixItInsertion
+_clang_getDiagnosticFixItKind
+_clang_getDiagnosticFixItRemoval
+_clang_getDiagnosticFixItReplacement
+_clang_getDiagnosticLocation
+_clang_getDiagnosticNumFixIts
+_clang_getDiagnosticNumRanges
+_clang_getDiagnosticRange
+_clang_getDiagnosticSeverity
+_clang_getDiagnosticSpelling
_clang_getFile
_clang_getFileName
_clang_getFileTime
+_clang_getInclusions
_clang_getInstantiationLocation
_clang_getLocation
_clang_getNullCursor
_clang_getNullLocation
+_clang_getNullRange
_clang_getNumCompletionChunks
_clang_getRange
_clang_getRangeEnd
_clang_getRangeStart
+_clang_getTokenExtent
+_clang_getTokenKind
+_clang_getTokenLocation
+_clang_getTokenSpelling
_clang_getTranslationUnitCursor
_clang_getTranslationUnitSpelling
_clang_isCursorDefinition
@@ -44,4 +62,5 @@ _clang_isReference
_clang_isStatement
_clang_isTranslationUnit
_clang_setUseExternalASTGeneration
+_clang_tokenize
_clang_visitChildren
diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp
index f3b60dc8b01a..4e41c5f1c7b5 100644
--- a/tools/CIndex/CIndexCodeCompletion.cpp
+++ b/tools/CIndex/CIndexCodeCompletion.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
+#include "CIndexDiagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -176,6 +178,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief The memory buffer from which we parsed the results. We
/// retain this buffer because the completion strings point into it.
llvm::MemoryBuffer *Buffer;
+
+ LangOptions LangOpts;
};
CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
@@ -186,10 +190,19 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
struct CXUnsavedFile *unsaved_files,
const char *complete_filename,
unsigned complete_line,
- unsigned complete_column) {
+ unsigned complete_column,
+ CXDiagnosticCallback diag_callback,
+ CXClientData diag_client_data) {
// The indexer, which is mainly used to determine where diagnostics go.
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ llvm::OwningPtr<Diagnostic> Diags;
+ Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
+ CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
+ Diags->setClient(&DiagClient);
+
// The set of temporary files that we've built.
std::vector<llvm::sys::Path> TemporaryFiles;
@@ -220,7 +233,8 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
argv.push_back("-no-code-completion-debug-printer");
argv.push_back("-Xclang");
argv.push_back("-code-completion-macros");
-
+ argv.push_back("-fdiagnostics-binary");
+
// Remap any unsaved files to temporary files.
std::vector<std::string> RemapArgs;
if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
@@ -256,31 +270,39 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
// Add the null terminator.
argv.push_back(NULL);
- // Generate a temporary name for the AST file.
+ // Generate a temporary name for the code-completion results file.
char tmpFile[L_tmpnam];
char *tmpFileName = tmpnam(tmpFile);
llvm::sys::Path ResultsFile(tmpFileName);
TemporaryFiles.push_back(ResultsFile);
+ // Generate a temporary name for the diagnostics file.
+ char tmpFileResults[L_tmpnam];
+ char *tmpResultsFileName = tmpnam(tmpFileResults);
+ llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
+ TemporaryFiles.push_back(DiagnosticsFile);
+
// Invoke 'clang'.
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
std::string ErrMsg;
- const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
+ const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
+ &DiagnosticsFile, 0 };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ &Redirects[0],
/* secondsToWait */ 0,
/* memoryLimits */ 0, &ErrMsg);
- if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_codeComplete: " << ErrMsg
- << '\n' << "Arguments: \n";
+ if (!ErrMsg.empty()) {
+ std::string AllArgs;
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
- I!=E; ++I) {
+ I != E; ++I) {
+ AllArgs += ' ';
if (*I)
- llvm::errs() << ' ' << *I << '\n';
+ AllArgs += *I;
}
- llvm::errs() << '\n';
+
+ Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
}
// Parse the resulting source file to find code-completion results.
@@ -319,6 +341,13 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
Results->Buffer = F;
}
+ // FIXME: The LangOptions we are passing here are not at all correct. However,
+ // in the current design we must pass something in so the SourceLocations have
+ // a LangOptions object to refer to.
+ ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
+ num_unsaved_files, unsaved_files,
+ Results->LangOpts);
+
for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
TemporaryFiles[i].eraseFromDisk();
diff --git a/tools/CIndex/CIndexDiagnostic.cpp b/tools/CIndex/CIndexDiagnostic.cpp
new file mode 100644
index 000000000000..d26094f7ee6f
--- /dev/null
+++ b/tools/CIndex/CIndexDiagnostic.cpp
@@ -0,0 +1,260 @@
+/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface -----------*- C -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements the diagnostic functions of the Clang C interface. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
+#include "CXSourceLocation.h"
+
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace clang;
+using namespace clang::cxloc;
+
+//-----------------------------------------------------------------------------
+// Opaque data structures
+//-----------------------------------------------------------------------------
+namespace {
+ /// \brief The storage behind a CXDiagnostic
+ struct CXStoredDiagnostic {
+ /// \brief The translation unit this diagnostic came from.
+ const LangOptions *LangOptsPtr;
+
+ /// \brief The severity level of this diagnostic.
+ Diagnostic::Level Level;
+
+ /// \brief A reference to the diagnostic information.
+ const DiagnosticInfo &Info;
+ };
+}
+
+//-----------------------------------------------------------------------------
+// CIndex Diagnostic Client
+//-----------------------------------------------------------------------------
+CIndexDiagnosticClient::~CIndexDiagnosticClient() { }
+
+void CIndexDiagnosticClient::BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP) {
+ assert(!LangOptsPtr && "Invalid state!");
+ LangOptsPtr = &LangOpts;
+}
+
+void CIndexDiagnosticClient::EndSourceFile() {
+ assert(LangOptsPtr && "Invalid state!");
+ LangOptsPtr = 0;
+}
+
+void CIndexDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info) {
+ if (!Callback)
+ return;
+
+ assert((LangOptsPtr || Info.getLocation().isInvalid()) &&
+ "Missing language options with located diagnostic!");
+ CXStoredDiagnostic Stored = { this->LangOptsPtr, DiagLevel, Info };
+ Callback(&Stored, ClientData);
+}
+
+//-----------------------------------------------------------------------------
+// C Interface Routines
+//-----------------------------------------------------------------------------
+extern "C" {
+
+enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return CXDiagnostic_Ignored;
+
+ switch (StoredDiag->Level) {
+ case Diagnostic::Ignored: return CXDiagnostic_Ignored;
+ case Diagnostic::Note: return CXDiagnostic_Note;
+ case Diagnostic::Warning: return CXDiagnostic_Warning;
+ case Diagnostic::Error: return CXDiagnostic_Error;
+ case Diagnostic::Fatal: return CXDiagnostic_Fatal;
+ }
+
+ llvm_unreachable("Invalid diagnostic level");
+ return CXDiagnostic_Ignored;
+}
+
+CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || StoredDiag->Info.getLocation().isInvalid())
+ return clang_getNullLocation();
+
+ return translateSourceLocation(StoredDiag->Info.getLocation().getManager(),
+ *StoredDiag->LangOptsPtr,
+ StoredDiag->Info.getLocation());
+}
+
+CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return CIndexer::createCXString("");
+
+ llvm::SmallString<64> Spelling;
+ StoredDiag->Info.FormatDiagnostic(Spelling);
+ return CIndexer::createCXString(Spelling.str(), true);
+}
+
+unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || StoredDiag->Info.getLocation().isInvalid())
+ return 0;
+
+ return StoredDiag->Info.getNumRanges();
+}
+
+CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || Range >= StoredDiag->Info.getNumRanges() ||
+ StoredDiag->Info.getLocation().isInvalid())
+ return clang_getNullRange();
+
+ return translateSourceRange(StoredDiag->Info.getLocation().getManager(),
+ *StoredDiag->LangOptsPtr,
+ StoredDiag->Info.getRange(Range));
+}
+
+unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return 0;
+
+ return StoredDiag->Info.getNumCodeModificationHints();
+}
+
+enum CXFixItKind clang_getDiagnosticFixItKind(CXDiagnostic Diag,
+ unsigned FixIt) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
+ return CXFixIt_Insertion;
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+ if (Hint.RemoveRange.isInvalid())
+ return CXFixIt_Insertion;
+ if (Hint.InsertionLoc.isInvalid())
+ return CXFixIt_Removal;
+
+ return CXFixIt_Replacement;
+}
+
+CXString clang_getDiagnosticFixItInsertion(CXDiagnostic Diag,
+ unsigned FixIt,
+ CXSourceLocation *Location) {
+ if (Location)
+ *Location = clang_getNullLocation();
+
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints())
+ return CIndexer::createCXString("");
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+
+ if (Location && StoredDiag->Info.getLocation().isValid())
+ *Location = translateSourceLocation(
+ StoredDiag->Info.getLocation().getManager(),
+ *StoredDiag->LangOptsPtr,
+ Hint.InsertionLoc);
+ return CIndexer::createCXString(Hint.CodeToInsert);
+}
+
+CXSourceRange clang_getDiagnosticFixItRemoval(CXDiagnostic Diag,
+ unsigned FixIt) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
+ StoredDiag->Info.getLocation().isInvalid())
+ return clang_getNullRange();
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+ return translateSourceRange(StoredDiag->Info.getLocation().getManager(),
+ *StoredDiag->LangOptsPtr,
+ Hint.RemoveRange);
+}
+
+CXString clang_getDiagnosticFixItReplacement(CXDiagnostic Diag,
+ unsigned FixIt,
+ CXSourceRange *Range) {
+ if (Range)
+ *Range = clang_getNullRange();
+
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || FixIt >= StoredDiag->Info.getNumCodeModificationHints() ||
+ StoredDiag->Info.getLocation().isInvalid()) {
+ if (Range)
+ *Range = clang_getNullRange();
+
+ return CIndexer::createCXString("");
+ }
+
+ const CodeModificationHint &Hint
+ = StoredDiag->Info.getCodeModificationHint(FixIt);
+ if (Range)
+ *Range = translateSourceRange(StoredDiag->Info.getLocation().getManager(),
+ *StoredDiag->LangOptsPtr,
+ Hint.RemoveRange);
+ return CIndexer::createCXString(Hint.CodeToInsert);
+}
+
+} // end extern "C"
+
+void clang::ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+ Diagnostic &Diags,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ const LangOptions &LangOpts) {
+ using llvm::MemoryBuffer;
+ using llvm::StringRef;
+ MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
+ if (!F)
+ return;
+
+ // Enter the unsaved files into the file manager.
+ SourceManager SourceMgr;
+ FileManager FileMgr;
+ for (unsigned I = 0; I != num_unsaved_files; ++I) {
+ const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename,
+ unsaved_files[I].Length,
+ 0);
+ if (!File) {
+ Diags.Report(diag::err_fe_remap_missing_from_file)
+ << unsaved_files[I].Filename;
+ return;
+ }
+
+ MemoryBuffer *Buffer
+ = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
+ unsaved_files[I].Contents + unsaved_files[I].Length);
+ if (!Buffer)
+ return;
+
+ SourceMgr.overrideFileContents(File, Buffer);
+ }
+
+ Diags.getClient()->BeginSourceFile(LangOpts, 0);
+
+ // Parse the diagnostics, emitting them one by one until we've
+ // exhausted the data.
+ StringRef Buffer = F->getBuffer();
+ const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size();
+ while (Memory != MemoryEnd) {
+ DiagnosticBuilder DB = Diags.Deserialize(FileMgr, SourceMgr,
+ Memory, MemoryEnd);
+ if (!DB.isActive())
+ return;
+ }
+
+ Diags.getClient()->EndSourceFile();
+}
diff --git a/tools/CIndex/CIndexDiagnostic.h b/tools/CIndex/CIndexDiagnostic.h
new file mode 100644
index 000000000000..9f7ae51a1083
--- /dev/null
+++ b/tools/CIndex/CIndexDiagnostic.h
@@ -0,0 +1,66 @@
+/*===-- CIndexDiagnostic.h - Diagnostics C Interface ------------*- C++ -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements the diagnostic functions of the Clang C interface. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+#ifndef LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+#define LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+
+#include "clang-c/Index.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+
+namespace llvm { namespace sys {
+class Path;
+} }
+
+namespace clang {
+
+class Diagnostic;
+class LangOptions;
+class Preprocessor;
+
+/**
+ * \brief Diagnostic client that translates Clang diagnostics into diagnostics
+ * for the C interface to Clang.
+ */
+class CIndexDiagnosticClient : public DiagnosticClient {
+ CXDiagnosticCallback Callback;
+ CXClientData ClientData;
+ const LangOptions *LangOptsPtr;
+
+public:
+ CIndexDiagnosticClient(CXDiagnosticCallback Callback,
+ CXClientData ClientData)
+ : Callback(Callback), ClientData(ClientData), LangOptsPtr(0) { }
+
+ virtual ~CIndexDiagnosticClient();
+
+ virtual void BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP);
+
+ virtual void EndSourceFile();
+
+ virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+ const DiagnosticInfo &Info);
+};
+
+/// \brief Given the path to a file that contains binary, serialized
+/// diagnostics produced by Clang, emit those diagnostics via the
+/// given diagnostic engine.
+void ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+ Diagnostic &Diags,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ const LangOptions &LangOpts);
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H
diff --git a/tools/CIndex/CIndexInclusionStack.cpp b/tools/CIndex/CIndexInclusionStack.cpp
new file mode 100644
index 000000000000..4a884e588432
--- /dev/null
+++ b/tools/CIndex/CIndexInclusionStack.cpp
@@ -0,0 +1,65 @@
+//===- CIndexInclusionStack.cpp - Clang-C Source Indexing Library ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a callback mechanism for clients to get the inclusion
+// stack from a translation unit.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CXSourceLocation.h"
+#include "clang/AST/DeclVisitor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+extern "C" {
+void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
+ CXClientData clientData) {
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+ SourceManager &SM = CXXUnit->getSourceManager();
+ ASTContext &Ctx = CXXUnit->getASTContext();
+
+ llvm::SmallVector<CXSourceLocation, 10> InclusionStack;
+ unsigned i = SM.sloc_loaded_entry_size();
+ unsigned n = SM.sloc_entry_size();
+
+ // In the case where all the SLocEntries are in an external source, traverse
+ // those SLocEntries as well. This is the case where we are looking
+ // at the inclusion stack of an AST/PCH file.
+ if (i >= n)
+ i = 0;
+
+ for ( ; i < n ; ++i) {
+
+ const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i);
+
+ if (!SL.isFile())
+ continue;
+
+ const SrcMgr::FileInfo &FI = SL.getFile();
+ if (!FI.getContentCache()->Entry)
+ continue;
+
+ // Build the inclusion stack.
+ SourceLocation L = FI.getIncludeLoc();
+ InclusionStack.clear();
+ while (L.isValid()) {
+ PresumedLoc PLoc = SM.getPresumedLoc(L);
+ InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L));
+ L = PLoc.getIncludeLoc();
+ }
+
+ // Callback to the client.
+ // FIXME: We should have a function to construct CXFiles.
+ CB((CXFile) FI.getContentCache()->Entry,
+ InclusionStack.data(), InclusionStack.size(), clientData);
+ }
+}
+} // end extern C
diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp
index fd605fb68d1b..a992dbf12a00 100644
--- a/tools/CIndex/CIndexUSRs.cpp
+++ b/tools/CIndex/CIndexUSRs.cpp
@@ -74,7 +74,7 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
void USRGenerator::VisitNamedDecl(NamedDecl *D) {
VisitDeclContext(D->getDeclContext());
const std::string &s = D->getNameAsString();
- assert(!s.empty());
+// assert(!s.empty());
Out << "@^" << s;
}
diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp
index 53636a4ff351..0774ae2f3722 100644
--- a/tools/CIndex/CIndexer.cpp
+++ b/tools/CIndex/CIndexer.cpp
@@ -69,7 +69,7 @@ const llvm::sys::Path& CIndexer::getClangPath() {
// We now have the CIndex directory, locate clang relative to it.
CIndexPath.eraseComponent();
- CIndexPath.eraseComponent();
+ CIndexPath.appendComponent("..");
CIndexPath.appendComponent("bin");
CIndexPath.appendComponent("clang");
#endif
@@ -95,16 +95,38 @@ std::string CIndexer::getClangResourcesPath() {
return P.str();
}
+static llvm::sys::Path GetTemporaryPath() {
+ // FIXME: This is lame; sys::Path should provide this function (in particular,
+ // it should know how to find the temporary files dir).
+ std::string Error;
+ const char *TmpDir = ::getenv("TMPDIR");
+ if (!TmpDir)
+ TmpDir = ::getenv("TEMP");
+ if (!TmpDir)
+ TmpDir = ::getenv("TMP");
+ if (!TmpDir)
+ TmpDir = "/tmp";
+ llvm::sys::Path P(TmpDir);
+ P.appendComponent("remap");
+ if (P.makeUnique(false, &Error))
+ return llvm::sys::Path("");
+
+ // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837.
+ P.eraseFromDisk(false, 0);
+
+ return P;
+}
+
bool clang::RemapFiles(unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files,
std::vector<std::string> &RemapArgs,
std::vector<llvm::sys::Path> &TemporaryFiles) {
for (unsigned i = 0; i != num_unsaved_files; ++i) {
- char tmpFile[L_tmpnam];
- char *tmpFileName = tmpnam(tmpFile);
-
// Write the contents of this unsaved file into the temporary file.
- llvm::sys::Path SavedFile(tmpFileName);
+ llvm::sys::Path SavedFile(GetTemporaryPath());
+ if (SavedFile.empty())
+ return true;
+
std::string ErrorInfo;
llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
if (!ErrorInfo.empty())
@@ -120,7 +142,7 @@ bool clang::RemapFiles(unsigned num_unsaved_files,
// Remap the file.
std::string RemapArg = unsaved_files[i].Filename;
RemapArg += ';';
- RemapArg += tmpFileName;
+ RemapArg += SavedFile.str();
RemapArgs.push_back("-Xclang");
RemapArgs.push_back("-remap-file");
RemapArgs.push_back("-Xclang");
diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h
index d01454f9dc64..b83e2b7f326c 100644
--- a/tools/CIndex/CIndexer.h
+++ b/tools/CIndex/CIndexer.h
@@ -18,36 +18,20 @@
#include "clang-c/Index.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/ASTUnit.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/System/Path.h"
#include <vector>
using namespace clang;
-/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted
-/// warnings and errors.
-class IgnoreDiagnosticsClient : public DiagnosticClient {
-public:
- virtual ~IgnoreDiagnosticsClient() {}
- virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
-};
-
class CIndexer {
- DiagnosticOptions DiagOpts;
- IgnoreDiagnosticsClient IgnoreDiagClient;
- llvm::OwningPtr<Diagnostic> TextDiags;
- Diagnostic IgnoreDiags;
bool UseExternalASTGeneration;
bool OnlyLocalDecls;
- bool DisplayDiagnostics;
llvm::sys::Path ClangPath;
public:
- CIndexer() : IgnoreDiags(&IgnoreDiagClient), UseExternalASTGeneration(false),
- OnlyLocalDecls(false), DisplayDiagnostics(false)
- {
- TextDiags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
- }
+ CIndexer() : UseExternalASTGeneration(false), OnlyLocalDecls(false) { }
/// \brief Whether we only want to see "local" declarations (that did not
/// come from a previous precompiled header). If false, we want to see all
@@ -55,20 +39,11 @@ public:
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
- bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
- void setDisplayDiagnostics(bool Display = true) {
- DisplayDiagnostics = Display;
- }
-
bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; }
void setUseExternalASTGeneration(bool Value) {
UseExternalASTGeneration = Value;
}
- Diagnostic &getDiags() {
- return DisplayDiagnostics ? *TextDiags : IgnoreDiags;
- }
-
/// \brief Get the path of the clang binary.
const llvm::sys::Path& getClangPath();
@@ -76,6 +51,8 @@ public:
std::string getClangResourcesPath();
static CXString createCXString(const char *String, bool DupString = false);
+ static CXString createCXString(llvm::StringRef String,
+ bool DupString = false);
};
namespace clang {
diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt
index 730eaafb5a2e..26e1b3bb905c 100644
--- a/tools/CIndex/CMakeLists.txt
+++ b/tools/CIndex/CMakeLists.txt
@@ -21,6 +21,8 @@ set( LLVM_LINK_COMPONENTS
add_clang_library(CIndex
CIndex.cpp
CIndexCodeCompletion.cpp
+ CIndexDiagnostic.cpp
+ CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp
CXCursor.cpp
diff --git a/tools/CIndex/CXCursor.cpp b/tools/CIndex/CXCursor.cpp
index 63d9bc9f2e9a..ec1477eb8a27 100644
--- a/tools/CIndex/CXCursor.cpp
+++ b/tools/CIndex/CXCursor.cpp
@@ -29,6 +29,7 @@ CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) {
}
static CXCursorKind GetCursorKind(Decl *D) {
+ assert(D && "Invalid arguments!");
switch (D->getKind()) {
case Decl::Enum: return CXCursor_EnumDecl;
case Decl::EnumConstant: return CXCursor_EnumConstantDecl;
@@ -72,11 +73,13 @@ static CXCursorKind GetCursorKind(Decl *D) {
}
CXCursor cxcursor::MakeCXCursor(Decl *D, ASTUnit *TU) {
+ assert(D && TU && "Invalid arguments!");
CXCursor C = { GetCursorKind(D), { D, 0, TU } };
return C;
}
CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
+ assert(S && TU && "Invalid arguments!");
CXCursorKind K = CXCursor_NotImplemented;
switch (S->getStmtClass()) {
@@ -112,7 +115,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
K = CXCursor_UnexposedStmt;
break;
- case Stmt::ExprClass:
case Stmt::PredefinedExprClass:
case Stmt::IntegerLiteralClass:
case Stmt::FloatingLiteralClass:
@@ -123,12 +125,10 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
case Stmt::UnaryOperatorClass:
case Stmt::SizeOfAlignOfExprClass:
case Stmt::ArraySubscriptExprClass:
- case Stmt::CastExprClass:
case Stmt::BinaryOperatorClass:
case Stmt::CompoundAssignOperatorClass:
case Stmt::ConditionalOperatorClass:
case Stmt::ImplicitCastExprClass:
- case Stmt::ExplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CompoundLiteralExprClass:
case Stmt::ExtVectorElementExprClass:
@@ -162,6 +162,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
case Stmt::UnaryTypeTraitExprClass:
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXBindReferenceExprClass:
case Stmt::CXXExprWithTemporariesClass:
case Stmt::CXXUnresolvedConstructExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
@@ -214,6 +215,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
SourceLocation Loc,
ASTUnit *TU) {
+ assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_ObjCSuperClassRef, { Super, RawLoc, TU } };
return C;
@@ -230,6 +232,7 @@ cxcursor::getCursorObjCSuperClassRef(CXCursor C) {
CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super,
SourceLocation Loc,
ASTUnit *TU) {
+ assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_ObjCProtocolRef, { Super, RawLoc, TU } };
return C;
@@ -246,6 +249,7 @@ cxcursor::getCursorObjCProtocolRef(CXCursor C) {
CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
SourceLocation Loc,
ASTUnit *TU) {
+ assert(Class && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } };
return C;
@@ -261,6 +265,7 @@ cxcursor::getCursorObjCClassRef(CXCursor C) {
CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
ASTUnit *TU) {
+ assert(Type && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
CXCursor C = { CXCursor_TypeRef, { Type, RawLoc, TU } };
return C;
diff --git a/tools/CIndex/CXCursor.h b/tools/CIndex/CXCursor.h
index 546dd7f48543..30fb26c936bf 100644
--- a/tools/CIndex/CXCursor.h
+++ b/tools/CIndex/CXCursor.h
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_CXCURSOR_H
-#define LLVM_CLANG_CXCursor_H
+#define LLVM_CLANG_CXCURSOR_H
#include "clang-c/Index.h"
#include "clang/Basic/SourceLocation.h"
diff --git a/tools/CIndex/CXSourceLocation.h b/tools/CIndex/CXSourceLocation.h
new file mode 100644
index 000000000000..8bfc6f9da7ab
--- /dev/null
+++ b/tools/CIndex/CXSourceLocation.h
@@ -0,0 +1,76 @@
+//===- CXSourceLocation.h - CXSourceLocations Utilities ---------*- 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 routines for manipulating CXSourceLocations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CXSOURCELOCATION_H
+#define LLVM_CLANG_CXSOURCELOCATION_H
+
+#include "clang-c/Index.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+
+class ASTContext;
+
+namespace cxloc {
+
+/// \brief Translate a Clang source location into a CIndex source location.
+static inline CXSourceLocation
+translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
+ SourceLocation Loc) {
+ CXSourceLocation Result = { { (void*) &SM, (void*) &LangOpts, },
+ Loc.getRawEncoding() };
+ return Result;
+}
+
+/// \brief Translate a Clang source location into a CIndex source location.
+static inline CXSourceLocation translateSourceLocation(ASTContext &Context,
+ SourceLocation Loc) {
+ return translateSourceLocation(Context.getSourceManager(),
+ Context.getLangOptions(),
+ Loc);
+}
+
+/// \brief Translate a Clang source range into a CIndex source range.
+///
+/// Clang internally represents ranges where the end location points to the
+/// start of the token at the end. However, for external clients it is more
+/// useful to have a CXSourceRange be a proper half-open interval. This routine
+/// does the appropriate translation.
+CXSourceRange translateSourceRange(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceRange R);
+
+/// \brief Translate a Clang source range into a CIndex source range.
+static inline CXSourceRange translateSourceRange(ASTContext &Context,
+ SourceRange R) {
+ return translateSourceRange(Context.getSourceManager(),
+ Context.getLangOptions(),
+ R);
+}
+
+static inline SourceLocation translateSourceLocation(CXSourceLocation L) {
+ return SourceLocation::getFromRawEncoding(L.int_data);
+}
+
+static inline SourceRange translateCXSourceRange(CXSourceRange R) {
+ return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data),
+ SourceLocation::getFromRawEncoding(R.end_int_data));
+}
+
+
+}} // end namespace: clang::cxloc
+
+#endif
diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile
index 7bdbba172f2c..3e288623e5eb 100644
--- a/tools/CIndex/Makefile
+++ b/tools/CIndex/Makefile
@@ -11,7 +11,6 @@ LEVEL = ../../../..
LIBRARYNAME = CIndex
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
# Include this here so we can get the configuration of the targets
# that have been configured for construction. We have to do this
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 06e24053aa0a..e9ba174275a4 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -10,7 +10,6 @@ LEVEL = ../../../..
TOOLNAME = c-index-test
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
NO_INSTALL = 1
# No plugins, optimize startup time.
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 4ef390413972..d4771c77f503 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -28,10 +28,20 @@ char *basename(const char* path)
extern char *basename(const char *);
#endif
+static void PrintDiagnosticCallback(CXDiagnostic Diagnostic,
+ CXClientData ClientData);
+
+
+static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
+ unsigned end_line, unsigned end_column) {
+ fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
+ end_line, end_column);
+}
+
static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
CXTranslationUnit *TU) {
- *TU = clang_createTranslationUnit(Idx, file);
+ *TU = clang_createTranslationUnit(Idx, file, PrintDiagnosticCallback, stderr);
if (!TU) {
fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
return 0;
@@ -151,7 +161,7 @@ static void PrintCursor(CXCursor Cursor) {
Referenced = clang_getCursorReferenced(Cursor);
if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
CXSourceLocation Loc = clang_getCursorLocation(Referenced);
- clang_getInstantiationLocation(Loc, 0, &line, &column);
+ clang_getInstantiationLocation(Loc, 0, &line, &column, 0);
printf(":%d:%d", line, column);
}
@@ -164,7 +174,7 @@ static const char* GetCursorSource(CXCursor Cursor) {
CXSourceLocation Loc = clang_getCursorLocation(Cursor);
const char *source;
CXFile file;
- clang_getInstantiationLocation(Loc, &file, 0, 0);
+ clang_getInstantiationLocation(Loc, &file, 0, 0, 0);
source = clang_getFileName(file);
if (!source)
return "<invalid loc>";
@@ -172,6 +182,131 @@ static const char* GetCursorSource(CXCursor Cursor) {
}
/******************************************************************************/
+/* Callbacks. */
+/******************************************************************************/
+
+typedef void (*PostVisitTU)(CXTranslationUnit);
+
+static void PrintDiagnosticCallback(CXDiagnostic Diagnostic,
+ CXClientData ClientData) {
+ FILE *out = (FILE *)ClientData;
+ CXFile file;
+ unsigned line, column;
+ CXString text;
+ enum CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(Diagnostic);
+
+ /* Ignore diagnostics that should be ignored. */
+ if (severity == CXDiagnostic_Ignored)
+ return;
+
+ /* Print file:line:column. */
+ clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
+ &file, &line, &column, 0);
+ if (file) {
+ unsigned i, n;
+ unsigned printed_any_ranges = 0;
+
+ fprintf(out, "%s:%d:%d:", clang_getFileName(file), line, column);
+
+ n = clang_getDiagnosticNumRanges(Diagnostic);
+ for (i = 0; i != n; ++i) {
+ CXFile start_file, end_file;
+ CXSourceRange range = clang_getDiagnosticRange(Diagnostic, i);
+
+ unsigned start_line, start_column, end_line, end_column;
+ clang_getInstantiationLocation(clang_getRangeStart(range),
+ &start_file, &start_line, &start_column,0);
+ clang_getInstantiationLocation(clang_getRangeEnd(range),
+ &end_file, &end_line, &end_column, 0);
+
+ if (start_file != end_file || start_file != file)
+ continue;
+
+ PrintExtent(out, start_line, start_column, end_line, end_column);
+ printed_any_ranges = 1;
+ }
+ if (printed_any_ranges)
+ fprintf(out, ":");
+
+ fprintf(out, " ");
+ }
+
+ /* Print warning/error/etc. */
+ switch (severity) {
+ case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
+ case CXDiagnostic_Note: fprintf(out, "note: "); break;
+ case CXDiagnostic_Warning: fprintf(out, "warning: "); break;
+ case CXDiagnostic_Error: fprintf(out, "error: "); break;
+ case CXDiagnostic_Fatal: fprintf(out, "fatal error: "); break;
+ }
+
+ text = clang_getDiagnosticSpelling(Diagnostic);
+ if (clang_getCString(text))
+ fprintf(out, "%s\n", clang_getCString(text));
+ else
+ fprintf(out, "<no diagnostic text>\n");
+ clang_disposeString(text);
+
+ if (file) {
+ unsigned i, num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
+ for (i = 0; i != num_fixits; ++i) {
+ switch (clang_getDiagnosticFixItKind(Diagnostic, i)) {
+ case CXFixIt_Insertion: {
+ CXSourceLocation insertion_loc;
+ CXFile insertion_file;
+ unsigned insertion_line, insertion_column;
+ text = clang_getDiagnosticFixItInsertion(Diagnostic, i, &insertion_loc);
+ clang_getInstantiationLocation(insertion_loc, &insertion_file,
+ &insertion_line, &insertion_column, 0);
+ if (insertion_file == file)
+ fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
+ clang_getCString(text), insertion_line, insertion_column);
+ clang_disposeString(text);
+ break;
+ }
+
+ case CXFixIt_Removal: {
+ CXFile start_file, end_file;
+ unsigned start_line, start_column, end_line, end_column;
+ CXSourceRange remove_range
+ = clang_getDiagnosticFixItRemoval(Diagnostic, i);
+ clang_getInstantiationLocation(clang_getRangeStart(remove_range),
+ &start_file, &start_line, &start_column,
+ 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(remove_range),
+ &end_file, &end_line, &end_column, 0);
+ if (start_file == file && end_file == file) {
+ fprintf(out, "FIX-IT: Remove ");
+ PrintExtent(out, start_line, start_column, end_line, end_column);
+ fprintf(out, "\n");
+ }
+ break;
+ }
+
+ case CXFixIt_Replacement: {
+ CXFile start_file, end_file;
+ unsigned start_line, start_column, end_line, end_column;
+ CXSourceRange remove_range;
+ text = clang_getDiagnosticFixItReplacement(Diagnostic, i,&remove_range);
+ clang_getInstantiationLocation(clang_getRangeStart(remove_range),
+ &start_file, &start_line, &start_column,
+ 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(remove_range),
+ &end_file, &end_line, &end_column, 0);
+ if (start_file == end_file) {
+ fprintf(out, "FIX-IT: Replace ");
+ PrintExtent(out, start_line, start_column, end_line, end_column);
+ fprintf(out, " with \"%s\"\n", clang_getCString(text));
+ }
+ clang_disposeString(text);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/******************************************************************************/
/* Logic for testing traversal. */
/******************************************************************************/
@@ -183,14 +318,14 @@ static void PrintCursorExtent(CXCursor C) {
unsigned begin_line, begin_column, end_line, end_column;
clang_getInstantiationLocation(clang_getRangeStart(extent),
- &begin_file, &begin_line, &begin_column);
+ &begin_file, &begin_line, &begin_column, 0);
clang_getInstantiationLocation(clang_getRangeEnd(extent),
- &end_file, &end_line, &end_column);
+ &end_file, &end_line, &end_column, 0);
if (!begin_file || !end_file)
return;
- printf(" [Extent=%d:%d:%d:%d]", begin_line, begin_column,
- end_line, end_column);
+ printf(" Extent=");
+ PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
}
/* Data used by all of the visitors. */
@@ -207,7 +342,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
CXSourceLocation Loc = clang_getCursorLocation(Cursor);
unsigned line, column;
- clang_getInstantiationLocation(Loc, 0, &line, &column);
+ clang_getInstantiationLocation(Loc, 0, &line, &column, 0);
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
GetCursorSource(Cursor), line, column);
PrintCursor(Cursor);
@@ -251,7 +386,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
curColumn++;
Loc = clang_getCursorLocation(Cursor);
- clang_getInstantiationLocation(Loc, &file, 0, 0);
+ clang_getInstantiationLocation(Loc, &file, 0, 0, 0);
source = clang_getFileName(file);
if (source) {
CXSourceLocation RefLoc
@@ -297,56 +432,93 @@ enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
}
/******************************************************************************/
+/* Inclusion stack testing. */
+/******************************************************************************/
+
+void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
+ unsigned includeStackLen, CXClientData data) {
+
+ unsigned i;
+ printf("file: %s\nincluded by:\n", clang_getFileName(includedFile));
+ for (i = 0; i < includeStackLen; ++i) {
+ CXFile includingFile;
+ unsigned line, column;
+ clang_getInstantiationLocation(includeStack[i], &includingFile, &line,
+ &column, 0);
+ printf(" %s:%d:%d\n", clang_getFileName(includingFile), line, column);
+ }
+ printf("\n");
+}
+
+void PrintInclusionStack(CXTranslationUnit TU) {
+ clang_getInclusions(TU, InclusionVisitor, NULL);
+}
+
+/******************************************************************************/
/* Loading ASTs/source. */
/******************************************************************************/
static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
const char *filter, const char *prefix,
- CXCursorVisitor Visitor) {
- enum CXCursorKind K = CXCursor_NotImplemented;
- enum CXCursorKind *ck = &K;
- VisitorData Data;
+ CXCursorVisitor Visitor,
+ PostVisitTU PV) {
if (prefix)
FileCheckPrefix = prefix;
+
+ if (Visitor) {
+ enum CXCursorKind K = CXCursor_NotImplemented;
+ enum CXCursorKind *ck = &K;
+ VisitorData Data;
- /* Perform some simple filtering. */
- if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
- else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
- else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
- else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
- else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
- else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
- else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
- else {
- fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
- return 1;
+ /* Perform some simple filtering. */
+ if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
+ else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
+ else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
+ else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
+ else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
+ else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
+ else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
+ else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
+ else {
+ fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
+ return 1;
+ }
+
+ Data.TU = TU;
+ Data.Filter = ck;
+ clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
}
- Data.TU = TU;
- Data.Filter = ck;
- clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
+ if (PV)
+ PV(TU);
+
clang_disposeTranslationUnit(TU);
return 0;
}
int perform_test_load_tu(const char *file, const char *filter,
- const char *prefix,
- CXCursorVisitor Visitor) {
+ const char *prefix, CXCursorVisitor Visitor,
+ PostVisitTU PV) {
CXIndex Idx;
CXTranslationUnit TU;
+ int result;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
- !strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnostics */ 1);
+ !strcmp(filter, "local") ? 1 : 0);
- if (!CreateTranslationUnit(Idx, file, &TU))
+ if (!CreateTranslationUnit(Idx, file, &TU)) {
+ clang_disposeIndex(Idx);
return 1;
+ }
- return perform_test_load(Idx, TU, filter, prefix, Visitor);
+ result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV);
+ clang_disposeIndex(Idx);
+ return result;
}
-int perform_test_load_source(int argc, const char **argv, const char *filter,
- CXCursorVisitor Visitor) {
+int perform_test_load_source(int argc, const char **argv,
+ const char *filter, CXCursorVisitor Visitor,
+ PostVisitTU PV) {
const char *UseExternalASTs =
getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
CXIndex Idx;
@@ -356,27 +528,32 @@ int perform_test_load_source(int argc, const char **argv, const char *filter,
int result;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
- !strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnostics */ 1);
+ !strcmp(filter, "local") ? 1 : 0);
if (UseExternalASTs && strlen(UseExternalASTs))
clang_setUseExternalASTGeneration(Idx, 1);
- if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files))
+ if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
+ clang_disposeIndex(Idx);
return -1;
+ }
TU = clang_createTranslationUnitFromSourceFile(Idx, 0,
argc - num_unsaved_files,
argv + num_unsaved_files,
num_unsaved_files,
- unsaved_files);
+ unsaved_files,
+ PrintDiagnosticCallback,
+ stderr);
if (!TU) {
fprintf(stderr, "Unable to load translation unit!\n");
+ clang_disposeIndex(Idx);
return 1;
}
- result = perform_test_load(Idx, TU, filter, NULL, Visitor);
+ result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
free_remapped_files(unsaved_files, num_unsaved_files);
+ clang_disposeIndex(Idx);
return result;
}
@@ -391,8 +568,8 @@ static void print_cursor_file_scan(CXCursor cursor,
printf("// %s: ", FileCheckPrefix);
if (prefix)
printf("-%s", prefix);
- printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
- start_line, start_col, end_line, end_col);
+ PrintExtent(stdout, start_line, start_col, end_line, end_col);
+ printf(" ");
PrintCursor(cursor);
printf("\n");
}
@@ -402,15 +579,12 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
CXIndex Idx;
CXTranslationUnit TU;
FILE *fp;
- unsigned line;
- CXCursor prevCursor;
+ CXCursor prevCursor = clang_getNullCursor();
CXFile file;
- unsigned printed;
- unsigned start_line, start_col, last_line, last_col;
- size_t i;
+ unsigned line = 1, col = 1;
+ unsigned start_line = 1, start_col = 1;
- if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnostics */ 1))) {
+ if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
@@ -423,52 +597,34 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
return 1;
}
- line = 0;
- prevCursor = clang_getNullCursor();
- printed = 0;
- start_line = last_line = 1;
- start_col = last_col = 1;
-
file = clang_getFile(TU, source_file);
- while (!feof(fp)) {
- size_t len = 0;
- int c;
+ for (;;) {
+ CXCursor cursor;
+ int c = fgetc(fp);
- while ((c = fgetc(fp)) != EOF) {
- len++;
- if (c == '\n')
- break;
+ if (c == '\n') {
+ ++line;
+ col = 1;
+ } else
+ ++col;
+
+ /* Check the cursor at this position, and dump the previous one if we have
+ * found something new.
+ */
+ cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
+ if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
+ prevCursor.kind != CXCursor_InvalidFile) {
+ print_cursor_file_scan(prevCursor, start_line, start_col,
+ line, col, prefix);
+ start_line = line;
+ start_col = col;
}
+ if (c == EOF)
+ break;
- ++line;
-
- for (i = 0; i < len ; ++i) {
- CXCursor cursor;
- cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, i+1));
-
- if (!clang_equalCursors(cursor, prevCursor) &&
- prevCursor.kind != CXCursor_InvalidFile) {
- print_cursor_file_scan(prevCursor, start_line, start_col,
- last_line, last_col, prefix);
- printed = 1;
- start_line = line;
- start_col = (unsigned) i+1;
- }
- else {
- printed = 0;
- }
-
- prevCursor = cursor;
- last_line = line;
- last_col = (unsigned) i+1;
- }
+ prevCursor = cursor;
}
- if (!printed && prevCursor.kind != CXCursor_InvalidFile) {
- print_cursor_file_scan(prevCursor, start_line, start_col,
- last_line, last_col, prefix);
- }
-
fclose(fp);
return 0;
}
@@ -481,42 +637,62 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
on failure. If successful, the pointer *filename will contain newly-allocated
memory (that will be owned by the caller) to store the file name. */
int parse_file_line_column(const char *input, char **filename, unsigned *line,
- unsigned *column) {
+ unsigned *column, unsigned *second_line,
+ unsigned *second_column) {
/* Find the second colon. */
- const char *second_colon = strrchr(input, ':'), *first_colon;
+ const char *last_colon = strrchr(input, ':');
+ unsigned values[4], i;
+ unsigned num_values = (second_line && second_column)? 4 : 2;
+
char *endptr = 0;
- if (!second_colon || second_colon == input) {
- fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
+ if (!last_colon || last_colon == input) {
+ if (num_values == 4)
+ fprintf(stderr, "could not parse filename:line:column:line:column in "
+ "'%s'\n", input);
+ else
+ fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
return 1;
}
- /* Parse the column number. */
- *column = strtol(second_colon + 1, &endptr, 10);
- if (*endptr != 0) {
- fprintf(stderr, "could not parse column in '%s'\n", input);
- return 1;
- }
+ for (i = 0; i != num_values; ++i) {
+ const char *prev_colon;
- /* Find the first colon. */
- first_colon = second_colon - 1;
- while (first_colon != input && *first_colon != ':')
- --first_colon;
- if (first_colon == input) {
- fprintf(stderr, "could not parse line in '%s'\n", input);
- return 1;
- }
+ /* Parse the next line or column. */
+ values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
+ if (*endptr != 0 && *endptr != ':') {
+ fprintf(stderr, "could not parse %s in '%s'\n",
+ (i % 2 ? "column" : "line"), input);
+ return 1;
+ }
+
+ if (i + 1 == num_values)
+ break;
- /* Parse the line number. */
- *line = strtol(first_colon + 1, &endptr, 10);
- if (*endptr != ':') {
- fprintf(stderr, "could not parse line in '%s'\n", input);
- return 1;
+ /* Find the previous colon. */
+ prev_colon = last_colon - 1;
+ while (prev_colon != input && *prev_colon != ':')
+ --prev_colon;
+ if (prev_colon == input) {
+ fprintf(stderr, "could not parse %s in '%s'\n",
+ (i % 2 == 0? "column" : "line"), input);
+ return 1;
+ }
+
+ last_colon = prev_colon;
}
+
+ *line = values[0];
+ *column = values[1];
+ if (second_line && second_column) {
+ *second_line = values[2];
+ *second_column = values[3];
+ }
+
/* Copy the file name. */
- *filename = (char*)malloc(first_colon - input + 1);
- memcpy(*filename, input, first_colon - input);
- (*filename)[first_colon - input] = 0;
+ *filename = (char*)malloc(last_colon - input + 1);
+ memcpy(*filename, input, last_colon - input);
+ (*filename)[last_colon - input] = 0;
return 0;
}
@@ -595,18 +771,21 @@ int perform_code_completion(int argc, const char **argv) {
CXCodeCompleteResults *results = 0;
input += strlen("-code-completion-at=");
- if ((errorCode = parse_file_line_column(input, &filename, &line, &column)))
+ if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
+ 0, 0)))
return errorCode;
if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
return -1;
- CIdx = clang_createIndex(0, 0);
+ CIdx = clang_createIndex(0);
results = clang_codeComplete(CIdx,
argv[argc - 1], argc - num_unsaved_files - 3,
argv + num_unsaved_files + 2,
num_unsaved_files, unsaved_files,
- filename, line, column);
+ filename, line, column,
+ PrintDiagnosticCallback, stderr);
+
if (results) {
unsigned i, n = results->NumResults;
for (i = 0; i != n; ++i)
@@ -650,7 +829,7 @@ int inspect_cursor_at(int argc, const char **argv) {
const char *input = argv[Loc + 1] + strlen("-cursor-at=");
if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
&Locations[Loc].line,
- &Locations[Loc].column)))
+ &Locations[Loc].column, 0, 0)))
return errorCode;
}
@@ -658,12 +837,14 @@ int inspect_cursor_at(int argc, const char **argv) {
&num_unsaved_files))
return -1;
- CIdx = clang_createIndex(0, 1);
+ CIdx = clang_createIndex(0);
TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
argc - num_unsaved_files - 2 - NumLocations,
argv + num_unsaved_files + 1 + NumLocations,
num_unsaved_files,
- unsaved_files);
+ unsaved_files,
+ PrintDiagnosticCallback,
+ stderr);
if (!TU) {
fprintf(stderr, "unable to parse input\n");
return -1;
@@ -689,6 +870,111 @@ int inspect_cursor_at(int argc, const char **argv) {
return 0;
}
+int perform_token_annotation(int argc, const char **argv) {
+ const char *input = argv[1];
+ char *filename = 0;
+ unsigned line, second_line;
+ unsigned column, second_column;
+ CXIndex CIdx;
+ CXTranslationUnit TU = 0;
+ int errorCode;
+ struct CXUnsavedFile *unsaved_files = 0;
+ int num_unsaved_files = 0;
+ CXToken *tokens;
+ unsigned num_tokens;
+ CXSourceRange range;
+ CXSourceLocation startLoc, endLoc;
+ CXFile file = 0;
+ CXCursor *cursors = 0;
+ unsigned i;
+
+ input += strlen("-test-annotate-tokens=");
+ if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
+ &second_line, &second_column)))
+ return errorCode;
+
+ if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
+ return -1;
+
+ CIdx = clang_createIndex(0);
+ TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
+ argc - num_unsaved_files - 3,
+ argv + num_unsaved_files + 2,
+ num_unsaved_files,
+ unsaved_files,
+ PrintDiagnosticCallback,
+ stderr);
+ if (!TU) {
+ fprintf(stderr, "unable to parse input\n");
+ clang_disposeIndex(CIdx);
+ free(filename);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return -1;
+ }
+ errorCode = 0;
+
+ file = clang_getFile(TU, filename);
+ if (!file) {
+ fprintf(stderr, "file %s is not in this translation unit\n", filename);
+ errorCode = -1;
+ goto teardown;
+ }
+
+ startLoc = clang_getLocation(TU, file, line, column);
+ if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
+ fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
+ column);
+ errorCode = -1;
+ goto teardown;
+ }
+
+ endLoc = clang_getLocation(TU, file, second_line, second_column);
+ if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
+ fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
+ second_line, second_column);
+ errorCode = -1;
+ goto teardown;
+ }
+
+ range = clang_getRange(startLoc, endLoc);
+ clang_tokenize(TU, range, &tokens, &num_tokens);
+ cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
+ clang_annotateTokens(TU, tokens, num_tokens, cursors);
+ for (i = 0; i != num_tokens; ++i) {
+ const char *kind = "<unknown>";
+ CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
+ CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
+ unsigned start_line, start_column, end_line, end_column;
+
+ switch (clang_getTokenKind(tokens[i])) {
+ case CXToken_Punctuation: kind = "Punctuation"; break;
+ case CXToken_Keyword: kind = "Keyword"; break;
+ case CXToken_Identifier: kind = "Identifier"; break;
+ case CXToken_Literal: kind = "Literal"; break;
+ case CXToken_Comment: kind = "Comment"; break;
+ }
+ clang_getInstantiationLocation(clang_getRangeStart(extent),
+ 0, &start_line, &start_column, 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(extent),
+ 0, &end_line, &end_column, 0);
+ printf("%s: \"%s\" ", kind, clang_getCString(spelling));
+ PrintExtent(stdout, start_line, start_column, end_line, end_column);
+ if (!clang_isInvalid(cursors[i].kind)) {
+ printf(" ");
+ PrintCursor(cursors[i]);
+ }
+ printf("\n");
+ }
+ free(cursors);
+
+ teardown:
+ clang_disposeTranslationUnit(TU);
+ clang_disposeIndex(CIdx);
+ free(filename);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return errorCode;
+}
+
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
@@ -712,8 +998,11 @@ static void print_usage(void) {
" c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
"[FileCheck prefix]\n"
" c-index-test -test-load-source <symbol filter> {<args>}*\n"
- " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n");
+ " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n");
fprintf(stderr,
+ " 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\n"
" <symbol filter> values:\n%s",
" all - load all symbols, including those from PCH\n"
" local - load all symbols except those in PCH\n"
@@ -733,17 +1022,26 @@ int main(int argc, const char **argv) {
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 13);
if (I)
- return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I);
+ return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
+ NULL);
}
else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 17);
if (I)
- return perform_test_load_source(argc - 3, argv + 3, argv[2], I);
+ return perform_test_load_source(argc - 3, argv + 3, argv[2], I, NULL);
}
else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
return perform_file_scan(argv[2], argv[3],
argc >= 5 ? argv[4] : 0);
-
+ else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
+ return perform_token_annotation(argc, argv);
+ else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
+ PrintInclusionStack);
+ else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
+ return perform_test_load_tu(argv[2], "all", NULL, NULL,
+ PrintInclusionStack);
+
print_usage();
return 1;
}
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 90fb09c0d9a8..c4320b0c905c 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,12 +1,13 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
- clangDriver
clangFrontend
+ clangDriver
clangCodeGen
+ clangSema
+ clangChecker
clangAnalysis
clangRewrite
- clangSema
clangAST
clangParse
clangLex
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 6ec82918c075..e5a9280a0cbe 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -13,7 +13,6 @@ ifndef CLANG_IS_PRODUCTION
TOOLALIAS = clang++
endif
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
# Clang tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
@@ -24,9 +23,9 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag
-USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangAnalysis.a \
- clangRewrite.a clangSema.a clangAST.a clangParse.a \
- clangLex.a clangBasic.a
+USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \
+ clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \
+ clangParse.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index d2f1017c2151..05fb6984d416 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -51,7 +51,7 @@ void LLVMErrorHandler(void *UserData, const std::string &Message) {
exit(1);
}
-static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
switch (CI.getFrontendOpts().ProgramAction) {
@@ -70,6 +70,7 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
case EmitHTML: return new HTMLPrintAction();
case EmitLLVM: return new EmitLLVMAction();
case EmitLLVMOnly: return new EmitLLVMOnlyAction();
+ case EmitObj: return new EmitObjAction();
case FixIt: return new FixItAction();
case GeneratePCH: return new GeneratePCHAction();
case GeneratePTH: return new GeneratePTHAction();
@@ -111,6 +112,21 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
}
}
+static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+ // Create the underlying action.
+ FrontendAction *Act = CreateFrontendBaseAction(CI);
+ if (!Act)
+ return 0;
+
+ // If there are any AST files to merge, create a frontend action
+ // adaptor to perform the merge.
+ if (!CI.getFrontendOpts().ASTMergeFiles.empty())
+ Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0],
+ CI.getFrontendOpts().ASTMergeFiles.size());
+
+ return Act;
+}
+
// FIXME: Define the need for this testing away.
static int cc1_test(Diagnostic &Diags,
const char **ArgBegin, const char **ArgEnd) {
@@ -179,7 +195,9 @@ static int cc1_test(Diagnostic &Diags,
int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
- CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ CompilerInstance Clang;
+
+ Clang.setLLVMContext(new llvm::LLVMContext);
// Run clang -cc1 test.
if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") {
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index f19dcb4718cb..8c64d3ffefda 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -403,7 +403,7 @@ if ($Status) { exit($Status >> 8); }
# Get the analysis options.
my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
-if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
+if (!defined($Analyses)) { $Analyses = '-analyzer-check-objc-mem'; }
# Get the store model.
my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
@@ -597,9 +597,12 @@ if ($Action eq 'compile' or $Action eq 'link') {
}
}
+ # FileLang still not defined? Skip the file.
next if (!defined $FileLang);
+
+ # Language not accepted?
next if (!defined $LangsAccepted{$FileLang});
-
+
my @CmdArgs;
my @AnalyzeArgs;
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index f978a888be83..432456b15fe7 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -82,52 +82,45 @@ sub DieDiag {
# Find 'clang'
my $ClangSB = Cwd::realpath("$RealBin/bin/clang");
-my $ClangCXXSB;
if (!defined $ClangSB || ! -x $ClangSB) {
$ClangSB = Cwd::realpath("$RealBin/clang");
- if (defined $ClangSB) { $ClangCXXSB = $ClangSB . "++"; }
}
-my $Clang = $ClangSB;
-my $ClangCXX = $ClangCXXSB;
-# Default to looking for 'clang' in the path.
-if (!defined $Clang || ! -x $Clang) {
- $Clang = "clang";
- $ClangCXX = "clang++";
+my $Clang;
+if (!defined $ClangSB || ! -x $ClangSB) {
+ # Default to looking for 'clang' in the path.
+ $Clang = `which clang`;
+ chomp $Clang;
+ if ($Clang eq "") {
+ DieDiag("No 'clang' executable found in path.");
+ }
+}
+else {
+ $Clang = $ClangSB;
}
+my $ClangCXX = $Clang . "++";
my %AvailableAnalyses;
# Query clang for analysis options.
-open(PIPE, "-|", $Clang, "-cc1", "--help") or
+open(PIPE, "-|", $Clang, "-cc1", "-help") or
DieDiag("Cannot execute '$Clang'\n");
-my $FoundAnalysis = 0;
-
while(<PIPE>) {
- if ($FoundAnalysis == 0) {
- if (/Checks and Analyses/) {
- $FoundAnalysis = 1;
- }
- next;
- }
- if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
- next if ($1 =~ /-dump/ or $1 =~ /-view/
- or $1 =~ /-warn-uninit/);
- $AvailableAnalyses{$1} = $2;
+ if (/(-analyzer-check-[^\s]+)/) {
+ $AvailableAnalyses{$1} = 1;
next;
}
- last;
}
close (PIPE);
my %AnalysesDefaultEnabled = (
- '-warn-dead-stores' => 1,
- '-checker-cfref' => 1,
- '-warn-objc-methodsigs' => 1,
+ '-analyzer-check-dead-stores' => 1,
+ '-analyzer-check-objc-mem' => 1,
+ '-analyzer-check-objc-methodsigs' => 1,
# Do not enable the missing -dealloc check by default.
- # '-warn-objc-missing-dealloc' => 1,
- '-warn-objc-unused-ivars' => 1,
- '-warn-security-syntactic' => 1
+ # '-analyzer-check-objc-missing-dealloc' => 1,
+ '-analyzer-check-objc-unused-ivars' => 1,
+ '-analyzer-check-security-syntactic' => 1
);
##----------------------------------------------------------------------------##
@@ -853,10 +846,6 @@ sub RunBuildCommand {
# When 'CC' is set, xcodebuild uses it to do all linking, even if we are
# linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
# when linking such files.
- if (!defined $ENV{'CCC_CXX'}) {
- $ENV{'CCC_CXX'} = 'g++';
- }
- $ENV{'LDPLUSPLUS'} = $ENV{'CCC_CXX'};
}
return (system(@$Args) >> 8);
@@ -951,7 +940,7 @@ ENDTEXT
print " ";
}
- print " $Analysis $AvailableAnalyses{$Analysis}\n";
+ print " $Analysis\n";
}
print <<ENDTEXT
@@ -1203,7 +1192,7 @@ if (!defined $CmdCXX || ! -x $CmdCXX) {
if (!defined $ClangSB || ! -x $ClangSB) {
Diag("'clang' executable not found in '$RealBin/bin'.\n");
- Diag("Using 'clang' from path.\n");
+ Diag("Using 'clang' from path: $Clang\n");
}
$ENV{'CC'} = $Cmd;
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
new file mode 100755
index 000000000000..cc068a56adf9
--- /dev/null
+++ b/tools/scan-build/set-xcode-analyzer
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import re
+import tempfile
+import shutil
+import stat
+from AppKit import *
+
+def FindClangSpecs(path):
+ for root, dirs, files in os.walk(path):
+ for f in files:
+ if f.endswith(".xcspec") and f.startswith("Clang LLVM"):
+ yield os.path.join(root, f)
+
+def ModifySpec(path, pathToChecker):
+ t = tempfile.NamedTemporaryFile(delete=False)
+ foundAnalyzer = False
+ with open(path) as f:
+ for line in f:
+ if not foundAnalyzer:
+ if line.find("Static Analyzer") >= 0:
+ foundAnalyzer = True
+ else:
+ m = re.search('^(\s*ExecPath\s*=\s*")', line)
+ if m:
+ line = "".join([m.group(0), pathToChecker, '";\n'])
+ t.write(line)
+ t.close()
+ print "(+) processing:", path
+ try:
+ shutil.copy(t.name, path)
+ os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
+ except IOError, why:
+ print " (-) Cannot update file:", why, "\n"
+ except OSError, why:
+ print " (-) Cannot update file:", why, "\n"
+ os.unlink(t.name)
+
+def main():
+ from optparse import OptionParser
+ parser = OptionParser('usage: %prog [options]')
+ parser.set_description(__doc__)
+ parser.add_option("--use-checker-build", dest="path",
+ help="Use the Clang located at the provided absolute path, e.g. /Users/foo/checker-1")
+ parser.add_option("--use-xcode-clang", action="store_const",
+ const="$(CLANG)", dest="default",
+ help="Use the Clang bundled with Xcode")
+ (options, args) = parser.parse_args()
+ if options.path is None and options.default is None:
+ parser.error("You must specify a version of Clang to use for static analysis. Specify '-h' for details")
+
+ # determine if Xcode is running
+ for x in NSWorkspace.sharedWorkspace().runningApplications():
+ if x.localizedName().find("Xcode") >= 0:
+ print "(-) You must quit Xcode first before modifying its configuration files."
+ return
+
+ if options.path:
+ # Expand tildes.
+ path = os.path.expanduser(options.path)
+ if not path.endswith("clang"):
+ print "(+) Using Clang bundled with checker build:", path
+ path = os.path.join(path, "bin", "clang");
+ else:
+ print "(+) Using Clang located at:", path
+ else:
+ print "(+) Using the Clang bundled with Xcode"
+ path = options.default
+
+ for x in FindClangSpecs('/Developer'):
+ ModifySpec(x, path)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/utils/ABITest/ABITestGen.py b/utils/ABITest/ABITestGen.py
index 63da02bcda9d..c45a0c343270 100755
--- a/utils/ABITest/ABITestGen.py
+++ b/utils/ABITest/ABITestGen.py
@@ -42,7 +42,8 @@ class TypePrinter:
print >>f, '#include "%s"\n'%(headerName,)
if self.outputDriver:
- print >>self.outputDriver, '#include <stdio.h>\n'
+ print >>self.outputDriver, '#include <stdio.h>'
+ print >>self.outputDriver, '#include <stdlib.h>\n'
print >>self.outputDriver, 'int main(int argc, char **argv) {'
print >>self.outputDriver, ' int index = -1;'
print >>self.outputDriver, ' if (argc > 1) index = atoi(argv[1]);'
@@ -206,6 +207,9 @@ class TypePrinter:
yield '(%s) 0'%(t.name,)
yield '(%s) -1'%(t.name,)
yield '(%s) 1'%(t.name,)
+ elif isinstance(t, EnumType):
+ for i in range(0, len(t.enumerators)):
+ yield 'enum%dval%d' % (t.index, i)
elif isinstance(t, RecordType):
nonPadding = [f for f in t.fields
if not f.isPaddingBitField()]
@@ -272,6 +276,8 @@ class TypePrinter:
else:
code = 'p'
print >>output, '%*sprintf("%s: %s = %%%s\\n", %s);'%(indent, '', prefix, name, code, name)
+ elif isinstance(t, EnumType):
+ print >>output, '%*sprintf("%s: %s = %%d\\n", %s);'%(indent, '', prefix, name, name)
elif isinstance(t, RecordType):
if not t.fields:
print >>output, '%*sprintf("%s: %s (empty)\\n");'%(indent, '', prefix, name)
@@ -300,6 +306,8 @@ class TypePrinter:
output = self.output
if isinstance(t, BuiltinType):
print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS)
+ elif isinstance(t, EnumType):
+ print >>output, '%*sassert(%s == %s);' % (indent, '', nameLHS, nameRHS)
elif isinstance(t, RecordType):
for i,f in enumerate(t.fields):
if f.isPaddingBitField():
@@ -402,6 +410,11 @@ def main():
help="do not generate void* types",
action="store_false", default=True)
+ # Enumerations
+ group.add_option("", "--no-enums", dest="useEnum",
+ help="do not generate enum types",
+ action="store_false", default=True)
+
# Derived types
group.add_option("", "--no-array", dest="useArray",
help="do not generate record types",
@@ -529,6 +542,8 @@ def main():
vTypes.append(ArrayType(i, True, type, count * type.size))
atg.addGenerator(FixedTypeGenerator(vTypes))
+ if opts.useEnum:
+ atg.addGenerator(EnumTypeGenerator([None, '-1', '1', '1u'], 1, 4))
if opts.recordMaxDepth is None:
# Fully recursive, just avoid top-level arrays.
diff --git a/utils/ABITest/TypeGen.py b/utils/ABITest/TypeGen.py
index d5678db6a0e8..40ea791eb515 100644
--- a/utils/ABITest/TypeGen.py
+++ b/utils/ABITest/TypeGen.py
@@ -46,6 +46,28 @@ class BuiltinType(Type):
def __str__(self):
return self.name
+class EnumType(Type):
+ def __init__(self, index, enumerators):
+ self.index = index
+ self.enumerators = enumerators
+
+ def getEnumerators(self):
+ result = ''
+ for i, init in enumerate(self.enumerators):
+ if i > 0:
+ result = result + ', '
+ result = result + 'enum%dval%d' % (self.index, i)
+ if init:
+ result = result + ' = %s' % (init)
+
+ return result
+
+ def __str__(self):
+ return 'enum { %s }' % (self.getEnumerators())
+
+ def getTypedefDef(self, name, printer):
+ return 'typedef enum %s { %s } %s;'%(name, self.getEnumerators(), name)
+
class RecordType(Type):
def __init__(self, index, isUnion, fields):
self.index = index
@@ -188,6 +210,63 @@ class FixedTypeGenerator(TypeGenerator):
def generateType(self, N):
return self.types[N]
+# Factorial
+def fact(n):
+ result = 1
+ while n > 0:
+ result = result * n
+ n = n - 1
+ return result
+
+# Compute the number of combinations (n choose k)
+def num_combinations(n, k):
+ return fact(n) / (fact(k) * fact(n - k))
+
+# Enumerate the combinations choosing k elements from the list of values
+def combinations(values, k):
+ # From ActiveState Recipe 190465: Generator for permutations,
+ # combinations, selections of a sequence
+ if k==0: yield []
+ else:
+ for i in xrange(len(values)-k+1):
+ for cc in combinations(values[i+1:],k-1):
+ yield [values[i]]+cc
+
+class EnumTypeGenerator(TypeGenerator):
+ def __init__(self, values, minEnumerators, maxEnumerators):
+ TypeGenerator.__init__(self)
+ self.values = values
+ self.minEnumerators = minEnumerators
+ self.maxEnumerators = maxEnumerators
+ self.setCardinality()
+
+ def setCardinality(self):
+ self.cardinality = 0
+ for num in range(self.minEnumerators, self.maxEnumerators + 1):
+ self.cardinality += num_combinations(len(self.values), num)
+
+ def generateType(self, n):
+ # Figure out the number of enumerators in this type
+ numEnumerators = self.minEnumerators
+ valuesCovered = 0
+ while numEnumerators < self.maxEnumerators:
+ comb = num_combinations(len(self.values), numEnumerators)
+ if valuesCovered + comb > n:
+ break
+ numEnumerators = numEnumerators + 1
+ valuesCovered += comb
+
+ # Find the requested combination of enumerators and build a
+ # type from it.
+ i = 0
+ for enumerators in combinations(self.values, numEnumerators):
+ if i == n - valuesCovered:
+ return EnumType(n, enumerators)
+
+ i = i + 1
+
+ assert False
+
class ComplexTypeGenerator(TypeGenerator):
def __init__(self, typeGen):
TypeGenerator.__init__(self)
@@ -363,10 +442,12 @@ def test():
btg = FixedTypeGenerator([BuiltinType('char', 4),
BuiltinType('int', 4)])
-
+ etg = EnumTypeGenerator([None, '-1', '1', '1u'], 0, 3)
+
atg = AnyTypeGenerator()
atg.addGenerator( btg )
atg.addGenerator( RecordTypeGenerator(fields0, False, 4) )
+ atg.addGenerator( etg )
print 'Cardinality:',atg.cardinality
for i in range(100):
if i == atg.cardinality:
diff --git a/www/analyzer/annotations.html b/www/analyzer/annotations.html
index 819886e822cf..620471346365 100644
--- a/www/analyzer/annotations.html
+++ b/www/analyzer/annotations.html
@@ -5,9 +5,12 @@
<title>Source Annotations</title>
<link type="text/css" rel="stylesheet" href="menu.css" />
<link type="text/css" rel="stylesheet" href="content.css" />
+ <script type="text/javascript" src="scripts/menu.js"></script>
+ <script type="text/javascript" src="scripts/dbtree.js"></script>
</head>
<body>
+<div id="page">
<!--#include virtual="menu.html.incl"-->
<div id="content">
@@ -33,30 +36,34 @@ attributes</a>.</p>
recognized by GCC. Their use can be conditioned using preprocessor macros
(examples included on this page).</p>
-<ul>
-<li><a href="#generic">Annotations to Enhance Generic Checks</a></li>
+<h4>Specific Topics</h4>
+
+<ul id="collapsetree" class="dbtree onclick multiple">
+<li><a href="#generic">Annotations to Enhance Generic Checks</a>
<ul>
- <li><a href="#null_checking">Null Pointer Checking</a></li>
+ <li><a href="#null_checking"><span>Null Pointer Checking</span></a>
<ul>
- <li><a href="#attr_nonnull">Attribute 'nonnull'</a></li>
+ <li><a href="#attr_nonnull"><span>Attribute 'nonnull'</span></a></li>
</ul>
+ </li>
</ul>
-<li><a href="#macosx">Mac OS X API Annotations</a></li>
+</li>
+<li><a href="#macosx">Mac OS X API Annotations</a>
<ul>
- <li><a href="#cocoa_mem">Cocoa &amp; Core Foundation Memory Management
- Annotations</a></li>
+ <li><a href="#cocoa_mem">Cocoa &amp; Core Foundation Memory Management Annotations</a>
<ul>
- <li><a href="#attr_ns_returns_retained">Attribute
- 'ns_returns_retained'</a></li>
- <li><a href="#attr_cf_returns_retained">Attribute
- 'cf_returns_retained'</a></li>
- </ul>
+ <li><a href="#attr_ns_returns_retained">Attribute 'ns_returns_retained'</a></li>
+ <li><a href="#attr_cf_returns_retained">Attribute 'cf_returns_retained'</a></li>
+ </ul>
+ </li>
</ul>
-<li><a href="#custom_assertions">Custom Assertion Handlers</a></li>
+</li>
+<li><a href="#custom_assertions">Custom Assertion Handlers</a>
<ul>
<li><a href="#attr_noreturn">Attribute 'noreturn'</a></li>
<li><a href="#attr_analyzer_noreturn">Attribute 'analyzer_noreturn'</a></li>
</ul>
+ </li>
</ul>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
@@ -383,6 +390,7 @@ void my_assert_rtn(const char *, const char *, int, const char *) <span class="c
</pre>
</div>
+</div>
</body>
</html>
diff --git a/www/analyzer/available_checks.html b/www/analyzer/available_checks.html
index 5e74fd8ea239..7af086506506 100644
--- a/www/analyzer/available_checks.html
+++ b/www/analyzer/available_checks.html
@@ -5,9 +5,11 @@
<title>Available Checks</title>
<link type="text/css" rel="stylesheet" href="menu.css" />
<link type="text/css" rel="stylesheet" href="content.css" />
+ <script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
+<div id="page">
<!--#include virtual="menu.html.incl"-->
<div id="content">
@@ -29,6 +31,7 @@ of some of the bugs that it finds:</p>
</div>
+</div>
</body>
</html>
diff --git a/www/analyzer/content.css b/www/analyzer/content.css
index 3f47e3bea7ad..823fae265c95 100644
--- a/www/analyzer/content.css
+++ b/www/analyzer/content.css
@@ -2,8 +2,11 @@ html { margin: 0px; } body { margin: 8px; }
html, body {
padding:0px;
+ margin:0px;
font-size:small; font-family:"Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, Helvetica, sans-serif; background-color: #fff; color: #222;
line-height:1.5;
+ background-color: #808080;
+
}
h1, h2, h3, tt { color: #000 }
@@ -27,7 +30,34 @@ IMG.img_slide {
margin-right: auto
}
+#page { width:930px; text-align: left; margin: 0 auto; padding:0;
+ background-color: white; height:100%;
+ border-left: 1px solid #EBF0FA;
+}
+
+#content {
+ clear: left;
+ padding: 1em 2em 0 2em;
+ background-color: #ffffff;
+}
+
.itemTitle { color:#2d58b7 }
+
/* Tables */
tr { vertical-align:top }
+
+/* Collapsing Trees: http://dbtree.megalingo.com/web/demo/simple-collapsible-tree.cfm */
+#collapsetree, #collapsetree a:link, #collapsetree li a:link, #collapsetree a:visited, #collapsetree li a:visited{color:#000;text-decoration:none}
+#collapsetree,#collapsetree ul{list-style-type:none; width:auto; margin:0; padding:0}
+#collapsetree ul{padding-left:20px;display:none;overflow:auto}
+#collapsetree li ul{margin:0 auto}
+#collapsetree li{display:block;width:100%;line-height:20px;white-space:nowrap}
+#collapsetree li a{display:block;padding-left:20px;color:#000;text-decoration:none;background:url(images/tree/bullet.gif) center left no-repeat;white-space:nowrap}
+#collapsetree li a:hover{text-decoration:underline;background-color:transparent;color:#000}
+#collapsetree li ul.click{display:block}
+#collapsetree li.click a{background:url(images/tree/bullet.gif) center left no-repeat}
+#collapsetree ul li.click a{background:url(images/tree/bullet.gif) center left no-repeat}
+#collapsetree li a.subMenu,#collapsetree ul li a.subMenu{background:url(images/tree/plus.gif) center left no-repeat}
+#collapsetree li a.click{background:url(images/tree/minus.gif) center left no-repeat}
+#collapsetree ul li a.click{background:url(images/tree/minus.gif) center left no-repeat} \ No newline at end of file
diff --git a/www/analyzer/dev_cxx.html b/www/analyzer/dev_cxx.html
new file mode 100644
index 000000000000..b5ef2b10919f
--- /dev/null
+++ b/www/analyzer/dev_cxx.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Analyzer Development: C++ Support</title>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css" />
+ <script type="text/javascript" src="scripts/menu.js"></script>
+</head>
+<body>
+
+<div id="page">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+
+<h1>C++ Support</h1>
+
+<p>The Clang frontend
+now <a href="http://clang.llvm.org/cxx_status.html">supports the
+majority of C++</a>. Support in the frontend for C++ language
+features, however, does not automatically translate into support for
+those features in the static analyzer. Language features need to be
+specifically modeled in the static analyzer so their semantics can be
+properly analyzed. Support for analyzing C++ and Objective-C++ files
+is currently extremely limited, and we are only encouraging those who
+are interested in contributing to the development of the analyzer to
+try this functionality out at this time.</p>
+
+<p>Listed here are a set of open tasks that are prerequisites for
+decent analysis of C++. This list is also not complete; new tasks
+will be added as deemed necessary.</p>
+
+<ul>
+ <li>Control-Flow Graph Enhancements:</li>
+ <ul>
+ <li>Model C++ destructors</li>
+ <li>Model C++ initializers (in constructors)</li>
+ </ul>
+ <li>Path-Sensitive Analysis Engine (GRExprEngine):</li>
+ <ul>
+ <li>Model C++ casts</li>
+ <li>Model C++ constructors</li>
+ <li>Model C++ destructors</li>
+ <li>Model <tt>new</tt> and <tt>delete</tt></li>
+ </ul>
+</ul>
+
+</div>
+</div>
+</body>
+</html>
+
diff --git a/www/analyzer/filing_bugs.html b/www/analyzer/filing_bugs.html
index 1ce02bee9286..746f1cb22eda 100644
--- a/www/analyzer/filing_bugs.html
+++ b/www/analyzer/filing_bugs.html
@@ -5,11 +5,12 @@
<title>Filing Bugs and Feature Requests</title>
<link type="text/css" rel="stylesheet" href="menu.css" />
<link type="text/css" rel="stylesheet" href="content.css" />
+ <script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
+<div id="page">
<!--#include virtual="menu.html.incl"-->
-
<div id="content">
<h1>Filing Bugs and Feature Requests</h1>
@@ -47,15 +48,14 @@ component.</p>
reports to Apple's <a href="http://bugreporter.apple.com">Bug Reporter</a> web
site.</p>
-<p>You are free to always file bugs through this website, but this option less
+<p>You are free to always file bugs through this website, but this option is less
attractive than filing bug reports through Bugzilla as not everyone who works on
the analyzer has access to that bug database.</p>
<h2>Apple-internal Users</h2>
<p>Please file bugs in Radar against the <b>llvm - checker</b> component.</p>
-
-
+</div>
</div>
</body>
</html>
diff --git a/www/analyzer/images/analyzer_html.png b/www/analyzer/images/analyzer_html.png
new file mode 100644
index 000000000000..607ea1882e71
--- /dev/null
+++ b/www/analyzer/images/analyzer_html.png
Binary files differ
diff --git a/www/analyzer/images/analyzer_xcode.png b/www/analyzer/images/analyzer_xcode.png
new file mode 100644
index 000000000000..84c69809e8c3
--- /dev/null
+++ b/www/analyzer/images/analyzer_xcode.png
Binary files differ
diff --git a/www/analyzer/images/tree/bullet.gif b/www/analyzer/images/tree/bullet.gif
new file mode 100644
index 000000000000..de1534854699
--- /dev/null
+++ b/www/analyzer/images/tree/bullet.gif
Binary files differ
diff --git a/www/analyzer/images/tree/minus.gif b/www/analyzer/images/tree/minus.gif
new file mode 100644
index 000000000000..225f40daeb0d
--- /dev/null
+++ b/www/analyzer/images/tree/minus.gif
Binary files differ
diff --git a/www/analyzer/images/tree/plus.gif b/www/analyzer/images/tree/plus.gif
new file mode 100644
index 000000000000..5398c801331c
--- /dev/null
+++ b/www/analyzer/images/tree/plus.gif
Binary files differ
diff --git a/www/analyzer/index.html b/www/analyzer/index.html
index 2cb318625b4e..006bc5c26522 100644
--- a/www/analyzer/index.html
+++ b/www/analyzer/index.html
@@ -3,19 +3,26 @@
<html>
<head>
<title>Clang Static Analyzer</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
<link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
+<div id="page">
<!--#include virtual="menu.html.incl"-->
-
<div id="content">
-<h1>Clang Static Analyzer</h1>
+
+<table style="margin-top:0px" width="100%" border="0" cellpadding="0px" cellspacing="0">
+<tr><td>
+
+<h1>Clang Static Analyzer</h1>
<p>The Clang Static Analyzer consists of both a source code analysis framework
-and a standalone tool that finds bugs in C and Objective-C programs. The
+and a standalone tool that finds bugs in C and Objective-C programs.</p>
+
+<p>The
standalone tool is invoked from the command-line, and is intended to run in
tandem with a build of a project or code base.</p>
@@ -75,7 +82,7 @@ href="http://clang.llvm.org">Clang</a> project.</p>
#wrappedcontent { padding:15px;}
</style>
-<div style="padding:0px">
+<div style="padding:0px; font-size: 90%">
<b class="spiffy">
<b class="spiffy1"><b></b></b>
<b class="spiffy2"><b></b></b>
@@ -107,6 +114,13 @@ href="http://clang.llvm.org">Clang</a> project.</p>
<b class="spiffy1"><b></b></b></b>
</div>
+</td><td style="padding-left:10px">
+<a href="images/analyzer_xcode.png"><img src="images/analyzer_xcode.png" width="450x" border=0></a>
+<center><b>Viewing static analyzer results in Xcode 3.2</b></center>
+<a href="images/analyzer_html.png"><img src="images/analyzer_html.png" width="450px" border=0></a>
+<center><b>Viewing static analyzer results in a web browser</b></center>
+</td></tr></table>
+
<h2 id="StaticAnalysis">What is Static Analysis?</h2>
<p>The term &quot;static analysis&quot; is conflated, but here we use it to mean
@@ -182,6 +196,7 @@ file <a href="filing_bugs.html">feature requests</a> or contribute your own
patches.</p>
</div>
+</div>
</body>
</html>
diff --git a/www/analyzer/installation.html b/www/analyzer/installation.html
index d2be711a4860..b84f26397237 100644
--- a/www/analyzer/installation.html
+++ b/www/analyzer/installation.html
@@ -5,11 +5,12 @@
<title>Obtaining the Static Analyzer</title>
<link type="text/css" rel="stylesheet" href="menu.css" />
<link type="text/css" rel="stylesheet" href="content.css" />
+ <script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
+<div id="page">
<!--#include virtual="menu.html.incl"-->
-
<div id="content">
<h1>Obtaining the Static Analyzer</h1>
@@ -106,7 +107,7 @@ are located in <tt>$(SRCDIR)/tools/clang/tools/scan-build</tt> and
are subject to change.</p></li>
</ul>
-
+</div>
</div>
</body>
</html>
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index cccedb5a88c0..87ef5fd45ed0 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://files.me.com/tkremenek/pxfgyv">checker-232.tar.bz2</a></b> (built December 14, 2009)
+<b><a href="http://checker.minormatter.com/checker-234.tar.bz2">checker-234.tar.bz2</a></b> (built February 9, 2010)
diff --git a/www/analyzer/menu.css b/www/analyzer/menu.css
index 0312f4c8b1f1..05c1bbfc82db 100644
--- a/www/analyzer/menu.css
+++ b/www/analyzer/menu.css
@@ -1,40 +1,52 @@
-/***************/
-/* page layout */
-/***************/
+/* From 'A list apart', 'dropdowns' */
-[id=menu] {
- position:fixed;
- width:35ex;
+#nav {
+ clear: left;
+ margin:0;
+ padding:0;
+ font-weight: bold;
+ width:100%;
+ background-color: #EBF0FA;
+ border-bottom: 1px solid;
+ font-size: 80%;
}
-[id=content] {
- /* ***** EDIT THIS VALUE IF CONTENT OVERLAPS MENU ***** */
- position:absolute;
- left:39ex;
- padding-right:4ex;
+#nav a {
+ text-decoration: none;
+}
+#nav a:hover {
+ text-decoration: underline;
}
-
-/**************/
-/* menu style */
-/**************/
-
-#menu .submenu {
- padding-top:1em;
- display:block;
+.menubar ul {
+ list-style: none inside;
}
-
-#menu label {
- display:block;
- font-weight: bold;
- text-align: center;
- color: #ffffff;
- background-color: #2d58b7;
+.menubar li {
+ margin: 0;
+ padding: 5px;
+ text-align: left;
+ text-indent: 0px;
+ list-style-position: inside;
+ list-style:none;
+ float: left;
+ position: relative;
+ width: 13em;
+ cursor: default;
+ background-color: #EBF0FA;
}
-#menu a {
- padding:0 .2em;
- display:block;
- text-align: center;
- background-color: #EBF0FA;
+.menubar li ul /* second level lists */ {
+ display: none;
+ position: absolute;
+ left: 0;
}
-#menu a:visited {
- color:rgb(100,50,100);
-} \ No newline at end of file
+.menubar li>ul {
+ border-left: 1px solid;
+ border-right: 1px solid;
+ border-bottom: 1px solid;
+ padding: 0;
+ margin: 5px 0;
+ left:auto;
+ font-weight: normal;
+}
+.menubar li:hover ul, li.over ul { /* lists nested under hovered list items */
+ display: block;
+}
+
diff --git a/www/analyzer/menu.html.incl b/www/analyzer/menu.html.incl
index b7c95f10fb81..8d465e44c2bd 100644
--- a/www/analyzer/menu.html.incl
+++ b/www/analyzer/menu.html.incl
@@ -1,35 +1,39 @@
-<div id="menu">
- <div>
- <a href="http://llvm.org/">LLVM Home</a>
- <a href="http://clang.llvm.org/">Clang Home</a>
- </div>
-
- <div class="submenu">
- <label>Events</label>
- <a href="http://llvm.org/devmtg/2009-10">October 2, 2009 - LLVM/Clang Developers' Meeting</a>
- </div>
-
- <div class="submenu">
- <label>Quick Links</label>
- <a href="/index.html">About the Analyzer</a>
- <a href="/filing_bugs.html">Filing Bugs</a>
- </div>
-
- <div class="submenu">
- <label>User Manual</label>
-<!-- <a href="/design_philosphy.html">Design&nbsp;Philosophy</a> -->
- <a href="/installation.html">Obtaining&nbsp;the&nbsp;Analyzer</a>
- <a href="/scan-build.html">Running&nbsp;the&nbsp;Analyzer</tt></a>
- <a href="/available_checks.html">Available&nbsp;Checks</a>
-<!-- <a href="/false_positives.html">False&nbsp;Positives</a> -->
- <a href="/annotations.html">Source-level Annotations</a>
- </div>
-
- <div class="submenu">
- <label>Clang Mailing Lists</label>
- <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev</a>
- <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">cfe-commits</a>
- </div>
-
- <center><a href="http://llvm.org"><img src="http://llvm.org/img/LLVM-Logo-Derivative-3.png" style="margin-top:10px"></a></center>
-</div>
+<table width="100%" id="nav" cellspacing=0 cellpadding=0>
+<tr><td>
+<ul style="margin:0; padding:0" class="menubar">
+<li style="padding-left:5em">
+ <a href="/index.html">About</a>
+ <ul class="menubar">
+ <li><a href="/index.html">About the Analyzer</a></li>
+ <li><a href="http://llvm.org/">LLVM Project</a></li>
+ <li><a href="http://clang.llvm.org/">Clang Project</a></li>
+ </ul>
+</li>
+<li>
+ <a href="/filing_bugs.html">Filing Bugs</a>
+</li>
+<li>
+ User Manual
+ <ul>
+ <li><a href="/installation.html">Obtaining the Analyzer</a></li>
+ <li><a href="/scan-build.html">Running the Analyzer</tt></a></li>
+ <li><a href="/available_checks.html">Available Checks</a></li>
+ <li><a href="/annotations.html">Source-level Annotations</a></li>
+ </ul>
+</li>
+<li>
+ Development
+ <ul>
+ <li><a href="/dev_cxx.html">Analysis support for C++</a></li>
+ </ul>
+</li>
+<li>
+ Mailing Lists
+ <ul>
+ <li><a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev</a></li>
+ <li><a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">cfe-commits</a></li>
+ </ul>
+</li>
+</ul>
+</td></tr>
+</table>
diff --git a/www/analyzer/menu.js b/www/analyzer/menu.js
new file mode 100644
index 000000000000..6b393c081c85
--- /dev/null
+++ b/www/analyzer/menu.js
@@ -0,0 +1,17 @@
+startList = function() {
+ if (document.all&&document.getElementById) {
+ navRoot = document.getElementById("nav");
+ for (i=0; i<navRoot.childNodes.length; i++) {
+ node = navRoot.childNodes[i];
+ if (node.nodeName=="LI") {
+ node.onmouseover=function() {
+ this.className+=" over";
+ }
+ node.onmouseout=function() {
+ this.className=this.className.replace(" over", "");
+ }
+ }
+ }
+ }
+}
+window.onload=startList;
diff --git a/www/analyzer/scan-build.html b/www/analyzer/scan-build.html
index fd05af021bd9..16bdbfdbe219 100644
--- a/www/analyzer/scan-build.html
+++ b/www/analyzer/scan-build.html
@@ -3,32 +3,33 @@
<html>
<head>
<title>Running the Analyzer</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
<link type="text/css" rel="stylesheet" href="content.css" />
- <style>
- thead {
- background-color:#eee; color:#666666;
- font-weight: bold; cursor: default;
- text-align:center;
- border-top: 2px solid #cccccc;
- border-bottom: 2px solid #cccccc;
- font-weight: bold; font-family: Verdana
- }
- table { border: 1px #cccccc solid }
- table { border-collapse: collapse; border-spacing: 0px }
- table { margin-left:0px; margin-top:20px; margin-bottom:20px }
- td { border-bottom: 1px #cccccc dotted }
- td { padding:5px; padding-left:8px; padding-right:8px }
- td { text-align:left; font-size:9pt }
- td.View { padding-left: 10px }
- </style>
+ <link type="text/css" rel="stylesheet" href="menu.css" />
+ <script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
+<div id="page">
<!--#include virtual="menu.html.incl"-->
-
<div id="content">
+<style>
+table.options thead {
+ background-color:#eee; color:#666666;
+ font-weight: bold; cursor: default;
+ text-align:left;
+ border-top: 2px solid #cccccc;
+ border-bottom: 2px solid #cccccc;
+ font-weight: bold; font-family: Verdana
+}
+table.options { border: 1px #cccccc solid }
+table.options { border-collapse: collapse; border-spacing: 0px }
+table.options { margin-left:0px; margin-top:20px; margin-bottom:20px }
+table.options td { border-bottom: 1px #cccccc dotted }
+table.options td { padding:5px; padding-left:8px; padding-right:8px }
+table.options td { text-align:left; font-size:9pt }
+</style>
+
<h1>Running the Analyzer</h1>
<p>While the static analyzer engine can be used as a library, many users will
@@ -116,7 +117,7 @@ options prefix the build command. For example:</p>
<p>Here is a subset of useful options:</p>
-<table>
+<table class="options">
<thead><tr><td>Option</td><td>Description</td></tr></thead>
<tr><td><b>-o</b></td><td>Target directory for HTML report files. Subdirectories
@@ -245,6 +246,7 @@ report bugs of this kind).
-->
</div>
+</div>
</body>
</html>
diff --git a/www/analyzer/scripts/dbtree.js b/www/analyzer/scripts/dbtree.js
new file mode 100644
index 000000000000..5face5db96de
--- /dev/null
+++ b/www/analyzer/scripts/dbtree.js
@@ -0,0 +1 @@
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('7 5,r,Q,u;7 17=[];5=H;1i();9(!1Z.1j.20){1Z.1j.20=k(a){C[C.D]=a}}7 19=\'35+/\';k 36(a){7 b,R=\'\',i=0;I(;i<a.D;i+=4){b=(19.1k(a.1l(i))&1a)<<18|(19.1k(a.1l(i+1))&1a)<<12|(19.1k(a.1l(i+2))&1a)<<6|19.1k(a.1l(i+3))&1a;R+=37.38((b&39)>>16,(b&3a)>>8,b&1a)}9(a.21(i-2)==22)1m=R.23(0,R.D-2);s 9(a.21(i-1)==22)1m=R.23(0,R.D-1);s 1m=R;z 3b(1m)}7 A={24:k(){7 a=l.E(\'X\');I(7 i=0;i<a.D;i++){9(a[i].h.F(/\\1n\\b/)==-1)3c;7 b=a[i];9(b.h.F(/\\1E\\b/)!=-1){7 c=b.E(\'a\');I(7 j=0;j<c.D;j++){m.B(c[j],\'25\',1F,o);m.B(c[j],\'26\',1G,o);m.B(c[j],\'1o\',1b,o);c[j].Y=\'1H:1I(0)\'}}7 d=b.E(\'X\');I(7 j=0;j<d.D;j++){7 e=d[j].p;e.27=J;9(b.h.F(/\\3d\\b/)!=-1){m.B(e,\'w\',A.w,o);9(b.h.F(/\\3e\\b/)==-1){e.E(\'a\')[0].Y=\'1H:1I(0)\'}}s{7 t=b.h.3f(/1J(.*)1J/);t=t?t[1]:H;m.B(e,\'3g\',A.28(e,t),o);m.B(e,\'3h\',A.29(e),o)}e.E(\'a\')[0].h+=\' 2a\'}9(b.h.F(/\\3i\\b/)!=-1)A.2b(b.v)}},2b:k(a){7 b=l.G(a+\'3j\');9(b){A.1p(b);b=b.p;1c(!!b&&(b.v!=a)){9((!b.h)||(b.h==\'\')){b.h=\'w\'}s{b.h+=\' w\'}9(b.1d.K.L()==\'a\')b.1d.h+=\' w\';b=b.p}}},29:k(a){z k(){A.1p(a)}},28:k(a,b){z k(){A.2c(a,b)}},1p:k(a){7 b=a;3k(b.2d);I(7 i=0;i<b.S.D;i++){7 c=b.S[i];9(c.K.L()==\'X\'){b.E(\'a\')[0].h+=\' w\';b.h+=\' w\';c.h+=\' w\'}}},2c:k(a,b){7 c=a;c.2d=3l(k(){A.1q(c)},b)},1q:k(a){I(7 i=0;i<a.S.D;i++){7 b=a.S[i];9(b.K.L()==\'X\'){a.E(\'a\')[0].h=a.E(\'a\')[0].h.1K(/w/g,\'\');b.h=b.h.1K(/w/g,\'\');a.h=a.h.1K(/w/g,\'\')}}},w:k(e){9(M.T){M.T.1L=J}9(e&&e.1r){e.1r()}7 a=(M.T)?M.T.2e:(e)?e.1M:H;9(!a||!(a=A.1N(a,\'2f\')))z;9(a.E(\'a\')[0].h.F(/\\2g\\b/)==-1){7 b=1e(a);9(2h(b)){9(l.G(b).h.F(/\\3m\\b/)==-1){I(n=0;n<a.p.S.D;n++){N=a.p.S[n];9(N.K.L()==\'2f\'){9(N.h.F(/\\2g\\b/)!=-1)A.1q(a.p.S[n])}}}}A.1p(a)}s{A.1q(a)}9(2h(1e(a))){z J}s{z o}},1N:k(a,b){9(a.K.L()!=b&&a.K.L()!=\'U\'){z A.1N(a.p,b)}s 9(a.K.L()==\'U\'){z H}s{z a}}};k 1i(){3n{u=M.2i?O 2i():O 3o(\'3p.3q\')}3r(e){2j(\'2k 2l: 3s 3t 3u 3v 3w-3x!\')}}k 1O(a,x){a.1f.3y=x+\'2m\'}k 1P(a,y){a.1f.3z=y+\'2m\'}k 1e(a){1c(a.h.F(/\\1n\\b/)==-1){a=a.p}9((a.h.F(/\\1n\\b/)!=-1)&&(a.h.F(/\\1E\\b/)!=-1)){I(i=0;i<17.D;i++){9(a.v==17[i].q)z i}}z a.v}k 1G(a){a=O m(a);r=a.P.p.p.v;7 b=r.1s(\'Z\');r=b[1];5=17[1e(a.P)];7 c=l.G(5.q+\'10\').3A(J);7 d=l.G(5.q+\'10\');d.p.2n(d);c.v=5.q+\'10\';l.U.2o(c);1O(c,a.x);1P(c,a.y);c.1f.1Q=\'2p\';a.1t();m.B(l,\'1u\',1R,o);z o}k 1R(c){c=O m(c);7 e;7 a=c.P;7 b=a;1c((b!=H)&&(b.K.L()!=\'U\')){9(b.v==5.q+\'10\')1g;b=b.p}9((b!=H)&&(b.v==5.q+\'10\')){3B(a.p.h){1S\'3C\':a.Y=5.V+\'11=1T&N=\'+5.13;1g;1S\'1T\':a.Y=5.V+\'11=1T&N=\'+r;1g;1S\'2q\':a.Y=5.V+\'11=2q&N=\'+r;1g;3D:e=5.2r+\'?q=\'+5.q;e+=\'&13=\'+5.13;9(a.p.h==\'3E\'){e+=\'&11=2s&N=\'+r+\'&2t=\'+5.13}s{e+=\'&11=\'+a.p.h+\'&N=\'+r}7 d=O 2u();7 f=d.2v();e+=\'&2w=\'+f;e+=\'&1v=\'+5.1v;e+=\'&1w=\'+5.1w;e+=\'&1x=\'+5.1x;e+=\'&1y=\'+5.1y;e+=\'&1z=\'+5.1z;e+=\'&1A=\'+5.1A;e+=\'&v=\'+5.v;e+=\'&1B=\'+5.1B;e+=\'&1C=\'+5.1C;e+=\'&V=\'+5.V;u.2x=1U;u.1V(\'2y\',e,J);u.14(\'2z\',\'2A-2B\');u.14(\'2C-2D\',\'2E-2F\');u.14(\'2G-2H-2I\',l.2J);u.2K(H)}}7 g=l.G(5.q+\'10\');9(g){g.1f.1Q=\'3F\'};m.1h(l,\'1u\',1R,o)}k 1F(a){a=O m(a);r=a.P.p.p.v;7 b=r.1s(\'Z\');r=b[1];5=17[1e(a.P)];9(!l.G(5.q+\'15\')){7 c=(!l.G(5.q+\'15\'))?l.3G(\'3H\'):l.G(5.q+\'15\');c.v=5.q+\'15\';c.2L=a.P.1d.3I;l.U.2o(c)}m.B(l,\'2M\',1W,o);m.B(l,\'1u\',1X,o);m.B(l,\'1o\',1b,o);a.1t();z o}k 1b(a){9(!a&&M.T)a=M.T;9(a!=H){9(3J(a.1Y)==\'k\')a.1Y();s a.2N=o}z o}k 1W(a){a=O m(a);7 b=l.G(5.q+\'15\');1O(b,a.x);1P(b,a.y);b.1f.1Q=\'2p\';a.1t();z o}k 1X(a){a=O m(a);7 b=a.P.p;9(b.K.L()==\'a\'){r=5.q+\'Z\'+r;9(r!=b.p.v){7 c=J;7 d=b.p;1c(!!d&&(d.v!=5.q)){9(d.v==r){c=o;1g}s{d=d.p}}9(c==J){7 e=r.1s(\'Z\');r=e[1];Q=b.p.v;7 f=Q.1s(\'Z\');Q=f[1];2O(a)}}}7 g=l.G(5.q+\'15\');9(g){g.p.2n(g)};m.1h(l,\'2M\',1W,o);m.1h(l,\'1u\',1X,o);m.1h(l,\'1o\',1b,o)}k 2O(a){7 d=O 2u();7 b=d.2v();7 c;c=5.2r+\'?q=\'+5.q+\'&11=2s&13=\'+5.13+\'&N=\'+r+\'&2t=\'+Q+\'&2w=\'+b;c+=\'&1v=\'+5.1v;c+=\'&1w=\'+5.1w;c+=\'&1x=\'+5.1x;c+=\'&1y=\'+5.1y;c+=\'&1z=\'+5.1z;c+=\'&1A=\'+5.1A;c+=\'&v=\'+5.v;c+=\'&1B=\'+5.1B;c+=\'&1C=\'+5.1C;c+=\'&V=\'+5.V;u.2x=1U;u.1V(\'2y\',c,J);u.14(\'2z\',\'2A-2B\');u.14(\'2C-2D\',\'2E-2F\');u.14(\'2G-2H-2I\',l.2J);u.2K(H)}k 2P(){7 a=(!!Q)?Q:r;a=5.q+\'Z\'+a;a=l.G(a);9(a){a=a.E(\'X\')[0];1c(!!a&&(a.h.F(/\\1n\\b/)==-1)&&(a.h.F(/\\1E\\b/)==-1)){9((!a.h)||(a.h==\'\')){a.h=\'w\'}s{a.h+=\' w\'}9(a.1d.K.L()==\'a\')a.1d.h+=\' w\';a=a.p}}}k 3K(a,b){9(a!=\'3L\'){3M(a+".3N=\'"+b.2Q[b.2R].2S+"\'")}s{M.1V(b.2Q[b.2R].2S)}}k 2T(a){7 b=l.G(a);7 c=b.E(\'X\');I(7 j=0;j<c.D;j++){7 d=c[j].p;d.27=J;m.B(d,\'w\',A.w,o);d.E(\'a\')[0].h+=\' 2a\'}7 e=b.E(\'a\');I(7 j=0;j<e.D;j++){m.B(e[j],\'25\',1F,o);m.B(e[j],\'26\',1G,o);m.B(e[j],\'1o\',1b,o);e[j].Y=\'1H:1I(0)\'}}k 1U(){9(u.3O==4){9(u.3P==3Q){l.G(5.q+\'3R\').2L=u.3S;2T(5.q);2P();1i()}s{2j(\'2k 2l: 3T, 3U 3V 1J 3W a 3X 3Y 3Z 40:\\n\'+u.41);1i()}}}k m(a){C.W=a?a:M.T;C.P=a.1M?a.1M:a.2e;C.x=a.2U?(a.2U):(a.42+2V.2W(l.U.2X,l.2Y.2X));C.y=a.2Z?(a.2Z):(a.43+2V.2W(l.U.30,l.2Y.30))}m.1j.44=k(){z\'m [ x = \'+C.x+\', y = \'+C.y+\' ]\'};m.1j.1t=k(){9(C.W.1r){C.W.1r();C.W.1Y()}s 9(C.W.1L){C.W.1L=J;C.W.2N=o}};m.B=k(a,b,c,d){9(l.31){a.31(b,c,d)}s 9(l.32){a.32(\'1D\'+b,c,d)}s{a[\'1D\'+b]=c}};m.1h=k(a,b,c,d){9(l.33){a.33(b,c,d)}s 9(l.34){a.34(\'1D\'+b,c,d)}s{a[\'1D\'+b]=H}};m.B(M,\'45\',A.24,o);',62,254,'|||||instance||var||if||||||||className|||function|document|Evt||false|parentNode|instanceName|nid|else||client|id|click|||return|dbTree|addEvent|this|length|getElementsByTagName|search|getElementById|null|for|true|nodeName|toLowerCase|window|node|new|source|nto|decOut|childNodes|event|body|editpage|evt|ul|href|_|_options|action||rootnode|setRequestHeader|_tip||dbtreeObj||b64s|0xff|PreventDefault|while|firstChild|getObj|style|break|removeEvent|createClient|prototype|indexOf|charAt|undecOut|bdbtree|selectstart|mOver|mOut|stopPropagation|split|consume|mouseup|type|query|datasource|username|password|table|parent|contentfield|on|bedit|dragPress|contextMenu|javascript|void|to|replace|cancelBubble|target|getTarget|setX|setY|display|contextAction|case|add|callback|open|dragMove|dragRelease|preventDefault|Array|push|charCodeAt|61|substring|init|mousedown|contextmenu|hasSubMenu|getMoutFor|getMoverFor|subMenu|mExp|mTimeout|timeout|srcElement|li|bclick|isNaN|XMLHttpRequest|alert|DBTree|Error|px|removeChild|appendChild|block|edit|tagpath|move|nodeto|Date|getTime|time|onreadystatechange|get|Pragma|no|cache|Cache|Control|must|revalidate|If|Modified|Since|lastModified|send|innerHTML|mousemove|returnValue|dragBoxDropped|expandtree|options|selectedIndex|value|reinit|pageX|Math|max|scrollLeft|documentElement|pageY|scrollTop|addEventListener|attachEvent|removeEventListener|detachEvent|ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789|decode|String|fromCharCode|0xff0000|0xff00|unescape|continue|bonclick|blinkparent|match|mouseout|mouseover|bexpand|_active|clearTimeout|setTimeout|bmultiple|try|ActiveXObject|Microsoft|XMLHTTP|catch|Your|browser|is|not|Ajax|enabled|left|top|cloneNode|switch|addroot|default|moveroot|none|createElement|div|nodeValue|typeof|jumpTo|blank|eval|location|readyState|status|200|_edit|responseText|Sorry|there|seems|be|problem|retrieving|the|response|statusText|clientX|clientY|toString|load'.split('|'),0,{}))
diff --git a/www/analyzer/scripts/menu.js b/www/analyzer/scripts/menu.js
new file mode 100644
index 000000000000..6b393c081c85
--- /dev/null
+++ b/www/analyzer/scripts/menu.js
@@ -0,0 +1,17 @@
+startList = function() {
+ if (document.all&&document.getElementById) {
+ navRoot = document.getElementById("nav");
+ for (i=0; i<navRoot.childNodes.length; i++) {
+ node = navRoot.childNodes[i];
+ if (node.nodeName=="LI") {
+ node.onmouseover=function() {
+ this.className+=" over";
+ }
+ node.onmouseout=function() {
+ this.className=this.className.replace(" over", "");
+ }
+ }
+ }
+ }
+}
+window.onload=startList;
diff --git a/www/comparison.html b/www/comparison.html
index 2462b89da283..0a6a7c8e00fa 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -51,8 +51,7 @@
<li>GCC supports languages that clang does not aim to, such as Java, Ada,
FORTRAN, etc.</li>
<li>GCC front-ends are very mature and already support C++.
- <a href="cxx_status.html">clang's support for C++</a> is nowhere near
- what GCC supports.</li>
+ <a href="cxx_status.html">clang's support for C++</a> is further behind.</li>
<li>GCC supports more targets than LLVM.</li>
<li>GCC is popular and widely adopted.</li>
<li>GCC does not require a C++ compiler to build it.</li>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index fdddc2274a2b..0da84c2048b5 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -24,11 +24,89 @@
<!--*************************************************************************-->
<h1>C++ Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2009-12-19 21:59:13 +0100 (Sat, 19 Dec 2009) $</p>
+<p>Last updated: $Date: 2010-02-09 17:50:54 +0100 (Tue, 09 Feb 2010) $</p>
-<p>
-This page tracks the status of C++ support in Clang.<br>
-Clang implements the majority of C++ features, although there are many bugs remaining and Clang is not yet generally useful as a C++ compiler. If you are looking to <a href="get_involved.html">get involved with Clang development</a> to help work on support for C++, please also look at our <a href="OpenProjects.html">Open Projects</a> page and the <a href="http://llvm.org/bugs/">LLVM bug tracker</a> for some specific ideas.</p>
+<h1>Clang C++ Status</h1>
+
+ <ul>
+ <li><a href="#projects">Projects Building with Clang</a></li>
+ <li><a href="#specification">Implementation Status by Section</a></li>
+ <li><a href="#cxx0x">C++0x Status</a></li>
+ </ul>
+
+<p>Clang currently implements nearly all of the ISO C++ 1998 standard
+(including the defects addressed in the ISO C++ 2003 standard), with
+the few notable exceptions listed below. However, the implementation
+of Clang C++ is still quite immature, with many remaining bugs that
+are likely to cause compiler crashes, erroneous errors and warnings,
+and miscompiled code. The <a href="http://llvm.org/bugs/">LLVM bug
+tracker</a> contains a Clang C++ component that tracks known Clang C++
+bugs.</p>
+
+<p>Clang is currently missing implementations of the following C++98/03 features and common extensions:</p>
+ <ul>
+
+ <li>Access control: Clang does not perform access-control checking
+ at this time, so it will fail to diagnose invalid accesses. Work
+ is underway to implement this feature.</li>
+
+ <li>Friends and friend templates: Clang parses friends and friend
+ templates for the most part, but they are not used in access
+ control and there are a number of problems with friend templates
+ and friends within class templates.</li>
+
+ <li>GNU <a href="http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Strong-Using.html">strong using</a> extension.</li>
+
+ <li>Qualified member accesses that disambiguate the base class in a diamond-shaped inheritance hierarchy.</li>
+
+ </ul>
+
+ <h2 id="projects">Projects Building with Clang</h2>
+
+ <p>Clang is now capable of compiling some language C++ projects, or
+large pieces of such projects. The following table describes various
+projects that we have attempted to compile with Clang along with the results of that attempt.</p>
+
+ <p> At this point in time, each new C++ project typically uncovers
+new bugs. We keep track of these in the <a
+ href="http://llvm.org/bugs/">LLVM bug tracker</a> via tracking bugs,
+which are used to relate all of the bugs known to affect that
+particular project. Introducing a new project in this list typically requires a liason familiar with LLVM or Clang development, who is able to provide detailed bug reports and track progress for the particular project.</p>
+
+<table width="689" border="1" cellspacing="0">
+ <tr>
+ <th>Project</th>
+ <th>Status</th>
+ <th>Last Tested</th>
+ <th>Tracking Bug</th>
+ </tr>
+ <tr>
+ <td><a href="http://clang.llvm.org">Clang</a> and <a href="http://llvm.org">LLVM</a></td>
+ <td>Successful self-hosting achieved</td>
+ <td>Continually</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><a href="http://www.cmake.org">CMake</a></td>
+ <td>Compiles, passes regression tests (debug build)</td>
+ <td>February 9, 2010</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><a href="http://qt.nokia.com">Qt</a></td>
+ <td>Partially compiles; miscompilation of uic prevents complete compilation, qmake works, some small examples also.</td>
+ <td>February 9, 2010</td>
+ <td><a href="http://llvm.org/bugs/show_bug.cgi?id=5881">PR5881</a></td>
+ </tr>
+ <tr>
+ <td><a href="http://www.boost.org">Boost</a></td>
+ <td>Some libraries (e.g., Boost.MPL) successfully build and pass regression tests, the majority still fail.</td>
+ <td>February 5, 2010</td>
+ <td><a href="http://llvm.org/bugs/show_bug.cgi?id=6023">PR6023</a></td>
+ </tr>
+</table>
+
+ <h2 id="specification">Implementation Status by Section</h2>
<!-- Within this table: The colors we're using to color-code our level
@@ -2297,6 +2375,12 @@ welcome!</p>
<tr><td>&nbsp;&nbsp;D.5 [depr.c.headers]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>E [extendid]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
+</table>
+
+ <h2 id="cxx0x">C++0x Implementation status</h2>
+<p>Clang's development effort is focused primarily on supporting the current ISO C++ standard (1998/2003). This section tracks the status of various C++0x features. In general, the implementations of these features are far less developed than C++98/03 features.</p>
+
+<table width="689" border="1" cellspacing="0">
<td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td>
</tr>
<tr>
diff --git a/www/diagnostics.html b/www/diagnostics.html
index 18f1bc7ff0be..4f7d025b8ec0 100644
--- a/www/diagnostics.html
+++ b/www/diagnostics.html
@@ -281,7 +281,7 @@ macros that in simple ones.</p>
<h2>Quality of Implementation and Attention to Detail</h2>
<p>Finally, we have put a lot of work polishing the little things, because
-little things add up over time and contribute to a great user experience. Two
+little things add up over time and contribute to a great user experience. Three
examples are:</p>
<pre>
@@ -314,6 +314,33 @@ and caret diagnostics, because otherwise you don't get the important context.
of GCC is completely useless for diagnosing the problem, Clang tries much harder
and produces a much more useful diagnosis of the problem.</p>
+<pre>
+ $ <b>cat t.cc</b>
+ template&lt;class T&gt;
+ class a {}
+ class temp {};
+ a&lt;temp&gt; b;
+ struct b {
+ }
+ $ <b>gcc-4.2 t.cc</b>
+ t.cc:3: error: multiple types in one declaration
+ t.cc:4: error: non-template type 'a' used as a template
+ t.cc:4: error: invalid type in declaration before ';' token
+ t.cc:6: error: expected unqualified-id at end of input
+ $ <b>clang t.cc</b>
+ t.cc:2:11: <font color="red">error:</font> expected ';' after class
+ <font color="darkgreen">class a {}</font>
+ <font color="blue"> ^</font>
+ <font color="blue"> ;</font>
+ t.cc:6:2: <font color="red">error:</font> expected ';' after struct
+ <font color="darkgreen">}</font>
+ <font color="blue"> ^</font>
+ <font color="blue"> ;</font>
+</pre>
+
+<p>This shows that we recover from the simple case of forgetting a ; after
+a struct definition much better than GCC.</p>
+
<p>While each of these details is minor, we feel that they all add up to provide
a much more polished experience.</p>
diff --git a/www/index.html b/www/index.html
index 776c72962260..9adf640f9b31 100644
--- a/www/index.html
+++ b/www/index.html
@@ -89,13 +89,15 @@
<h2>Current Status</h2>
<!--=====================================================================-->
- <p>Clang is still under heavy development. Clang is considered to be
- a production quality C and Objective-C compiler when targetting X86-32 and X86-64
- (other targets may have caveats, but are usually easy to fix). If you are
- looking for source
- analysis or source-to-source transformation tools, clang is probably
- a great solution for you. If you are interested in C++,
- <a href="cxx_status.html">full support</a> is still way off.</p>
+ <p>Clang is still under heavy development. Clang is considered to
+ be a production quality C and Objective-C compiler when targetting
+ X86-32 and X86-64 (other targets may have caveats, but are usually
+ easy to fix). If you are looking for source analysis or
+ source-to-source transformation tools, clang is probably a great
+ solution for you. Clang's C++ support is currently alpha quality
+ at best, but is evolving rapidly: see the <a
+ href="cxx_status.html">C++ status</a> page for more
+ information.</p>
<!--=====================================================================-->
<h2>Get it and get involved!</h2>